本文的主要内容来源于Services和Bound Services,均为google官方文档,如果英文好的话建议直接看原文。下面主要是我自己的一些笔记。
Service
Service是android的四大组件之一,平常用的最多的也就是activity,其他三个都只会在特定的情景下才会使用,所以接触的机会不会太多。这次主要是要在android上做一个计步功能,需要使用到service在后台计步。总的来说,service可以在后台长时间运行一个任务而不依赖于界面,它可以在后台处理网络请求,播放音乐,文件读写等等。
Service有两种启动方式,startService()和bindService(),下面主要介绍两种创建方式。
在使用service之前,需要在manifest文件中声明该service
service的主要方法有:
onStartCommand() 通过startService启动时,会调用该方法,使用这个方法启动的service会一直在后台运行,除非遇到stopSelf()或者stopService()才会停止
onBind() 通过bindService()启动时,会调用该方法,使用这个方法需要提供一个client和service通信的接口(ServiceConnction,比较麻烦)
onCreate() 这个方法会在onStartCommand或onBind之前调用,也就是不管已那种方式启动,第一次创建时都会执行该函数
onDestroy() 这个方法会在系统kill该service时调用,该函数应该释放一些线程、注册监听器、接收器的资源
第一种创建方式 startService()
在activity等组件里通过startService启动service,该方法可以传递一个Intent对象给onStartCommand()。下面介绍两个创建service的类
Service, 这是所有services的基类,直接集成该类,需要新起一个线程,因为该类默认是在主线程中运行的。
IntentService, 这是一个Service的子类,它会在子线程中处理请求,你只需要实现一个onHandlerIntent()方法就可以了。
IntentService例子
public class HelloIntentService extends IntentService {
/**
* A constructor is required, and must call the super IntentService(String)
* constructor with a name for the worker thread.
*/
public HelloIntentService() {
super("HelloIntentService");
}
/**
* The IntentService calls this method from the default worker thread with
* the intent that started the service. When this method returns, IntentService
* stops the service, as appropriate.
*/
@Override
protected void onHandleIntent(Intent intent) {
// Normally we would do some work here, like download a file.
// For our sample, we just sleep for 5 seconds.
long endTime = System.currentTimeMillis() + 5*1000;
while (System.currentTimeMillis() < endTime) {
synchronized (this) {
try {
wait(endTime - System.currentTimeMillis());
} catch (Exception e) {
}
}
}
}
}
Intent例子
public class HelloService extends Service { private Looper mServiceLooper; private ServiceHandler mServiceHandler; // Handler that receives messages from the thread private final class ServiceHandler extends Handler { public ServiceHandler(Looper looper) { super(looper); } @Override public void handleMessage(Message msg) { // Normally we would do some work here, like download a file. // For our sample, we just sleep for 5 seconds. long endTime = System.currentTimeMillis() + 5*1000; while (System.currentTimeMillis() < endTime) { synchronized (this) { try { wait(endTime - System.currentTimeMillis()); } catch (Exception e) { } } } // Stop the service using the startId, so that we don't stop // the service in the middle of handling another job stopSelf(msg.arg1); } } @Override public void onCreate() { // Start up the thread running the service. Note that we create a // separate thread because the service normally runs in the process's // main thread, which we don't want to block. We also make it // background priority so CPU-intensive work will not disrupt our UI. HandlerThread thread = new HandlerThread("ServiceStartArguments", Process.THREAD_PRIORITY_BACKGROUND); thread.start(); // Get the HandlerThread's Looper and use it for our Handler mServiceLooper = thread.getLooper(); mServiceHandler = new ServiceHandler(mServiceLooper); } @Override public int onStartCommand(Intent intent, int flags, int startId) { Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show(); // For each start request, send a message to start a job and deliver the // start ID so we know which request we're stopping when we finish the job Message msg = mServiceHandler.obtainMessage(); msg.arg1 = startId; mServiceHandler.sendMessage(msg); // If we get killed, after returning from here, restart return START_STICKY; } @Override public IBinder onBind(Intent intent) { // We don't provide binding, so return null return null; } @Override public void onDestroy() { Toast.makeText(this, "service done", Toast.LENGTH_SHORT).show(); } }开启一个Service
Intent intent = new Intent(this, HelloService.class); startService(intent);可以通过startForeground()让Service运行在前台,在前台运行的service必须在通知栏里面提供一个status bar,这样的service在low memory的时候不会被系统杀掉,就像播放音乐的应用在通知栏里面有一栏显示当前歌曲一样。
Service的生命周期如下:
Bound Service主要用于service和别的组件的通信,允许别的组件绑定到service上,发送请求接受返回值来进行通信,当然前提是servcie实现了onBind方法,允许别的组件绑定。
主要有三种方式,
1.继承Binder类,用于同一应用之间的通信
2.Messenger,用于应用间的通信
3.AIDL, 通过先让servcie同一时间内处理多个请求,可直接使用该方法
我的项目用的是第一种,使用方法如下:
public class LocalService extends Service { // Binder given to clients private final IBinder mBinder = new LocalBinder(); // Random number generator private final Random mGenerator = new Random(); /** * Class used for the client Binder. Because we know this service always * runs in the same process as its clients, we don't need to deal with IPC. */ public class LocalBinder extends Binder { LocalService getService() { // Return this instance of LocalService so clients can call public methods return LocalService.this; } } @Override public IBinder onBind(Intent intent) { return mBinder; } /** method for clients */ public int getRandomNumber() { return mGenerator.nextInt(100); } }
上面的例子中,在LocalBinder中提供了一个getService()的方法,该方法提供了一个LocalService的当前对象实例,它可以给客户端用来调用service中的公用方法,比如此时,在客户端中就可以从service重调用getRandomNumber()
public class BindingActivity extends Activity { LocalService mService; boolean mBound = false; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); } @Override protected void onStart() { super.onStart(); // Bind to LocalService Intent intent = new Intent(this, LocalService.class); bindService(intent, mConnection, Context.BIND_AUTO_CREATE); } @Override protected void onStop() { super.onStop(); // Unbind from the service if (mBound) { unbindService(mConnection); mBound = false; } } /** Called when a button is clicked (the button in the layout file attaches to * this method with the android:onClick attribute) */ public void onButtonClick(View v) { if (mBound) { // Call a method from the LocalService. // However, if this call were something that might hang, then this request should // occur in a separate thread to avoid slowing down the activity performance. int num = mService.getRandomNumber(); Toast.makeText(this, "number: " + num, Toast.LENGTH_SHORT).show(); } } /** Defines callbacks for service binding, passed to bindService() */ private ServiceConnection mConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName className, IBinder service) { // We've bound to LocalService, cast the IBinder and get LocalService instance LocalBinder binder = (LocalBinder) service; mService = binder.getService(); mBound = true; } @Override public void onServiceDisconnected(ComponentName arg0) { mBound = false; } }; }
Activity的客户端在绑定service时,实现了一个ServiceConnection类,该类在client和service建立通信时,会调用起回调函数onServiceConnected()
BoundService的生命周期如下: