d總結(jié)篇系列:Android ServiceService通??偸欠Q之為“后臺(tái)服務(wù)”,其中“后臺(tái)”一詞是相對于前臺(tái)而言的,具體是指其本身的運(yùn)行并不依賴于用戶可視的UI界面,因此,從實(shí)際業(yè)務(wù)需求上來理解,Service的適用場景應(yīng)該具備以下條件: 1.并不依賴于用戶可視的UI界面(當(dāng)然,這一條其實(shí)也不是絕對的,如前臺(tái)Service就是與Notification界面結(jié)合使用的); 2.具有較長時(shí)間的運(yùn)行特性。 1.Service AndroidManifest.xml 聲明 一般而言,從Service的啟動(dòng)方式上,可以將Service分為Started Service和Bound Service。無論哪種具體的Service啟動(dòng)類型,都是通過繼承Service基類自定義而來。在使用Service時(shí),要想系統(tǒng)能夠找到此自定義Service,無論哪種類型,都需要在AndroidManifest.xml中聲明,語法格式如下: 1 <service android:enabled=["true" | "false"]
2 android:exported=["true" | "false"]
3 android:icon="drawable resource"
4 android:isolatedProcess=["true" | "false"]
5 android:label="string resource"
6 android:name="string"
7 android:permission="string"
8 android:process="string" >
9 . . .
10 </service>
其中,android:exported屬性上一篇博文中對此已進(jìn)行詳盡描述,android:name對應(yīng)Service類名,android:permission是權(quán)限聲明,android:process設(shè)置具體的進(jìn)程名稱。需要注意的是Service能否單獨(dú)使用一個(gè)進(jìn)程與其啟動(dòng)方式有關(guān),本后下面會(huì)給出具體說明。其他的屬性此處與其他組件基本相同,不再過多描述。 注:如果自定義Service沒有在AndroidManifest.xml中聲明,當(dāng)具體使用時(shí),不會(huì)像Activity那樣直接崩潰報(bào)錯(cuò),對于顯式Intent啟動(dòng)的Service,此時(shí)也會(huì)給出waring信息“IllegalArgumentException: Service not registered”,有時(shí)候不容易發(fā)現(xiàn)忘了聲明而一時(shí)定位不到問題。
2.Started Service Started Service相對比較簡單,通過context.startService(Intent serviceIntent)啟動(dòng)Service,context.stopService(Intent serviceIntent)停止此Service。當(dāng)然,在Service內(nèi)部,也可以通過stopSelf(...)方式停止其本身。 1)Started Service自定義 下面代碼片段顯示的是一個(gè)最基本的Started Service的自定義方式: 1 public class MyService extends Service {
2
3 public static final String TAG = "MyService";
4
5 @Override
6 public IBinder onBind(Intent intent) {
7 return null;
8 }
9
10 @Override
11 public void onCreate() {
12 super.onCreate();
13 Log.w(TAG, "in onCreate");
14 }
15
16 @Override
17 public int onStartCommand(Intent intent, int flags, int startId) {
18 Log.w(TAG, "in onStartCommand");
19 Log.w(TAG, "MyService:" + this);
20 String name = intent.getStringExtra("name");
21 Log.w(TAG, "name:" + name);
22 return START_STICKY;
23 }
24
25 @Override
26 public void onDestroy() {
27 super.onDestroy();
28 Log.w(TAG, "in onDestroy");
29 }
30 }
其中,onBind(...)函數(shù)是Service基類中的唯一抽象方法,子類都必須重寫實(shí)現(xiàn),此函數(shù)的返回值是針對Bound Service類型的Service才有用的,在Started Service類型中,此函數(shù)直接返回 null 即可。onCreate(...)、onStartCommand(...)和onDestroy()都是Started Service相應(yīng)生命周期階段的回調(diào)函數(shù)。 2) Started Service使用 1 public class MainActivity extends Activity {
2
3 public static final String TAG = "MainActivity";
4
5 private Button startServiceBtn;
6 private Button stopServideBtn;
7 private Button goBtn;
8
9 private Intent serviceIntent;
10
11 @Override
12 protected void onCreate(Bundle savedInstanceState) {
13 super.onCreate(savedInstanceState);
14 setContentView(R.layout.activity_main);
15
16 startServiceBtn = (Button) findViewById(R.id.start_service);
17 stopServideBtn = (Button) findViewById(R.id.stop_service);
18 goBtn = (Button) findViewById(R.id.go);
19
20 startServiceBtn.setOnClickListener(new View.OnClickListener() {
21 @Override
22 public void onClick(View v) {
23 serviceIntent = new Intent(MainActivity.this, MyService.class);
24 startService(serviceIntent);
25 }
26 });
27
28 stopServideBtn.setOnClickListener(new View.OnClickListener() {
29 @Override
30 public void onClick(View v) {
31 stopService(serviceIntent);
32 }
33 });
34
35 goBtn.setOnClickListener(new View.OnClickListener() {
36 @Override
37 public void onClick(View v) {
38 Intent intent = new Intent(MainActivity.this, BActivity.class);
39 startActivity(intent);
40 }
41 });
42
43 }
44
45 @Override
46 protected void onDestroy() {
47 super.onDestroy();
48 Log.w(TAG, "in onDestroy");
49 }
50 }
如上代碼片段, 當(dāng)Client調(diào)用startService(Intent serviceIntent)后,如果MyService是第一次啟動(dòng),首先會(huì)執(zhí)行 onCreate()回調(diào),然后再執(zhí)行onStartCommand(Intent intent, int flags, int startId),當(dāng)Client再次調(diào)用startService(Intent serviceIntent),將只執(zhí)行onStartCommand(Intent intent, int flags, int startId),因?yàn)榇藭r(shí)Service已經(jīng)創(chuàng)建了,無需執(zhí)行onCreate()回調(diào)。無論多少次的startService,只需要一次stopService()即可將此Service終止,執(zhí)行onDestroy()函數(shù)(其實(shí)很好理解,因?yàn)閛nDestroy()與onCreate()回調(diào)是相對的)。 下面重點(diǎn)關(guān)注下onStartCommand(Intent intent, int flags, int startId)方法。 其中參數(shù)flags默認(rèn)情況下是0,對應(yīng)的常量名為START_STICKY_COMPATIBILITY。startId是一個(gè)唯一的整型,用于表示此次Client執(zhí)行startService(...)的請求請求標(biāo)識(shí),在多次startService(...)的情況下,呈現(xiàn)0,1,2....遞增。另外,此函數(shù)具有一個(gè)int型的返回值,具體的可選值及含義如下: START_NOT_STICKY:當(dāng)Service因?yàn)閮?nèi)存不足而被系統(tǒng)kill后,接下來未來的某個(gè)時(shí)間內(nèi),即使系統(tǒng)內(nèi)存足夠可用,系統(tǒng)也不會(huì)嘗試重新創(chuàng)建此Service。除非程序中Client明確再次調(diào)用startService(...)啟動(dòng)此Service。 START_STICKY:當(dāng)Service因?yàn)閮?nèi)存不足而被系統(tǒng)kill后,接下來未來的某個(gè)時(shí)間內(nèi),當(dāng)系統(tǒng)內(nèi)存足夠可用的情況下,系統(tǒng)將會(huì)嘗試重新創(chuàng)建此Service,一旦創(chuàng)建成功后將回調(diào)onStartCommand(...)方法,但其中的Intent將是null,pendingintent除外。 START_REDELIVER_INTENT:與START_STICKY唯一不同的是,回調(diào)onStartCommand(...)方法時(shí),其中的Intent將是非空,將是最后一次調(diào)用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。此值一般不會(huì)使用,所以注意前面三種情形就好。 以上的描述中,”當(dāng)Service因?yàn)閮?nèi)存不足而被系統(tǒng)kill后“一定要非常注意,因?yàn)榇撕瘮?shù)的返回值設(shè)定只是針對此種情況才有意義的,換言之,當(dāng)認(rèn)為的kill掉Service進(jìn)程,此函數(shù)返回值無論怎么設(shè)定,接下來未來的某個(gè)時(shí)間內(nèi),即使系統(tǒng)內(nèi)存足夠可用,Service也不會(huì)重啟。 小米手機(jī)針對此處做了變更: 另外,需要注意的是,小米手機(jī)針對此處做了一定的修改。在“自啟動(dòng)管理”中有一個(gè)自啟動(dòng)應(yīng)用列表,默認(rèn)情況下,只有少應(yīng)用(如微信、QQ、YY、360等)默認(rèn)是可以自啟動(dòng)的,其他應(yīng)用默認(rèn)都是禁止的。用戶可以手動(dòng)添加自啟動(dòng)應(yīng)用,添加后的應(yīng)用中如果Started Service onStartCommand(...)回調(diào)返回值是START_STICKY或START_REDELIVER_INTENT,當(dāng)用戶在小米手機(jī)上長按Home鍵結(jié)束App后,接下來未來的某個(gè)時(shí)間內(nèi),當(dāng)系統(tǒng)內(nèi)存足夠可用時(shí),Service依然可以按照上述規(guī)定重啟。當(dāng)然,如果用戶在 設(shè)置 >> 應(yīng)用 >> 強(qiáng)制kill掉App進(jìn)程,此時(shí)Service是不會(huì)重啟的。 注:以上實(shí)驗(yàn)結(jié)論基于小米2S親測。
3) Started Service生命周期及進(jìn)程相關(guān) 1.onCreate(Client首次startService(..)) >> onStartCommand >> onStartCommand - optional ... >> onDestroy(Client調(diào)用stopService(..)) 注:onStartCommand(..)可以多次被調(diào)用,onDestroy()與onCreate()想匹配,當(dāng)用戶強(qiáng)制kill掉進(jìn)程時(shí),onDestroy()是不會(huì)執(zhí)行的。 2.對于同一類型的Service,Service實(shí)例一次永遠(yuǎn)只存在一個(gè),而不管Client是否是相同的組件,也不管Client是否處于相同的進(jìn)程中。 3.Service通過startService(..)啟動(dòng)Service后,此時(shí)Service的生命周期與Client本身的什么周期是沒有任何關(guān)系的,只有Client調(diào)用stopService(..)或Service本身調(diào)用stopSelf(..)才能停止此Service。當(dāng)然,當(dāng)用戶強(qiáng)制kill掉Service進(jìn)程或系統(tǒng)因內(nèi)存不足也可能kill掉此Service。 4.Client A 通過startService(..)啟動(dòng)Service后,可以在其他Client(如Client B、Client C)通過調(diào)用stopService(..)結(jié)束此Service。 5.Client調(diào)用stopService(..)時(shí),如果當(dāng)前Service沒有啟動(dòng),也不會(huì)出現(xiàn)任何報(bào)錯(cuò)或問題,也就是說,stopService(..)無需做當(dāng)前Service是否有效的判斷。 6.startService(Intent serviceIntent),其中的intent既可以是顯式Intent,也可以是隱式Intent,當(dāng)Client與Service同處于一個(gè)App時(shí),一般推薦使用顯示Intent。當(dāng)處于不同App時(shí),只能使用隱式Intent。 當(dāng)Service需要運(yùn)行在單獨(dú)的進(jìn)程中,AndroidManifest.xml聲明時(shí)需要通過android:process指明此進(jìn)程名稱,當(dāng)此Service需要對其他App開放時(shí),android:exported屬性值需要設(shè)置為true(當(dāng)然,在有intent-filter時(shí)默認(rèn)值就是true)。 1 <service
2 android:name=".MyService"
3 android:exported="true"
4 android:process=":MyCorn" >
5 <intent-filter>
6 <action android:name="com.example.androidtest.myservice" />
7 </intent-filter>
8 </service>
4)Started Service Client與Service通信相關(guān) 當(dāng)Client調(diào)用startService(Intent serviceIntent)啟動(dòng)Service時(shí),Client可以將參數(shù)通過Intent直接傳遞給Service。Service執(zhí)行過程中,如果需要將參數(shù)傳遞給Client,一般可以通過借助于發(fā)送廣播的方式(此時(shí),Client需要注冊此廣播)。
3.Bound Service 相對于Started Service,Bound Service具有更多的知識(shí)點(diǎn)。Bound Service的主要特性在于Service的生命周期是依附于Client的生命周期的,當(dāng)Client不存在時(shí),Bound Service將執(zhí)行onDestroy,同時(shí)通過Service中的Binder對象可以較為方便進(jìn)行Client-Service通信。Bound Service一般使用過程如下: 1.自定義Service繼承基類Service,并重寫onBind(Intent intent)方法,此方法中需要返回具體的Binder對象; 2.Client通過實(shí)現(xiàn)ServiceConnection接口來自定義ServiceConnection,并通過bindService (Intent service, ServiceConnection sc, int flags)方法將Service綁定到此Client上; 3.自定義的ServiceConnection中實(shí)現(xiàn)onServiceConnected(ComponentName name, IBinder binder)方法,獲取Service端Binder實(shí)例; 4.通過獲取的Binder實(shí)例進(jìn)行Service端其他公共方法的調(diào)用,以完成Client-Service通信; 5.當(dāng)Client在恰當(dāng)?shù)纳芷冢ㄈ鏾nDestroy等)時(shí),此時(shí)需要解綁之前已經(jīng)綁定的Service,通過調(diào)用函數(shù)unbindService(ServiceConnection sc)。 在Bound Service具體使用過程中,根據(jù)onBind(Intent intent)方法放回的Binder對象的定義方式不同,又可以將其分為以下三種方式,且每種方式具有不同的特點(diǎn)和適用場景: 1).Extending the Binder class 這是Bound Service中最常見的一種使用方式,也是Bound Service中最簡單的一種。 局限:Clinet與Service必須同屬于同一個(gè)進(jìn)程,不能實(shí)現(xiàn)進(jìn)程間通信(IPC)。否則則會(huì)出現(xiàn)類似于“android.os.BinderProxy cannot be cast to xxx”錯(cuò)誤。 下面通過代碼片段看下具體的使用: 1 public class MyBindService extends Service {
2
3 public static final String TAG = "MyBindService";
4
5 private MyBinder mBinder = new MyBinder();
6
7 public class MyBinder extends Binder {
8 MyBindService getService() {
9 return MyBindService.this;
10 }
11 }
12
13 @Override
14 public void onCreate() {
15 super.onCreate();
16 Log.w(TAG, "in onCreate");
17 }
18
19 @Override
20 public IBinder onBind(Intent intent) {
21 Log.w(TAG, "in onBind");
22 return mBinder;
23 }
24
25 @Override
26 public boolean onUnbind(Intent intent) {
27 Log.w(TAG, "in onUnbind");
28 return super.onUnbind(intent);
29 }
30
31 @Override
32 public void onDestroy() {
33 super.onDestroy();
34 Log.w(TAG, "in onDestroy");
35 }
36 }
1 public class BActivity extends Activity {
2
3 public static final String TAG = "BActivity";
4
5 private Button bindServiceBtn;
6 private Button unbindServiceBtn;
7
8 private Button startIntentService;
9
10 private Intent serviceIntent;
11
12 private ServiceConnection sc = new MyServiceConnection();
13 private MyBinder mBinder;
14 private MyBindService mBindService;
15 private boolean mBound;
16
17 private class MyServiceConnection implements ServiceConnection {
18
19 @Override
20 public void onServiceConnected(ComponentName name, IBinder binder) {
21 Log.w(TAG, "in MyServiceConnection onServiceConnected");
22 mBinder = (MyBinder) binder;
23 mBindService = mBinder.getService();
24
25 mBound = true;
26 }
27
28 @Override
29 public void onServiceDisconnected(ComponentName name) {
30 // This is called when the connection with the service has been
31 // unexpectedly disconnected -- that is, its process crashed.
32 Log.w(TAG, "in MyServiceConnection onServiceDisconnected");
33 mBound = false;
34 }
35
36 }
37
38 @Override
39 protected void onCreate(Bundle savedInstanceState) {
40 super.onCreate(savedInstanceState);
41 setContentView(R.layout.b);
42
43 bindServiceBtn = (Button) findViewById(R.id.bind_service);
44 unbindServiceBtn = (Button) findViewById(R.id.unbind_service);
45 startIntentService = (Button) findViewById(R.id.start_intentservice);
46
47 bindServiceBtn.setOnClickListener(new View.OnClickListener() {
48 @Override
49 public void onClick(View v) {
50 Intent intent = new Intent(BActivity.this, MyBindService.class);
51 bindService(intent, sc, Context.BIND_AUTO_CREATE);
52 }
53 });
54
55 unbindServiceBtn.setOnClickListener(new View.OnClickListener() {
56 @Override
57 public void onClick(View v) {
58 excuteUnbindService();
59 }
60 });
61
62 startIntentService.setOnClickListener(new View.OnClickListener() {
63 @Override
64 public void onClick(View v) {
65 Intent intent = new Intent(BActivity.this, MyIntentService.class);
66 startService(intent);
67 }
68 });
69
70 }
71
72 private void excuteUnbindService() {
73 if (mBound) {
74 unbindService(sc);
75 mBound = false;
76 }
77 }
78
79 @Override
80 protected void onDestroy() {
81 super.onDestroy();
82 Log.w(TAG, "in onDestroy");
83 excuteUnbindService();
84 }
85 }
首次點(diǎn)擊bindServiceBtn進(jìn)行bindService(..)時(shí),依次回調(diào)順序如下: 1 MyBindService(13457): in onCreate
2 MyBindService(13457): in onBind
3 BActivity(13457): in MyServiceConnection onServiceConnected
再次點(diǎn)擊bindServiceBtn按鈕時(shí),發(fā)現(xiàn)沒有任何輸出,說明MyBindService沒有進(jìn)行任何回調(diào)。 點(diǎn)擊unbindServiceBtn進(jìn)行unbindService(..)時(shí),回調(diào)順序?yàn)椋?/span> 1 MyBindService(13457): in onUnbind
2 MyBindService(13457): in onDestroy
注:在四大基本組件中,需要注意的的是BroadcastReceiver不能作為Bound Service的Client,因?yàn)锽roadcastReceiver的生命周期很短,當(dāng)執(zhí)行完onReceive(..)回調(diào)時(shí),BroadcastReceiver生命周期完結(jié)。而Bound Service又與Client本身的生命周期相關(guān),因此,Android中不允許BroadcastReceiver去bindService(..),當(dāng)有此類需求時(shí),可以考慮通過startService(..)替代。
2)Using a Messenger Messenger,在此可以理解成”信使“,通過Messenger方式返回Binder對象可以不用考慮Clinet - Service是否屬于同一個(gè)進(jìn)程的問題,并且,可以實(shí)現(xiàn)Client - Service之間的雙向通信。極大方便了此類業(yè)務(wù)需求的實(shí)現(xiàn)。 局限:不支持嚴(yán)格意義上的多線程并發(fā)處理,實(shí)際上是以隊(duì)列去處理 下面直接看下具體的使用: 1 public class MyMessengerService extends Service {
2
3 public static final String TAG = "MyMessengerService";
4
5 public static final int MSG_FROM_CLIENT_TO_SERVER = 1;
6 public static final int MSG_FROM_SERVER_TO_CLIENT = 2;
7
8 private Messenger mClientMessenger;
9 private Messenger mServerMessenger = new Messenger(new ServerHandler());
10
11 @Override
12 public IBinder onBind(Intent intent) {
13 Log.w(TAG, "in onBind");
14 return mServerMessenger.getBinder();
15 }
16
17 class ServerHandler extends Handler {
18 @Override
19 public void handleMessage(Message msg) {
20 Log.w(TAG, "thread name:" + Thread.currentThread().getName());
21 switch (msg.what) {
22 case MSG_FROM_CLIENT_TO_SERVER:
23 Log.w(TAG, "receive msg from client");
24 mClientMessenger = msg.replyTo;
25
26 // service發(fā)送消息給client
27 Message toClientMsg = Message.obtain(null, MSG_FROM_SERVER_TO_CLIENT);
28 try {
29 Log.w(TAG, "server begin send msg to client");
30 mClientMessenger.send(toClientMsg);
31 } catch (RemoteException e) {
32 e.printStackTrace();
33 }
34 break;
35 default:
36 super.handleMessage(msg);
37 }
38 }
39 }
40
41 @Override
42 public boolean onUnbind(Intent intent) {
43 Log.w(TAG, "in onUnbind");
44 return super.onUnbind(intent);
45 }
46
47 @Override
48 public void onDestroy() {
49 Log.w(TAG, "in onDestroy");
50 super.onDestroy();
51 }
52 }
1 public class CActivity extends Activity {
2
3 public static final String TAG = "CActivity";
4
5 private Button bindServiceBtn;
6 private Button unbindServiceBtn;
7 private Button sendMsgToServerBtn;
8
9 private ServiceConnection sc = new MyServiceConnection();
10 private boolean mBound;
11
12 private Messenger mServerMessenger;
13
14 private Handler mClientHandler = new MyClientHandler();
15 private Messenger mClientMessenger = new Messenger(mClientHandler);
16
17 private class MyClientHandler extends Handler {
18 @Override
19 public void handleMessage(Message msg) {
20 if (msg.what == MyMessengerService.MSG_FROM_SERVER_TO_CLIENT) {
21 Log.w(TAG, "reveive msg from server");
22 }
23 }
24 }
25
26 private class MyServiceConnection implements ServiceConnection {
27
28 @Override
29 public void onServiceConnected(ComponentName name, IBinder binder) {
30 Log.w(TAG, "in MyServiceConnection onServiceConnected");
31 mServerMessenger = new Messenger(binder);
32
33 mBound = true;
34 }
35
36 @Override
37 public void onServiceDisconnected(ComponentName name) {
38 // This is called when the connection with the service has been
39 // unexpectedly disconnected -- that is, its process crashed.
40 Log.w(TAG, "in MyServiceConnection onServiceDisconnected");
41
42 mBound = false;
43 }
44 }
45
46 @Override
47 protected void onCreate(Bundle savedInstanceState) {
48 super.onCreate(savedInstanceState);
49 setContentView(R.layout.c);
50
51 bindServiceBtn = (Button) findViewById(R.id.bind_service);
52 unbindServiceBtn = (Button) findViewById(R.id.unbind_service);
53 sendMsgToServerBtn = (Button) findViewById(R.id.send_msg_to_server);
54
55 bindServiceBtn.setOnClickListener(new View.OnClickListener() {
56 @Override
57 public void onClick(View v) {
58 Intent intent = new Intent(CActivity.this, MyMessengerService.class);
59 bindService(intent, sc, Context.BIND_AUTO_CREATE);
60 }
61 });
62
63 unbindServiceBtn.setOnClickListener(new View.OnClickListener() {
64 @Override
65 public void onClick(View v) {
66 excuteUnbindService();
67 }
68 });
69
70 sendMsgToServerBtn.setOnClickListener(new View.OnClickListener() {
71 @Override
72 public void onClick(View v) {
73 sayHello();
74 }
75 });
76
77 new Handler().postDelayed(new Runnable() {
78 @Override
79 public void run() {
80 Intent intent = new Intent(CActivity.this, MyAlarmBroadcastReceiver.class);
81 sendBroadcast(intent);
82 }
83 }, 3 * 1000);
84
85 }
86
87 public void sayHello() {
88 if (!mBound)
89 return;
90 // Create and send a message to the service, using a supported 'what' value
91 Message msg = Message.obtain(null, MyMessengerService.MSG_FROM_CLIENT_TO_SERVER, 0, 0);
92 // 通過replyTo把client端的Messenger(信使)傳遞給service
93 msg.replyTo = mClientMessenger;
94 try {
95 mServerMessenger.send(msg);
96 } catch (RemoteException e) {
97 e.printStackTrace();
98 }
99 }
100
101 private void excuteUnbindService() {
102 if (mBound) {
103 unbindService(sc);
104 mBound = false;
105 }
106 }
107
108 @Override
109 protected void onDestroy() {
110 super.onDestroy();
111 Log.w(TAG, "in onDestroy");
112 excuteUnbindService();
113 }
114 }
其中,需要注意的幾點(diǎn)是: 1.MyMessengerService自定中,通過new Messenger(new ServerHandler())創(chuàng)建Messenger對象,在onBind(..)回調(diào)中,通過調(diào)用Messenger對象的getBinder()方法,將Binder返回; 2.Client在ServiceConnection的onServiceConnected(..)的回調(diào)中,通過new Messenger(binder)獲取到Service傳遞過來的mServerMessenger; 3.接下來,就可以通過mServerMessenger.send(msg)方法向Service發(fā)送message,Service中的Messenger構(gòu)造器中的Handler即可接收到此信息,在handleMessage(..)回調(diào)中處理; 4.至此只是完成了從Client發(fā)送消息到Service,同樣的道理,想實(shí)現(xiàn)Service發(fā)送消息到Client,可以在客戶端定義一個(gè)Handler,并得到相應(yīng)的Messenger,在Clinet發(fā)送消息給Service時(shí),通過msg.replyTo = mClientMessenger方式將Client信使傳遞給Service; 5.Service接收到Client信使后,獲取此信使,并通過mClientMessenger.send(toClientMsg)方式將Service消息發(fā)送給Client。 至此,完成了Client - Service之間的雙向通信流程。
3).AIDL(Android Interface Definition Language) 一般情況下,Messenger這種方式都是可以滿足需求的,當(dāng)然,通過自定義AIDL方式相對更加靈活。 這種方式需要自己在項(xiàng)目中自定義xxx.aidl文件,然后系統(tǒng)會(huì)自動(dòng)在gen目錄下生成相應(yīng)的接口類文件,接下來整個(gè)的流程與Messenger方式差別不大,網(wǎng)上也有不少實(shí)例,在此不再具體給出。
注:無論哪種方式的Bound Service,在進(jìn)行unbind(..)操作時(shí),都需要注意當(dāng)前Service是否處于已經(jīng)綁定狀態(tài),否則可能會(huì)因?yàn)楫?dāng)前Service已經(jīng)解綁后繼續(xù)執(zhí)行unbind(..)會(huì)導(dǎo)致崩潰。這點(diǎn)與Started Service區(qū)別很大(如前文所述:stopService(..)無需做當(dāng)前Service是否有效的判斷)。
4.Local Service VS Remote Service Local Service:不少人又稱之為”本地服務(wù)“,是指Client - Service同處于一個(gè)進(jìn)程; Remote Service:又稱之為”遠(yuǎn)程服務(wù)“,一般是指Service處于單獨(dú)的一個(gè)進(jìn)程中。 其他使用上上文中基本上都有所述。
5.Service特性 1.Service本身都是運(yùn)行在其所在進(jìn)程的主線程(如果Service與Clinet同屬于一個(gè)進(jìn)程,則是運(yùn)行于UI線程),但Service一般都是需要進(jìn)行”長期“操作,所以經(jīng)常寫法是在自定義Service中處理”長期“操作時(shí)需要新建線程,以免阻塞UI線程或?qū)е翧NR; 2.Service一旦創(chuàng)建,需要停止時(shí)都需要顯示調(diào)用相應(yīng)的方法(Started Service需要調(diào)用stopService(..)或Service本身調(diào)用stopSelf(..), Bound Service需要調(diào)用unbindService(..)),否則對于Started Service將處于一直運(yùn)行狀態(tài),對于Bound Service,當(dāng)Client生命周期結(jié)束時(shí)也將因此問題。也就是說,Service執(zhí)行完畢后,必須人為的去停止它。
6.IntentService IntentService是系統(tǒng)提供給我們的一個(gè)已經(jīng)繼承自Service類的特殊類,IntentService特殊性是相對于Service本身的特性而言的: 1.默認(rèn)直接實(shí)現(xiàn)了onBind(..)方法,直接返回null,并定義了抽象方法onHandlerIntent(..),用戶自定義子類時(shí),需要實(shí)現(xiàn)此方法; 2.onHandlerIntent(..)主要就是用來處于相應(yīng)的”長期“任務(wù)的,并且已經(jīng)自動(dòng)在新的線程中,用戶無語自定義新線程; 3.當(dāng)”長期“任務(wù)執(zhí)行完畢后(也就是onHandlerIntent(..)執(zhí)行完畢后),此IntentService將自動(dòng)結(jié)束,無需人為調(diào)用方法使其結(jié)束; 4.IntentService處于任務(wù)時(shí),也是按照隊(duì)列的方式一個(gè)個(gè)去處理,而非真正意義上的多線程并發(fā)方式。 下面是一個(gè)基本的繼承自IntentService的自定義Service: 1 public class MyIntentService extends IntentService {
2
3 public static final String TAG = "MyIntentService";
4
5 public MyIntentService() {
6 super(TAG);
7 }
8
9 public MyIntentService(String name) {
10 super(name);
11 }
12
13 @Override
14 protected void onHandleIntent(Intent intent) {
15 Log.w(TAG, "in onHandleIntent");
16 Log.w(TAG, "thread name:" + Thread.currentThread().getName());
17 }
18
19 }
7.前臺(tái)Service Android中Service接口中還提供了一個(gè)稱之為”前臺(tái)Service“的概念。通過Service.startForeground (int id, Notification notification)方法可以將此Service設(shè)置為前臺(tái)Service。在UI顯示上,notification將是一個(gè)處于onGoing狀態(tài)的通知,使得前臺(tái)Service擁有更高的進(jìn)程優(yōu)先級(jí),并且Service可以直接notification通信。 下面是一個(gè)簡單的前臺(tái)Service使用實(shí)例: 1 public class MyService extends Service {
2
3 public static final String TAG = "MyService";
4
5 @Override
6 public IBinder onBind(Intent intent) {
7 return null;
8 }
9
10 @Override
11 public void onCreate() {
12 super.onCreate();
13 Log.w(TAG, "in onCreate");
14 }
15
16 @Override
17 public int onStartCommand(Intent intent, int flags, int startId) {
18 Log.w(TAG, "in onStartCommand");
19 Log.w(TAG, "MyService:" + this);
20 String name = intent.getStringExtra("name");
21 Log.w(TAG, "name:" + name);
22
23
24 Notification notification = new Notification(R.drawable.ic_launcher, "test", System.currentTimeMillis());
25 Intent notificationIntent = new Intent(this, DActivity.class);
26 PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntesnt, 0);
27 notification.setLatestEventInfo(this, "title", "content", pendingIntent);
28 startForeground(1, notification);
29
30
31 return START_REDELIVER_INTENT;
32 }
33
34 @Override
35 public void onDestroy() {
36 super.onDestroy();
37 Log.w(TAG, "in onDestroy");
38 }
39 }
---------------------------------------------------------------------------------
筆者水平有限,若有錯(cuò)漏,歡迎指正,歡迎轉(zhuǎn)載以及CV操作,但希注明出處,謝謝! 分類: Android
|
|