什么是Service
Service是一個可以在后臺長時間執(zhí)行的應用組件。
Service的啟動方式
startService
- 啟動方式
在其他組件中調(diào)用startService()方法; - 停止方式
在Service中調(diào)用stopSelf()方法;0
在其他組件中調(diào)用stopService()方法; - Service與其他組件之間的通信方式
沒有提供默認的通信。
bindService
- 啟動方式
在其他組件中調(diào)用bindService()方法; - 停止方式
所有與Service綁定的組件都被銷毀;
與Service綁定的組件調(diào)用unbindService()方法; - Service與其他組件之間的通信方式
可以通過ServiceConnection進行通信,發(fā)送請求、獲取結(jié)果;
可以通過IPC跨進程完成通信。
注意:
- startService()和bindService()并不沖突,同一個Service可以即被組件調(diào)用startService()啟動,又被另一個組件調(diào)用bindService()綁定啟動。
當同一個Service與其他組件同時存在這兩種調(diào)用聯(lián)系的時候,必須從兩種方法的角度看該Service均停止,該Service才能真正停止。 - Service并不是運行在一個獨立的進程當中,而是依賴于創(chuàng)建Service時所在的應用程序進程。
當某個應用程序進程被殺掉后,所有依賴于該進程的Service也會停止運行。
Service的創(chuàng)建
- public void onCreate()
只有在Service創(chuàng)建的時候調(diào)用一次。 - public int onStartCommand(Intent intent,int flags,int startId)
當組件調(diào)用startService()方法時,此方法被執(zhí)行,在這里進行Service的主要操作。 - public IBinder onBind(Intent intent)
當組件調(diào)用bindService()方法的時候調(diào)用,此時該Service將與組件綁定。 - public void onDestroy()
Service停止的時候調(diào)用該方法。
啟動Service
startService()
當組件調(diào)用startService()方法的時候,就可以啟動指定的Service了,同時這將導致Service中的onStartCommande()方法被調(diào)用。
Intent intent = new Intent(getContext(),Service.class);
startService(intent);
在調(diào)用startService()方法時候,傳入的Intent參數(shù)可以攜帶數(shù)據(jù),該數(shù)據(jù)將在Service執(zhí)行onStartCommand()方法中接收:
public int onStartCommand(Intent intent,int flags,int startId){}
bindService()
當組件調(diào)用bindService()方法的時候,將啟動指定的Service,并且將該組件與該Service進行綁定。
通常,將綁定它的組件稱為客戶端,將被綁定的Service稱為服務器。
要完成客戶端與服務器端的綁定,需要完成以下兩件事情:
- 在客戶端完成bindService()的調(diào)用以及相關(guān)配置;
- 在服務器端完成onBind()方法的重寫,返回一個IBinder接口給客戶端。
客戶端的配置
public boolean bindService(Intent service,ServiceConnection connection,int flags) {}
在bindService()方法中,需要三個參數(shù):
- Intent:用來指定啟動哪一個Service,同時可以傳遞一些數(shù)據(jù);
- ServiceConnection:用以實現(xiàn)客戶端與服務器端的關(guān)鍵類,此時我們需要重寫該類的兩個回調(diào)方法
1.onServiceConneced()
2.onServiceDisconnected()
而我們可以通過這兩個回調(diào)方法得到服務端的IBinder對象,從而通過該IBinder對象實現(xiàn)客戶端與服務端的通信。
Service mService;
Service.Binder mBinder;
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name,IBinder service) {
mBinder = (Service.Binder) service;
mService = mBinder.gerService();
}
@Override
public void onServiceDisconnected(ComponentName name) {}
}
- int:用于指定綁定選項的標志,一般是BIND_AUTO_CREATE。
服務端的配置
如果要創(chuàng)建一個支持綁定的Service,我們必須要重寫它的onBind()方法。
這個方法返回一個IBinder對象,它是服務端對客戶端暴露的交互接口。
而要得到IBinder接口,通常有三種方式:
- 繼承Binder類
- 使用Messenger類
- 使用AIDL
繼承Binder類
Binder類實現(xiàn)了IBinder接口,通過實現(xiàn)Binder類,客戶端可以直接通過這個類調(diào)用服務端的公有方法。
具體實現(xiàn)步驟:
- 在Service類中,創(chuàng)建一個繼承Binder類的內(nèi)部類;
- 在onBind()方法中返回這個Binder內(nèi)部類的實例;
- 在客戶端中通過綁定Service獲得Binder內(nèi)部類的實例,通過它提供的方法進行后續(xù)的通信操作。
服務端示例代碼:
public class LocalService extends Service {
private final IBinder mBinder = new LocalBinder();
private final Random mGenerator = new Random();
public class LocalBinder extends Binder {
public LocalService gerService() {
return LocalService.this;
}
}
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
public int getRandomNumber() {
return mGenerator.netInt(100);
}
}
LocalBinder為客戶端提供了getService()方法,用以獲得LocalService的當前實例。這樣,客戶端綁定服務端后,就可以調(diào)用服務中的公有方法(例如getRandomNumber())。
客戶端示例代碼:
public class BindingActivity extends Activity {
LocalService mService;
boolean mBound = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
@Override
protected void onStart() {
super.onStart();
Intent intent = new Intent(this,LocalService.class);
bindService(intent,mConnection,Context.BIND_AUTO_CREATE);
}
@Override
protected void onStop() {
super.onStop();
if (mBond) {
unbindService(mConnection);
}
}
public void onButtonClick(View v) {
if (mBound) {
int num = mService.getRandomNumber();
}
}
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(CompondName name,IBinder service) {
LocalBinder binder = (LocalBinder) service;
mService = binder.getService();
mBound = true;
}
@Override
public void onServiceDisconnected(ComponentName name) {
mBound = false;
}
}
}
使用Messenger
Messenger的核心就是Message以及Handler來進行線程間的通信。
具體實現(xiàn)步驟:
- 服務端實現(xiàn)一個Handler,由其接受來自客戶端的每一個調(diào)用的回調(diào);
- 使用實現(xiàn)的Handler創(chuàng)建一個Messenger對象;
- 通過Messenger得到一個IBinder對象,并將其通過onBind()返回給客戶端;
- 客戶端使用IBinder將Messenger(引用服務的Handler)實例化,然后使用后者將Messag對象發(fā)送給服務;
- 服務端在Handler中接收每個Message。
使用該方法,客戶端通過傳遞Message來與服務端進行交互。
服務端示例代碼:
public class MessengerService extends Service {
static final int MSG_SAY_HELLO = 1;
class ServiceHandler extends Handler {
@Override
public void handleMessage(Message msg) {
switch(msg.what) {
case MSG_SAY_HELLO:
Toast.maktText(getApplicationContext(),"Hello",Toast.LENGTH_SHORT).show();
break;
}
}
final Messenger mMessenger = new Messenger(new ServiceHandler());
@Override
public IBinder onBind(Intent intent) {
return mMessenger.getBinder();//返回給客戶端一個IBinder實例,用于給客戶端構(gòu)造Messenger
}
}
}
服務端主要是返回給客戶端一個IBinder實例,以供客戶端構(gòu)造Messenger,并且處理客戶端發(fā)送過來的Message。
此時,我們需要在Manifests.xml中完成對Messenger的注冊。
<service
android:name=".MessengerService"
android:enabled="true"
android:exported="true">
<intent-filter>
<anction android:name="com.mglee.messenger"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</service>
客戶端示例代碼:
public class ActivityMessenger extends Activity {
static final int MSG_SAY_HELLO = 1;
Messenger mService = null;
boolean mBound;
private ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName name,IBinder service) {
mService = new Messenger(service);//利用服務端返回的IBinder實例,構(gòu)造Messenger
mBound = true;
}
public void onServiceDisconneted(ComponentName name) {
mService = null;
mBound = false;
}
public void sayHello() {
if (mBound) {
Message msg = new Message();
msg.what = MSG_SAY_HELLO;
try {
mService.send(msg);
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
@Override
protected void onCreate(Bundle sacedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
@Override
protected void onStart() {
super.onStart();
Intent intent = new Intent("com.mglee.messenger");
intent.setPackage("com.mglee");//包名是一定要設(shè)置的,不然會報錯
bindService(intent,mConnection,BIND_AUTO_CREATE);
}
@Override
protected void onStop() {
super.onStop();
if (mBound) {
unbindService(mConnection);
mBound = false;
}
}
}
}
客戶端通過綁定服務獲取服務端返回的IBinder實例,借此構(gòu)造Messenger,從而用Messenger發(fā)送Message的方式與服務端進行交互。
上面的示例中,只是演示了客戶端向服務端的單方面數(shù)據(jù)通信,而要讓服務端向客戶端實現(xiàn)數(shù)據(jù)通信,只需要客戶端也創(chuàng)建一個Handler實例,讓它接受來自服務端的信息,同時讓服務端在客戶端給他發(fā)送的請求完成之后再給客戶端發(fā)送一條信息即可。
AIDL
AIDL,Android接口自定義語言。
既然是接口自定義語言,其實就是系統(tǒng)根據(jù)它完成IInterface實例的代碼,其實就是一種代碼模板。
使用AIDL實現(xiàn)服務端和客戶端通信的基本步驟:
- 服務端創(chuàng)建一個AIDL文件,將需要暴露給客戶端的接口在里面聲明;
- 在Service中實現(xiàn)這些接口;
- 客戶端綁定服務端,并將onServiceConnected()得到的IBinder轉(zhuǎn)換為AIDL生成的IInterface實例;
- 同構(gòu)得到的實例調(diào)用暴露的方法,完成與服務端的數(shù)據(jù)通信。