浅谈Android中Service的注册方式及使用

Service通常总是称之为“后台服务”,其中“后台”一词是相对于前台而言的,具体是指其本身的运行并不依赖于用户可视的UI界面,因此,从实际业务需求上来理解,Service的适用场景应该具备以下条件:

1.并不依赖于用户可视的UI界面(当然,这一条其实也不是绝对的,如前台Service就是与Notification界面结合使用的);

2.具有较长时间的运行特性。

1.Service AndroidManifest.xml 声明

一般而言,从Service的启动方式上,可以将Service分为Started Service和Bound Service。无论哪种具体的Service启动类型,都是通过继承Service基类自定义而来。在使用Service时,要想系统能够找到此自定义Service,无论哪种类型,都需要在AndroidManifest.xml中声明,语法格式如下:

<service android:enabled=["true" | "false"]
 android:exported=["true" | "false"]
 android:icon="drawable resource"
 android:isolatedProcess=["true" | "false"]
 android:label="string resource"
 android:name="string"
 android:permission="string"
 android:process="string" >
 . . .
</service>

其中,android:exported属性上一篇博文中对此已进行详尽描述,android:name对应Service类名,android:permission是权限声明,android:process设置具体的进程名称。需要注意的是Service能否单独使用一个进程与其启动方式有关,本后下面会给出具体说明。其他的属性此处与其他组件基本相同,不再过多描述。

注:如果自定义Service没有在AndroidManifest.xml中声明,当具体使用时,不会像Activity那样直接崩溃报错,对于显式Intent启动的Service,此时也会给出waring信息“IllegalArgumentException: Service not registered”,有时候不容易发现忘了声明而一时定位不到问题。

2.Started Service

Started Service相对比较简单,通过context.startService(Intent serviceIntent)启动Service,context.stopService(Intent serviceIntent)停止此Service。当然,在Service内部,也可以通过stopSelf(...)方式停止其本身。

1)Started Service自定义

下面代码片段显示的是一个最基本的Started Service的自定义方式:

public class MyService extends Service {
 public static final String TAG = "MyService";
 @Override
 public IBinder onBind(Intent intent) {
  return null;
 }
 @Override
 public void onCreate() {
  super.onCreate();
  Log.w(TAG, "in onCreate");
 }
 @Override
 public int onStartCommand(Intent intent, int flags, int startId) {
  Log.w(TAG, "in onStartCommand");
  Log.w(TAG, "MyService:" + this);
  String name = intent.getStringExtra("name");
  Log.w(TAG, "name:" + name);
  return START_STICKY;
 }
 @Override
 public void onDestroy() {
  super.onDestroy();
  Log.w(TAG, "in onDestroy");
 }
}

其中,onBind(...)函数是Service基类中的唯一抽象方法,子类都必须重写实现,此函数的返回值是针对Bound Service类型的Service才有用的,在Started Service类型中,此函数直接返回 null 即可。onCreate(...)、onStartCommand(...)和onDestroy()都是Started Service相应生命周期阶段的回调函数。

2) Started Service使用

public class MainActivity extends Activity {
 public static final String TAG = "MainActivity";
 private Button startServiceBtn;
 private Button stopServideBtn;
 private Button goBtn;
 private Intent serviceIntent;
 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  startServiceBtn = (Button) findViewById(R.id.start_service);
  stopServideBtn = (Button) findViewById(R.id.stop_service);
  goBtn = (Button) findViewById(R.id.go);
  startServiceBtn.setOnClickListener(new View.OnClickListener() {
   @Override
   public void onClick(View v) {
    serviceIntent = new Intent(MainActivity.this, MyService.class);
    startService(serviceIntent);
   }
  });
  stopServideBtn.setOnClickListener(new View.OnClickListener() {
   @Override
   public void onClick(View v) {
    stopService(serviceIntent);
   }
  });
  goBtn.setOnClickListener(new View.OnClickListener() {
   @Override
   public void onClick(View v) {
    Intent intent = new Intent(MainActivity.this, BActivity.class);
    startActivity(intent);
   }
  });
 }
 @Override
 protected void onDestroy() {
  super.onDestroy();
  Log.w(TAG, "in onDestroy");
 }
}

如上代码片段,

当Client调用startService(Intent serviceIntent)后,如果MyService是第一次启动,首先会执行 onCreate()回调,然后再执行onStartCommand(Intent intent, int flags, int startId),当Client再次调用startService(Intent serviceIntent),将只执行onStartCommand(Intent intent, int flags, int startId),因为此时Service已经创建了,无需执行onCreate()回调。无论多少次的startService,只需要一次stopService()即可将此Service终止,执行onDestroy()函数(其实很好理解,因为onDestroy()与onCreate()回调是相对的)。

下面重点关注下onStartCommand(Intent intent, int flags, int startId)方法。

其中参数flags默认情况下是0,对应的常量名为START_STICKY_COMPATIBILITY。startId是一个唯一的整型,用于表示此次Client执行startService(...)的请求请求标识,在多次startService(...)的情况下,呈现0,1,2....递增。另外,此函数具有一个int型的返回值,具体的可选值及含义如下:

START_NOT_STICKY:当Service因为内存不足而被系统kill后,接下来未来的某个时间内,即使系统内存足够可用,系统也不会尝试重新创建此Service。除非程序中Client明确再次调用startService(...)启动此Service。

START_STICKY:当Service因为内存不足而被系统kill后,接下来未来的某个时间内,当系统内存足够可用的情况下,系统将会尝试重新创建此Service,一旦创建成功后将回调onStartCommand(...)方法,但其中的Intent将是null,pendingintent除外。

START_REDELIVER_INTENT:与START_STICKY唯一不同的是,回调onStartCommand(...)方法时,其中的Intent将是非空,将是最后一次调用startService(...)中的intent。

START_STICKY_COMPATIBILITY:compatibility version of {@link #START_STICKY} that does not guarantee that {@link #onStartCommand} will be called again after being killed。此值一般不会使用,所以注意前面三种情形就好。

以上的描述中,”当Service因为内存不足而被系统kill后“一定要非常注意,因为此函数的返回值设定只是针对此种情况才有意义的,换言之,当认为的kill掉Service进程,此函数返回值无论怎么设定,接下来未来的某个时间内,即使系统内存足够可用,Service也不会重启。

小米手机针对此处做了变更:

另外,需要注意的是,小米手机针对此处做了一定的修改。在“自启动管理”中有一个自启动应用列表,默认情况下,只有少应用(如微信、QQ、YY、360等)默认是可以自启动的,其他应用默认都是禁止的。用户可以手动添加自启动应用,添加后的应用中如果Started Service onStartCommand(...)回调返回值是START_STICKY或START_REDELIVER_INTENT,当用户在小米手机上长按Home键结束App后,接下来未来的某个时间内,当系统内存足够可用时,Service依然可以按照上述规定重启。当然,如果用户在 设置 >> 应用 >> 强制kill掉App进程,此时Service是不会重启的。

注:以上实验结论基于小米2S亲测。

3) Started Service生命周期及进程相关

1.onCreate(Client首次startService(..)) >> onStartCommand >> onStartCommand - optional ... >> onDestroy(Client调用stopService(..))

注:onStartCommand(..)可以多次被调用,onDestroy()与onCreate()想匹配,当用户强制kill掉进程时,onDestroy()是不会执行的。

2.对于同一类型的Service,Service实例一次永远只存在一个,而不管Client是否是相同的组件,也不管Client是否处于相同的进程中。

3.Service通过startService(..)启动Service后,此时Service的生命周期与Client本身的什么周期是没有任何关系的,只有Client调用stopService(..)或Service本身调用stopSelf(..)才能停止此Service。当然,当用户强制kill掉Service进程或系统因内存不足也可能kill掉此Service。

4.Client A 通过startService(..)启动Service后,可以在其他Client(如Client B、Client C)通过调用stopService(..)结束此Service。

5.Client调用stopService(..)时,如果当前Service没有启动,也不会出现任何报错或问题,也就是说,stopService(..)无需做当前Service是否有效的判断。

6.startService(Intent serviceIntent),其中的intent既可以是显式Intent,也可以是隐式Intent,当Client与Service同处于一个App时,一般推荐使用显示Intent。当处于不同App时,只能使用隐式Intent。

当Service需要运行在单独的进程中,AndroidManifest.xml声明时需要通过android:process指明此进程名称,当此Service需要对其他App开放时,android:exported属性值需要设置为true(当然,在有intent-filter时默认值就是true)。

<service
 android:name=".MyService"
 android:exported="true"
 android:process=":MyCorn" >
 <intent-filter>
  <action android:name="com.example.androidtest.myservice" />
 </intent-filter>
</service>

4)Started Service Client与Service通信相关

当Client调用startService(Intent serviceIntent)启动Service时,Client可以将参数通过Intent直接传递给Service。Service执行过程中,如果需要将参数传递给Client,一般可以通过借助于发送广播的方式(此时,Client需要注册此广播)。

3.Bound Service

相对于Started Service,Bound Service具有更多的知识点。Bound Service的主要特性在于Service的生命周期是依附于Client的生命周期的,当Client不存在时,Bound Service将执行onDestroy,同时通过Service中的Binder对象可以较为方便进行Client-Service通信。Bound Service一般使用过程如下:

1.自定义Service继承基类Service,并重写onBind(Intent intent)方法,此方法中需要返回具体的Binder对象;

2.Client通过实现ServiceConnection接口来自定义ServiceConnection,并通过bindService (Intent service, ServiceConnection sc, int flags)方法将Service绑定到此Client上;

3.自定义的ServiceConnection中实现onServiceConnected(ComponentName name, IBinder binder)方法,获取Service端Binder实例;

4.通过获取的Binder实例进行Service端其他公共方法的调用,以完成Client-Service通信;

5.当Client在恰当的生命周期(如onDestroy等)时,此时需要解绑之前已经绑定的Service,通过调用函数unbindService(ServiceConnection sc)。

在Bound Service具体使用过程中,根据onBind(Intent intent)方法放回的Binder对象的定义方式不同,又可以将其分为以下三种方式,且每种方式具有不同的特点和适用场景:

1).Extending the Binder class

这是Bound Service中最常见的一种使用方式,也是Bound Service中最简单的一种。

局限:Clinet与Service必须同属于同一个进程,不能实现进程间通信(IPC)。否则则会出现类似于“android.os.BinderProxy cannot be cast to xxx”错误。

下面通过代码片段看下具体的使用:

public class MyBindService extends Service {
 public static final String TAG = "MyBindService";
 private MyBinder mBinder = new MyBinder();
 public class MyBinder extends Binder {
  MyBindService getService() {
   return MyBindService.this;
  }
 }
 @Override
 public void onCreate() {
  super.onCreate();
  Log.w(TAG, "in onCreate");
 }
 @Override
 public IBinder onBind(Intent intent) {
  Log.w(TAG, "in onBind");
  return mBinder;
 }
 @Override
 public boolean onUnbind(Intent intent) {
  Log.w(TAG, "in onUnbind");
  return super.onUnbind(intent);
 }
 @Override
 public void onDestroy() {
  super.onDestroy();
  Log.w(TAG, "in onDestroy");
 }
}
public class BActivity extends Activity {
 public static final String TAG = "BActivity";
 private Button bindServiceBtn;
 private Button unbindServiceBtn;
 private Button startIntentService;
 private Intent serviceIntent;
 private ServiceConnection sc = new MyServiceConnection();
 private MyBinder mBinder;
 private MyBindService mBindService;
 private boolean mBound;
 private class MyServiceConnection implements ServiceConnection {
  @Override
  public void onServiceConnected(ComponentName name, IBinder binder) {
   Log.w(TAG, "in MyServiceConnection onServiceConnected");
   mBinder = (MyBinder) binder;
   mBindService = mBinder.getService();
   mBound = true;
  }
  @Override
  public void onServiceDisconnected(ComponentName name) {
   // This is called when the connection with the service has been
   // unexpectedly disconnected -- that is, its process crashed.
   Log.w(TAG, "in MyServiceConnection onServiceDisconnected");
   mBound = false;
  }
 }
 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.b);
  bindServiceBtn = (Button) findViewById(R.id.bind_service);
  unbindServiceBtn = (Button) findViewById(R.id.unbind_service);
  startIntentService = (Button) findViewById(R.id.start_intentservice);
  bindServiceBtn.setOnClickListener(new View.OnClickListener() {
   @Override
   public void onClick(View v) {
    Intent intent = new Intent(BActivity.this, MyBindService.class);
    bindService(intent, sc, Context.BIND_AUTO_CREATE);
   }
  });
  unbindServiceBtn.setOnClickListener(new View.OnClickListener() {
   @Override
   public void onClick(View v) {
    excuteUnbindService();
   }
  });
  startIntentService.setOnClickListener(new View.OnClickListener() {
   @Override
   public void onClick(View v) {
    Intent intent = new Intent(BActivity.this, MyIntentService.class);
    startService(intent);
   }
  });
 }
 private void excuteUnbindService() {
  if (mBound) {
   unbindService(sc);
   mBound = false;
  }
 }
 @Override
 protected void onDestroy() {
  super.onDestroy();
  Log.w(TAG, "in onDestroy");
  excuteUnbindService();
 }
}

首次点击bindServiceBtn进行bindService(..)时,依次回调顺序如下:

MyBindService(13457): in onCreate
MyBindService(13457): in onBind
BActivity(13457): in MyServiceConnection onServiceConnected

再次点击bindServiceBtn按钮时,发现没有任何输出,说明MyBindService没有进行任何回调。

点击unbindServiceBtn进行unbindService(..)时,回调顺序为:

MyBindService(13457): in onUnbind
MyBindService(13457): in onDestroy

注:在四大基本组件中,需要注意的的是BroadcastReceiver不能作为Bound Service的Client,因为BroadcastReceiver的生命周期很短,当执行完onReceive(..)回调时,BroadcastReceiver生命周期完结。而Bound Service又与Client本身的生命周期相关,因此,Android中不允许BroadcastReceiver去bindService(..),当有此类需求时,可以考虑通过startService(..)替代。

2)Using a Messenger

Messenger,在此可以理解成”信使“,通过Messenger方式返回Binder对象可以不用考虑Clinet - Service是否属于同一个进程的问题,并且,可以实现Client - Service之间的双向通信。极大方便了此类业务需求的实现。

局限:不支持严格意义上的多线程并发处理,实际上是以队列去处理

下面直接看下具体的使用:

public class MyMessengerService extends Service {
 public static final String TAG = "MyMessengerService";
 public static final int MSG_FROM_CLIENT_TO_SERVER = 1;
 public static final int MSG_FROM_SERVER_TO_CLIENT = 2;
 private Messenger mClientMessenger;
 private Messenger mServerMessenger = new Messenger(new ServerHandler());
 @Override
 public IBinder onBind(Intent intent) {
  Log.w(TAG, "in onBind");
  return mServerMessenger.getBinder();
 }
 class ServerHandler extends Handler {
  @Override
  public void handleMessage(Message msg) {
   Log.w(TAG, "thread name:" + Thread.currentThread().getName());
   switch (msg.what) {
   case MSG_FROM_CLIENT_TO_SERVER:
    Log.w(TAG, "receive msg from client");
    mClientMessenger = msg.replyTo;
    // service发送消息给client
    Message toClientMsg = Message.obtain(null, MSG_FROM_SERVER_TO_CLIENT);
    try {
     Log.w(TAG, "server begin send msg to client");
     mClientMessenger.send(toClientMsg);
    } catch (RemoteException e) {
     e.printStackTrace();
    }
    break;
   default:
    super.handleMessage(msg);
   }
  }
 }
 @Override
 public boolean onUnbind(Intent intent) {
  Log.w(TAG, "in onUnbind");
  return super.onUnbind(intent);
 }
 @Override
 public void onDestroy() {
  Log.w(TAG, "in onDestroy");
  super.onDestroy();
 }
}
public class CActivity extends Activity {
 public static final String TAG = "CActivity";
 private Button bindServiceBtn;
 private Button unbindServiceBtn;
 private Button sendMsgToServerBtn;
 private ServiceConnection sc = new MyServiceConnection();
 private boolean mBound;
 private Messenger mServerMessenger;
 private Handler mClientHandler = new MyClientHandler();
 private Messenger mClientMessenger = new Messenger(mClientHandler);
 private class MyClientHandler extends Handler {
  @Override
  public void handleMessage(Message msg) {
   if (msg.what == MyMessengerService.MSG_FROM_SERVER_TO_CLIENT) {
    Log.w(TAG, "reveive msg from server");
   }
  }
 }
 private class MyServiceConnection implements ServiceConnection {
  @Override
  public void onServiceConnected(ComponentName name, IBinder binder) {
   Log.w(TAG, "in MyServiceConnection onServiceConnected");
   mServerMessenger = new Messenger(binder);
   mBound = true;
  }
  @Override
  public void onServiceDisconnected(ComponentName name) {
   // This is called when the connection with the service has been
   // unexpectedly disconnected -- that is, its process crashed.
   Log.w(TAG, "in MyServiceConnection onServiceDisconnected");
   mBound = false;
  }
 }
 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.c);
  bindServiceBtn = (Button) findViewById(R.id.bind_service);
  unbindServiceBtn = (Button) findViewById(R.id.unbind_service);
  sendMsgToServerBtn = (Button) findViewById(R.id.send_msg_to_server);
  bindServiceBtn.setOnClickListener(new View.OnClickListener() {
   @Override
   public void onClick(View v) {
    Intent intent = new Intent(CActivity.this, MyMessengerService.class);
    bindService(intent, sc, Context.BIND_AUTO_CREATE);
   }
  });
  unbindServiceBtn.setOnClickListener(new View.OnClickListener() {
   @Override
   public void onClick(View v) {
    excuteUnbindService();
   }
  });
  sendMsgToServerBtn.setOnClickListener(new View.OnClickListener() {
   @Override
   public void onClick(View v) {
    sayHello();
   }
  });
  new Handler().postDelayed(new Runnable() {
   @Override
   public void run() {
    Intent intent = new Intent(CActivity.this, MyAlarmBroadcastReceiver.class);
    sendBroadcast(intent);
   }
  }, 3 * 1000);
 }
 public void sayHello() {
  if (!mBound)
   return;
  // Create and send a message to the service, using a supported 'what' value
  Message msg = Message.obtain(null, MyMessengerService.MSG_FROM_CLIENT_TO_SERVER, 0, 0);
  // 通过replyTo把client端的Messenger(信使)传递给service
  msg.replyTo = mClientMessenger;
  try {
   mServerMessenger.send(msg);
  } catch (RemoteException e) {
   e.printStackTrace();
  }
 }
 private void excuteUnbindService() {
  if (mBound) {
   unbindService(sc);
   mBound = false;
  }
 }
 @Override
 protected void onDestroy() {
  super.onDestroy();
  Log.w(TAG, "in onDestroy");
  excuteUnbindService();
 }
}

其中,需要注意的几点是:

1.MyMessengerService自定中,通过new Messenger(new ServerHandler())创建Messenger对象,在onBind(..)回调中,通过调用Messenger对象的getBinder()方法,将Binder返回;

2.Client在ServiceConnection的onServiceConnected(..)的回调中,通过new Messenger(binder)获取到Service传递过来的mServerMessenger;

3.接下来,就可以通过mServerMessenger.send(msg)方法向Service发送message,Service中的Messenger构造器中的Handler即可接收到此信息,在handleMessage(..)回调中处理;

4.至此只是完成了从Client发送消息到Service,同样的道理,想实现Service发送消息到Client,可以在客户端定义一个Handler,并得到相应的Messenger,在Clinet发送消息给Service时,通过msg.replyTo = mClientMessenger方式将Client信使传递给Service;

5.Service接收到Client信使后,获取此信使,并通过mClientMessenger.send(toClientMsg)方式将Service消息发送给Client。

至此,完成了Client - Service之间的双向通信流程。

3).AIDL(Android Interface Definition Language)

一般情况下,Messenger这种方式都是可以满足需求的,当然,通过自定义AIDL方式相对更加灵活。

这种方式需要自己在项目中自定义xxx.aidl文件,然后系统会自动在gen目录下生成相应的接口类文件,接下来整个的流程与Messenger方式差别不大,网上也有不少实例,在此不再具体给出。

注:无论哪种方式的Bound Service,在进行unbind(..)操作时,都需要注意当前Service是否处于已经绑定状态,否则可能会因为当前Service已经解绑后继续执行unbind(..)会导致崩溃。这点与Started Service区别很大(如前文所述:stopService(..)无需做当前Service是否有效的判断)。

4.Local Service VS Remote Service

Local Service:不少人又称之为”本地服务“,是指Client - Service同处于一个进程;

Remote Service:又称之为”远程服务“,一般是指Service处于单独的一个进程中。

其他使用上上文中基本上都有所述。

5.Service特性

1.Service本身都是运行在其所在进程的主线程(如果Service与Clinet同属于一个进程,则是运行于UI线程),但Service一般都是需要进行”长期“操作,所以经常写法是在自定义Service中处理”长期“操作时需要新建线程,以免阻塞UI线程或导致ANR;

2.Service一旦创建,需要停止时都需要显示调用相应的方法(Started Service需要调用stopService(..)或Service本身调用stopSelf(..), Bound Service需要调用unbindService(..)),否则对于Started Service将处于一直运行状态,对于Bound Service,当Client生命周期结束时也将因此问题。也就是说,Service执行完毕后,必须人为的去停止它。

6.IntentService

IntentService是系统提供给我们的一个已经继承自Service类的特殊类,IntentService特殊性是相对于Service本身的特性而言的:

1.默认直接实现了onBind(..)方法,直接返回null,并定义了抽象方法onHandlerIntent(..),用户自定义子类时,需要实现此方法;

2.onHandlerIntent(..)主要就是用来处于相应的”长期“任务的,并且已经自动在新的线程中,用户无语自定义新线程;

3.当”长期“任务执行完毕后(也就是onHandlerIntent(..)执行完毕后),此IntentService将自动结束,无需人为调用方法使其结束;

4.IntentService处于任务时,也是按照队列的方式一个个去处理,而非真正意义上的多线程并发方式。

下面是一个基本的继承自IntentService的自定义Service:

public class MyIntentService extends IntentService {
 public static final String TAG = "MyIntentService";
 public MyIntentService() {
  super(TAG);
 }
 public MyIntentService(String name) {
  super(name);
 }
 @Override
 protected void onHandleIntent(Intent intent) {
  Log.w(TAG, "in onHandleIntent");
  Log.w(TAG, "thread name:" + Thread.currentThread().getName());
 }
}

7.前台Service

Android中Service接口中还提供了一个称之为”前台Service“的概念。通过Service.startForeground (int id, Notification notification)方法可以将此Service设置为前台Service。在UI显示上,notification将是一个处于onGoing状态的通知,使得前台Service拥有更高的进程优先级,并且Service可以直接notification通信。

下面是一个简单的前台Service使用实例:

public class MyService extends Service {
 public static final String TAG = "MyService";
 @Override
 public IBinder onBind(Intent intent) {
  return null;
 }
 @Override
 public void onCreate() {
  super.onCreate();
  Log.w(TAG, "in onCreate");
 }
 @Override
 public int onStartCommand(Intent intent, int flags, int startId) {
  Log.w(TAG, "in onStartCommand");
  Log.w(TAG, "MyService:" + this);
  String name = intent.getStringExtra("name");
  Log.w(TAG, "name:" + name);

  Notification notification = new Notification(R.drawable.ic_launcher, "test", System.currentTimeMillis());
  Intent notificationIntent = new Intent(this, DActivity.class);
  PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntesnt, 0);
  notification.setLatestEventInfo(this, "title", "content", pendingIntent);
  startForeground(1, notification);

  return START_REDELIVER_INTENT;
 }
 @Override
 public void onDestroy() {
  super.onDestroy();
  Log.w(TAG, "in onDestroy");
 }
}

以上这篇浅谈Android中Service的注册方式及使用就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持我们。

您可能感兴趣的文章:

  • Android Service服务详细介绍及使用总结
  • Android Service绑定过程完整分析
  • Android Service总结及详细介绍
  • Android开发入门之Service用法分析
  • Android Service中方法使用详细介绍
  • Android中Service的全面总结
(0)

相关推荐

  • Android Service服务详细介绍及使用总结

    Android Service服务详解 一.Service简介 Service是android 系统中的四大组件之一(Activity.Service.BroadcastReceiver. ContentProvider),它跟Activity的级别差不多,但不能页面显示只能后台运行,并且可以和其他组件进行交互.service可以在很多场合的应用中使用,比如播放多媒体的时候用户启动了其他Activity这个时候程序要在后台继续播放,比如检测SD卡上文件的变化,再或者在后台记录你地理信息位置的改变

  • Android Service总结及详细介绍

    1.Service的种类 按运行地点分类: 类别 区别  优点 缺点   应用 本地服务(Local) 该服务依附在主进程上,  服务依附在主进程上而不是独立的进程,这样在一定程度上节约了资源,另外Local服务因为是在同一进程因此不需要IPC,也不需要AIDL.相应bindService会方便很多.  主进程被Kill后,服务便会终止.  非常常见的应用如:HTC的音乐播放服务,天天动听音乐播放服务. 远程服务(Remote) 该服务是独立的进程,  服务为独立的进程,对应进程名格式为所在包名

  • Android Service绑定过程完整分析

    通常我们使用Service都要和它通信,当想要与Service通信的时候,那么Service要处于绑定状态的.然后客户端可以拿到一个Binder与服务端进行通信,这个过程是很自然的. 那你真的了解过Service的绑定过程吗?为什么可以是Binder和Service通信? 同样的先看一张图大致了解一下,灰色背景框起来的是同一个类的方法,如下: 我们知道调用Context的bindService方法即可绑定一个Service,而ContextImpl是Context的实现类.那接下来就从源码的角度

  • Android开发入门之Service用法分析

    本文实例讲述了Android中Service用法.分享给大家供大家参考,具体如下: 关于Service的讲解网上已经很多了,这里是关于自己通过写代码Service的一点体会 还有结合其他人对Service的一点总结 Service可以理解为一个隐形的Activity 但它又与Activity有些不同,首先Service是没界面,用户看不到 可交互的组件 级别是与Activity是差不多的 Service中定义了一系列和自身声明周期相关的方法: onBind(...)是必须实现的方法,返回一个绑定

  • Android Service中方法使用详细介绍

     service作为四大组件值得我们的更多的关注 在Android中,Activity主要负责前台页面的展示,Service主要负责需要长期运行的任务.例如,一个从service播放音乐的音乐播放器,应被设置为前台运行,因为用户会明确地注意它的运行.在状态栏中的通知可能会显示当前的歌曲并且允许用户启动一个activity来与音乐播放器交互. Service的两种实现形式 1.非绑定 通过调用应用程序组件(例如Activity)的startService()方法来启动一个服务.一旦启动,服务就会在

  • Android中Service的全面总结

    全面总结Android Service的使用方法,具体内容如下 1.Service的种类 按运行地点分类: 其实remote服务还是很少见的,并且一般都是系统服务. 按运行类型分类: 有同学可能会问,后台服务我们可以自己创建 ONGOING 的 Notification 这样就成为前台服务吗?答案是否定的,前台服务是在做了上述工作之后需要调用 startForeground ( android 2.0 及其以后版本 )或 setForeground (android 2.0 以前的版本)使服务成

  • 浅谈Android中Service的注册方式及使用

    Service通常总是称之为"后台服务",其中"后台"一词是相对于前台而言的,具体是指其本身的运行并不依赖于用户可视的UI界面,因此,从实际业务需求上来理解,Service的适用场景应该具备以下条件: 1.并不依赖于用户可视的UI界面(当然,这一条其实也不是绝对的,如前台Service就是与Notification界面结合使用的): 2.具有较长时间的运行特性. 1.Service AndroidManifest.xml 声明 一般而言,从Service的启动方式上

  • 浅谈Android中适配器的notifyDataSetChanged()为何有时不刷新

    学过Android开发的人都知道,ListView控件在开发中经常遇到,并且ListView通常结合Adapter适配器来进行数据显示和数据更新操作.姑且假设数据存储在名为dataList的成员变量中.数据操作无非是增加数据.删除数据这两种主要的操作,而当数据有所变化时,为了及时向用户提供更新后的数据,我们知道需要在数据更新后调用适配器的notifyDataSetChanged()方法,来显示更新后的数据.殊不知,该方法并非百试不爽,在此我们便来讨论下具体的原因,其实本质是关注内存的分配情况.

  • 浅谈Android中AsyncTask的工作原理

    概述 实际上,AsyncTask内部是封装了Thread和Handler.虽然AsyncTask很方便的执行后台任务,以及在主线程上更新UI,但是,AsyncTask并不合适进行特别耗时的后台操作,对于特别耗时的任务,个人还是建议使用线程池.好了,话不多说了,我们先看看AsyncTask的简单用法吧. AsyncTask使用方法 AsyncTask是一个抽象的泛型类.简单的介绍一下它的使用方式代码如下: package com.example.huangjialin.myapplication;

  • 浅谈vue中所有的封装方式总结

    目录 1.封装API 2.注册全局工具组件 3.封装全局函数 4. 为了减少页面代码量的封装 如何确定我需要封装呢? 1.复用,如果觉得以后还会用到 2.你觉得方便,别的地方可能也需要用 3.如果不封装,页面代码臃肿的时候 1.封装API 使用场景:业务中最常见最普通的封装 步骤一: 步骤二:  步骤三:  2.注册全局工具组件 使用场景:想让组件全局可用,尤其是第三方插件使用时 步骤一:   步骤二: 3.封装全局函数 使用场景:有些逻辑处理函数代码量很大,且具有独特功能(如日期处理函数,数组

  • 浅谈android中数据库的拷贝

    SQLiteDatabase不支持直接从assets读取文件,所以要提前拷贝数据库.在读取数据库时,先在项目中建立assets文件夹用于存放外部文件,将数据库文件拷到该目录下. 代码方法: /** * 拷贝数据库至file文件夹下 * @param dbName 数据库名称 */ private void initAddressDB(String dbName) { //1,在files文件夹下创建同名dbName数据库文件过程 File files=getFilesDir();//获取/dat

  • 浅谈HashMap中7种遍历方式的性能分析

    目录 一.前言 二.HashMap遍历 2.1.迭代器EntrySet 2.2.迭代器 KeySet 2.3.ForEachEntrySet 2.4.ForEach KeySet 2.5.Lambda 2.6.Streams API 单线程 2.7.Streams API 多线程 三.性能分析 四.字节码分析 五.EntrySet性能分析 六.安全性测试 6.1.迭代器方式 6.2.For 循环方式 6.3.Lambda 方式 6.4.Stream 方式 6.5.小结 七.总结 一.前言 随着

  • 浅谈Python3中打开文件的方式(With open)

    目录 0.背景知识 1.常规方式:读取文件-----open() 2.推荐方式:读取文件-----With Open 1).读取方式 2).常见的坑 3).跳过第一行内容(字段名) 3.写入内容----open()函数 4.写入内容----- With Open函数 5.打开非utf-8编码的文件 6.打开二进制文件 0.背景知识 python文件读写文件是最常见的IO操作.Python内置了读写文件的函数,用法和C是兼容的. 读写文件前,我们先必须了解一下,在磁盘上读写文件的功能都是由操作系统

  • 浅谈Android中多线程切换的几种方法

    我们知道,多线程是Android开发中必现的场景,很多原生API和开源项目都有多线程的内容,这里简单总结和探讨一下常见的多线程切换方式. 我们先回顾一下Java多线程的几个基础内容,然后再分析总结一些经典代码中对于线程切换的实现方式. 几点基础 多线程切换,大概可以切分为这样几个内容:如何开启多个线程,如何定义每个线程的任务,如何在线程之间互相通信. Thread Thread可以解决开启多个线程的问题. Thread是Java中实现多线程的线程类,每个Thread对象都可以启动一个新的线程,注

  • 浅谈Android中关于静态变量(static)的使用问题

    项目中,在不停地接收串口数据很长一段时间(几小时)后,会偶然性的报错.初步排除了oom和cpu紧张问题,因为是工业平板不方便调试,用了些比较笨的方法最后锁定在几个用了static的地方.在这里记录下Android中使用static的一些问题. 静态变量的生命周期遵守Java的设计.静态变量在类被load的时候分配内存,并存在于方法区.当类被卸载时,静态变量被销毁.在PC机的客户端程序中,一个类被加载和卸载,可简单的等同于jvm进程的启动和结束.在Android中,用的DVM也是一样的,不过And

  • 浅谈Android中Drawable使用知识总结

    本文是学习<Android开发艺术探索>中Drawable章节之后的一个总结. Drawable在我们平时的开发中,基本都会用到,而且给大家非常的有用.那么什么是Drawable呢?能够在canvas上绘制的一个玩意,而且相比于View,并不需要去考虑measure.layout,仅仅只要去考虑如何draw(canavs).当然了,对于Drawable传统的用法,大家肯定不陌生 ,今天主要给大家带来以下几个Drawable的用法: 1.自定义Drawable,相比View来说,Drawable

随机推荐