简介
Service 是Android四大组件之一。与Activity比较相似,它们都代表可执行的程序。Service与Activity的区别在于:Service一直在后台运行,它没有用户界面,具有自己的生命周期。在开发中,如果某个程序组件需要在运行时向用户呈现某种界面,或者该程序需要与用户交互,就需要使用Activity,否则就应该考虑Service。
Service分类
按照启动方式的不同Service可以分为两类:
1>Started Service :在后台,作为一个独立的可执行单元不能与调用者进行交互,适合在后台做一些独立的耗时任务,比如:下载、上传。
2>Bound Service :类似client-server模式,此类Service可被多个client端绑定,client与Service可实现双向通信。
下面就按照此分类介绍其创建、启动、销毁、生命周期等一系列知识
1>Started Service
A.创建Service步骤:
类似Activity的开发步骤:1.开发一个Activity子类 2.在配置文件中配置Activity,开发Service也需要两个步骤。
1》定义一个派生自Service或ServiceIntent的子类。
2》在AndroidManifest.xml中配置之
配置示例代码:
<manifest ... >
...
<application ... >
<service android:name=".ExampleService" />
...
</application>
</manifest>
Note:Service 的配置与Activity基本相同,如果开发的Service只供本应用调用则不需要为其配置intent-filter 标签。Service标签下可以配置许多属性,了解更多请参考这里
示例1:继承自Service
View Code
1 package com.example.services;
2
3 import android.app.Service;
4 import android.content.Intent;
5 import android.os.IBinder;
6
7 public class Myservice extends Service {
8
9 @Override
10 public IBinder onBind(Intent intent) {
11 System.out.println("onBind");
12 return null;
13 }
14
15 @Override
16 public void onCreate() {
17 System.out.println("onCreate");
18 super.onCreate();
19 }
20
21 @Override
22 public int onStartCommand(Intent intent, int flags, int startId) {
23 System.out.println("onStartCommand");
24 return super.onStartCommand(intent, flags, startId);
25
26 }
27
28 @Override
29 public void onDestroy() {
30 System.out.println("onDestroy");
31 super.onDestroy();
32 }
33 }
示例2:继承自ServiceIntent
View Code
1 package com.example.services;
2
3 import android.content.Intent;
4
5 public class ExtendIntentService extends android.app.IntentService {
6
7 public ExtendIntentService() {
8 super("ExtendIntentService");
9 }
10
11 @Override
12 protected void onHandleIntent(Intent intent) {
13 System.out
14 .println("onHandleIntent:" + Thread.currentThread().getName());
15 }
16
17 @Override
18 public void onCreate() {
19 super.onCreate();
20 System.out.println("onCreate:" + Thread.currentThread().getName());
21 }
22
23 @Override
24 public int onStartCommand(Intent intent, int flags, int startId) {
25 System.out
26 .println("onStartCommand:" + Thread.currentThread().getName());
27 return super.onStartCommand(intent, flags, startId);
28 }
29
30 @Override
31 public void onDestroy() {
32 super.onDestroy();
33 System.out.println("onDestroy");
34 }
35
36 }
分析:
示例1
继承自Service类,需要我们根据需要实现特定的几个回调方法主要有以下几个:
onBind(Intent intent):该方法是子类必须要实现的方法。该方法返回一个IBinder对象,应用程序可通过此对象与Service通信。
onCreate():当Service第一次被创建时将回调此方法。
onDestroy():当该Service被销毁时将回调此方法。
onStart(Intent intent, int startId):已被标注Deprecated,被onStartCommand方法取代,其实onStartCommand在内部也是调用onStart,只是多了个int返回值。
int onStartCommand(Intent intent, int flags, int startId):该方法的早期版本是onStart(Intent intent, int startId),每当客户端调用startService(Intent)时系统将 回调此方法。其有一个int返回值,系统根据此值决定当系统由于某种原因(比如:内存紧张)销毁此service后,是否重启它及对intent的处理细节。
onUnbind(Intent intent):当service上绑定的所有方法都断开链接时,将回调此方法。
通过这种方式,我们操作的灵活性较高,但请注意对于某些耗时性的操作我们应该为其开一个单独的线程,以防阻塞UI主线程,因为Service也是运行在主线程中的,对于某些实时性要求较高的请求,我们也可以为其开单独的线程处理。
示例2
ServiceIntent也是Service的一个子类,里面默认实现好了一套消息处理机制(一个单独的线程,Handler,Looper),在onHandleIntent中是按照FIFO的方式处理所有Client发送过来的intent请求。
B.启动Service
这里只讲通过startService(intent)方式,另一种方式将在下面介绍。我们一般会在Activity中开启一个Service,示例代码:
1 final Intent intent_Service = new Intent(this,
2 ExtendIntentService.class);
3
4 findViewById(R.id.start).setOnClickListener(new OnClickListener() {
5
6 @Override
7 public void onClick(View v) {
8 System.out.println("startService");
9 startService(intent);
10 }
11 });
View Code
C.关闭Service
通过start方式启动service,此service并不会自己销毁,即使启动它的组件(比如:Activity)已销毁。所以当我们通过这种方式启动service后一定要记得在合适的时机主动关闭它。我们可以通过stopService(intent)方法在某个组件中关闭,也可以通过stopSelf()方法,在service中关闭。stopService方法还有另一种形式:void stopSelf(int startId),startId用于区分不同的intent的请求。此方法的作用是:我们可以在Service中每处理完一个请求,就调用一次stopSelf(int startId)方法,但此方法并不会真正关闭service,只有当service中所有的请求都处理完后才会关闭service.此方法可防止出现任务未处理完就关闭Service的情况。
D.生命周期
图1
说明:上面我们所讲的对应此图的左半幅,即通过start方式。
2>Bound Service
A.创建步骤
1>写一个继承自Service的子类
2>在1>中定义的Service中实现一个IBinder类型的接口,以供onBind方法返回到client端,client与service也是通过此接口实现通信的
IBinder类型的接口,有三种实现方式:
1>继承Binder类:如果你开发的Service只供当前应用使用,采用这种方式是最佳的。在此Binder类中要实现一些公共的方法以供client端调用,或者返回当前service实例。
示例:
1 public class LocalService extends Service {
2 // Binder given to clients
3 private final IBinder mBinder = new LocalBinder();
4 // Random number generator
5 private final Random mGenerator = new Random();
6
7 /**
8 * Class used for the client Binder. Because we know this service always
9 * runs in the same process as its clients, we don't need to deal with IPC.
10 */
11 public class LocalBinder extends Binder {
12 LocalService getService() {
13 // Return this instance of LocalService so clients can call public methods
14 return LocalService.this;
15 }
16 }
17
18 @Override
19 public IBinder onBind(Intent intent) {
20 return mBinder;
21 }
22
23 /** method for clients */
24 public int getRandomNumber() {
25 return mGenerator.nextInt(100);
26 }
27 }
View Code
1 public class BindingActivity extends Activity {
2 LocalService mService;
3 boolean mBound = false;
4
5 @Override
6 protected void onCreate(Bundle savedInstanceState) {
7 super.onCreate(savedInstanceState);
8 setContentView(R.layout.main);
9 }
10
11 @Override
12 protected void onStart() {
13 super.onStart();
14 // Bind to LocalService
15 Intent intent = new Intent(this, LocalService.class);
16 bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
17 }
18
19 @Override
20 protected void onStop() {
21 super.onStop();
22 // Unbind from the service
23 if (mBound) {
24 unbindService(mConnection);
25 mBound = false;
26 }
27 }
28
29 /** Called when a button is clicked (the button in the layout file attaches to
30 * this method with the android:onClick attribute) */
31 public void onButtonClick(View v) {
32 if (mBound) {
33 // Call a method from the LocalService.
34 // However, if this call were something that might hang, then this request should
35 // occur in a separate thread to avoid slowing down the activity performance.
36 int num = mService.getRandomNumber();
37 Toast.makeText(this, "number: " + num, Toast.LENGTH_SHORT).show();
38 }
39 }
40
41 /** Defines callbacks for service binding, passed to bindService() */
42 private ServiceConnection mConnection = new ServiceConnection() {
43
44 @Override
45 public void onServiceConnected(ComponentName className,
46 IBinder service) {
47 // We've bound to LocalService, cast the IBinder and get LocalService instance
48 LocalBinder binder = (LocalBinder) service;
49 mService = binder.getService();
50 mBound = true;
51 }
52
53 @Override
54 public void onServiceDisconnected(ComponentName arg0) {
55 mBound = false;
56 }
57 };
58 }
View Code
2>利用Messenger:如果你的service要提供被别的应用访问的功能(进程间访问)就要利用此方式
示例:
1 public class MessengerService extends Service {
2 /** Command to the service to display a message */
3 static final int MSG_SAY_HELLO = 1;
4
5 /**
6 * Handler of incoming messages from clients.
7 */
8 class IncomingHandler extends Handler {
9 @Override
10 public void handleMessage(Message msg) {
11 switch (msg.what) {
12 case MSG_SAY_HELLO:
13 Toast.makeText(getApplicationContext(), "hello!", Toast.LENGTH_SHORT).show();
14 break;
15 default:
16 super.handleMessage(msg);
17 }
18 }
19 }
20
21 /**
22 * Target we publish for clients to send messages to IncomingHandler.
23 */
24 final Messenger mMessenger = new Messenger(new IncomingHandler());
25
26 /**
27 * When binding to the service, we return an interface to our messenger
28 * for sending messages to the service.
29 */
30 @Override
31 public IBinder onBind(Intent intent) {
32 Toast.makeText(getApplicationContext(), "binding", Toast.LENGTH_SHORT).show();
33 return mMessenger.getBinder();
34 }
35 }
View Code
1 public class ActivityMessenger extends Activity {
2 /** Messenger for communicating with the service. */
3 Messenger mService = null;
4
5 /** Flag indicating whether we have called bind on the service. */
6 boolean mBound;
7
8 /**
9 * Class for interacting with the main interface of the service.
10 */
11 private ServiceConnection mConnection = new ServiceConnection() {
12 public void onServiceConnected(ComponentName className, IBinder service) {
13 // This is called when the connection with the service has been
14 // established, giving us the object we can use to
15 // interact with the service. We are communicating with the
16 // service using a Messenger, so here we get a client-side
17 // representation of that from the raw IBinder object.
18 mService = new Messenger(service);
19 mBound = true;
20 }
21
22 public void onServiceDisconnected(ComponentName className) {
23 // This is called when the connection with the service has been
24 // unexpectedly disconnected -- that is, its process crashed.
25 mService = null;
26 mBound = false;
27 }
28 };
29
30 public void sayHello(View v) {
31 if (!mBound) return;
32 // Create and send a message to the service, using a supported 'what' value
33 Message msg = Message.obtain(null, MessengerService.MSG_SAY_HELLO, 0, 0);
34 try {
35 mService.send(msg);
36 } catch (RemoteException e) {
37 e.printStackTrace();
38 }
39 }
40
41 @Override
42 protected void onCreate(Bundle savedInstanceState) {
43 super.onCreate(savedInstanceState);
44 setContentView(R.layout.main);
45 }
46
47 @Override
48 protected void onStart() {
49 super.onStart();
50 // Bind to the service
51 bindService(new Intent(this, MessengerService.class), mConnection,
52 Context.BIND_AUTO_CREATE);
53 }
54
55 @Override
56 protected void onStop() {
57 super.onStop();
58 // Unbind from the service
59 if (mBound) {
60 unbindService(mConnection);
61 mBound = false;
62 }
63 }
64 }
View Code
3>利用AIDL
待续...
B.绑定到Service
通过bindService (Intent service, ServiceConnection conn, int flags)方法。第一个参数就是一个普通的Intent包含了所要绑定的Service名。第二个参数ServiceConnection需要我们自己在Client端定义。里面有两个方法要我们实现。一个是onServiceConnected(ComponentName name, IBinder service),此方法会在绑定成功时被回调,其中的第二个参数service就是那个我们在Service中定义的接口,通过它我们可以访问Service,以实现某些功能。void onServiceDisconnected (ComponentName name),当client与service断开连接时将回调此方法。
C.生命周期
总结:
1>service可以分为两种:1.started service; 2.Bound service。
2>started service:与启动方无关联,被启动后在后台作为一个独立的执行单元运行,此类service一定要记得关闭,否则会一直在后台运行。有两种关闭方式a.在某个组件类中调用stopService方法 b.在service内部合适的地方与时机(任务完成时)调用stopSelf方法。此类service适合在后台做一些较独立的任务,比如:下载、上传...
3>Bound service:此类service类似client-server模式中的server端,一个server可以被不同的组件绑定。绑定成功后,可以调用service内容提供的公共方法。此类service还可以提供进程间的通信。当所有的客户端都与其断开连接后,系统将回调其onDestroy方法,因此针对此类型的service不需要我们显式去关闭。
4>一个通过startService方法启动后的service,还可以被别的组件通过bindService方法绑定。
5>service作为android的四大组件之一,它也是运行在主线程中的。因此,如果要在service中作耗时性的操作最好要开新的线程。
6>由于系统资源紧张问题,导致service被系统杀死,在以后某个时刻资源不再紧张,则系统会自动重启它。具体规则可以看onStartCommand方法的返回值 。 7>对于bound型service,若开启它的组件(比如activity)销毁后,此service也会被销毁,不管是否在那个activity的onDestory中调用unBindService方法。
ps:有点懒了,示例代码直接copy的官方文档中的。还有很多细节并没有介绍到。官方文档中介绍的真是太全了,英语还行的朋友,建议直接看文档。