官方文檔中國(guó)版: https://developer.android.google.cn/guide/components/bound-services.html
谷歌2016年底為中國(guó)開發(fā)者提供中國(guó)版,方便訪問!
綁定服務(wù)簡(jiǎn)介
Android服務(wù)與客戶端相互調(diào)用(傳遞消息),必須創(chuàng)建綁定服務(wù)bindService()提供IBinder接口()!
服務(wù)與客戶端交互方式(傳遞消息)有三種:
1.使用Binder類(客戶端與服務(wù)在同一進(jìn)程)
如果服務(wù)與客戶端在同一進(jìn)程中運(yùn)行,通過(guò)擴(kuò)展Binder類并從onBind()返回它的一個(gè)實(shí)例來(lái)創(chuàng)建接口。
客戶端收到Binder后,可利用它直接訪問Binder實(shí)現(xiàn)中乃至Service中可用的公共方法!
2.使用Messenger(客戶端與服務(wù)在不同進(jìn)程,服務(wù)只能是單線程)
不同進(jìn)程工作,可用Messenger為服務(wù)創(chuàng)建接口。Message對(duì)象內(nèi)含Handler。
隨后可與客戶端分享一個(gè)IBinder,從而讓客戶端能利用 Message 對(duì)象向服務(wù)發(fā)送命令。
此外,客戶端還可定義自有 Messenger,以便服務(wù)回傳消息!
這是進(jìn)程間通信(IPC)的最簡(jiǎn)單方法(AIDL的簡(jiǎn)化),因?yàn)镸essenger會(huì)在服務(wù)單一線程創(chuàng)建所有請(qǐng)求隊(duì)列。
3.使用AIDL(客戶端與服務(wù)在不同進(jìn)程,服務(wù)可以是多線程)
AIDL(Android 接口定義語(yǔ)言)執(zhí)行所有將對(duì)象分解成原語(yǔ)的工作,
操作系統(tǒng)可以識(shí)別這些原語(yǔ)并將它們編組到各進(jìn)程中以執(zhí)行IPC。
之前的Messenger實(shí)際是以AIDL作為其底層結(jié)構(gòu)。如果服務(wù)同時(shí)處理多個(gè)請(qǐng)求(多線程),應(yīng)該用AIDL。
注:大多數(shù)應(yīng)用“都不會(huì)”使用AIDL來(lái)創(chuàng)建綁定服務(wù),因?yàn)樗赡芤缶邆涠嗑€程處理能力,
并可能導(dǎo)致實(shí)現(xiàn)的復(fù)雜性增加。因此,AIDL并不適合大多數(shù)應(yīng)用!
4.此外,還可用廣播這個(gè)萬(wàn)金油組件進(jìn)行傳遞消息,無(wú)論是不同進(jìn)程,還是不同APP應(yīng)用,都可用廣播傳遞消息!
但是需要注意的是, 廣播有可能泄露數(shù)據(jù)、惡意程序發(fā)送廣播等安全性問題,
所以應(yīng)該限制廣播只在本應(yīng)用內(nèi)傳播:
1.設(shè)置permission或Intent.setPackage,不把廣播發(fā)送到應(yīng)用外!
2.使用LocalBroadcastManager或設(shè)置android:exported="false"不接收應(yīng)用外廣播!
一.使用Binder類(客戶端與服務(wù)在同一進(jìn)程)
// 1.本地服務(wù)————————————————————————————————————
public class LocalService extends Service {
private final IBinder mLocalBinder = new LocalBinder();
public class LocalBinder extends Binder {
LocalService getService() {
return LocalService.this;
}
}
@Override
public IBinder onBind(Intent intent) {
return mLocalBinder;
}
public int getRandomNumber() {
return new Random().nextInt(100);
}
}
// 2.客戶端————————————————————————————————————
public class BindingActivity extends Activity {
boolean mBound = false;
@Override
protected void onStart() {
super.onStart();
// 綁定本地服務(wù)(同一進(jìn)程)
bindService(new Intent(this, LocalService.class),
mConnection,
Context.BIND_AUTO_CREATE);
}
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName className, IBinder service) {
mBound = true;
// 獲取本地服務(wù)的實(shí)例,并調(diào)用方法,獲取隨機(jī)數(shù)
LocalService localService = ((LocalBinder) service).getService();
int num = localService.getRandomNumber();
}
@Override
public void onServiceDisconnected(ComponentName arg0) {
mBound = false;
}
};
@Override
protected void onStop() {
super.onStop();
if (mBound) {
// 解綁本地服務(wù)
unbindService(mConnection);
mBound = false;
}
}
}
二.使用Messenger(客戶端與服務(wù)在不同進(jìn)程,服務(wù)只能是單線程)
// 1.注冊(cè)遠(yuǎn)程服務(wù)————————————————————————————————————
<service
android:name=".MessengerService"
android:process=":remote"> (process指定服務(wù)在另一個(gè)進(jìn)程,名叫remote)
</service>
// 2.遠(yuǎn)程服務(wù)————————————————————————————————————
public class MessengerService extends Service {
final Messenger mServiceMessenger = new Messenger(new Handler(){
@Override
public void handleMessage(Message msg) {
// 接收客戶端消息
switch (msg.what) {
case 1:
Toast.makeText(getApplicationContext(), "service hello!", Toast.LENGTH_SHORT).show();
Thread.sleep(3000);
// 向客戶端發(fā)消息
Messenger messenger = msg.replyTo;
messenger.send(Message.obtain(null, 1, 0, 0))
break;
}
}
});
@Override
public IBinder onBind(Intent intent) {
return mServiceMessenger.getBinder();
}
}
// 3.客戶端————————————————————————————————————
public class ActivityMessenger extends Activity {
boolean mBound = false;
private Messenger mActivityMessenger = new Messenger(new Handler(){
@Override
public void handleMessage(Message msg){
// 接收遠(yuǎn)程服務(wù)消息
switch (msg.what){
case 1:
Toast.makeText(ActivityMessenger.this, "activity hello!", Toast.LENGTH_SHORT).show();
break;
}
}
});
private ServiceConnection mConnection = new ServiceConnection(){
public void onServiceConnected(ComponentName className, IBinder service) {
mBound = true;
// 向遠(yuǎn)程服務(wù)發(fā)消息
Messenger messenger = new Messenger(service);
Message msg = Message.obtain(null, 1, 0, 0);
msg.replyTo = mActivityMessenger
messenger.send(msg);
}
public void onServiceDisconnected(ComponentName className) {
mBound = false;
}
};
@Override
protected void onStart() {
super.onStart();
// 綁定遠(yuǎn)程服務(wù)(不同進(jìn)程)
bindService(new Intent(this, MessengerService.class),
mConnection,
Context.BIND_AUTO_CREATE);
}
@Override
protected void onStop() {
super.onStop();
// 解綁遠(yuǎn)程服務(wù)
if (mBound) {
unbindService(mConnection);
}
}
}
三.使用AIDL(客戶端與服務(wù)在不同進(jìn)程,服務(wù)可以是多線程)
1.創(chuàng)建AIDL接口
默認(rèn)情況下AIDL支持下列數(shù)據(jù)類型
int、long、char、boolean、String、CharSequence、List、Map
List中元素都必須是以上類型、其他AIDL接口、可打包類型(即實(shí)現(xiàn)Parcelable接口).
Map中元素都必須是以上類型、其他AIDL接口、可打包類型(即實(shí)現(xiàn)了Parcelable接口)
不支持通用Map(如Map<String,Integer>形式的Map)
// IRemoteService.aidl文件
interface IRemoteService {
// 注冊(cè)回調(diào)
void registerCallback(IRemoteServiceCallBack cb);
void unregisterCallback(IRemoteServiceCallBack cb);
}
// IRemoteServiceCallBack.aidl文件
interface IRemoteServiceCallBack{
void valueChanged(int value);
}
2.在遠(yuǎn)程服務(wù)中實(shí)現(xiàn)AIDL接口
public class RemoteService extends Service {
// 一個(gè)服務(wù)會(huì)綁定多個(gè)客戶端, 需要集合來(lái)存放客戶端的回調(diào)接口
private RemoteCallbackList<IRemoteServiceCallBack> mCallbackList
= new RemoteCallbackList<IRemoteServiceCallBack>();
// 實(shí)現(xiàn)IRemoteService.AIDL接口
private IRemoteService.Stub mBinder = new IRemoteService.Stub() {
@Override
public void registerCallback(IRemoteServiceCallBack cb)throws RemoteException {
if (cb != null) {
mCallbackList.register(cb);
}
}
@Override
public void unRegisterCallback(IRemoteServiceCallBack cb)throws RemoteException {
if (cb != null) {
mCallbackList.unregister(cb);
}
}
};
// 通知所有客戶端的回調(diào)接口
public void sendMsg(){
int N = mCallbackList.beginBroadcast();
for(int i=0;i<N;i++){
try {
// 回調(diào)通知客戶端
mCallbackList.getBroadcastItem(i).valueChanged(mValue);
} catch (RemoteException e) {
e.printStackTrace();
}
}
mCallbackList.finishBroadcast(); // 通知完成
}
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
}
3.客戶端
public class BindActivity extends Activity {
IRemoteService mService = null;
private boolean mIsBound = false;
// 實(shí)現(xiàn)IRemoteServiceCallback.AIDL接口
private IRemoteServiceCallback mCallback = new IRemoteServiceCallback.Stub() {
/**
* 來(lái)自遠(yuǎn)程服務(wù)的回調(diào)通知,
* 此方法不在UI線程中, 更新UI需小心!
*/
public void valueChanged(int value) {
...
}
};
private ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className,IBinder service){
mIsBound = true;
mService = IRemoteService.Stub.asInterface(service);
// 注冊(cè)回調(diào)接口
mService.registerCallback(mCallback);
}
public void onServiceDisconnected(ComponentName className) {
mIsBound = false;
mService = null;
}
};
@Override
protected void onStart() {
super.onStart();
// 綁定遠(yuǎn)程服務(wù)
bindService(new Intent(BindActivity.this, RemoteService.class),
mConnection,
Context.BIND_AUTO_CREATE);
}
@Override
protected void onStop() {
super.onStop();
if (mIsBound){
// 取消回調(diào)接口
mService.unregisterCallback(mCallback);
// 解綁遠(yuǎn)程服務(wù)
unbindService(mConnection);
}
}
}
總結(jié):
綜上比較, AIDL實(shí)現(xiàn)客戶端與遠(yuǎn)程服務(wù)通信太繁瑣, 相互通知調(diào)用至少需要兩個(gè)AIDL接口文件
在遠(yuǎn)程服務(wù)中通知客戶端, 需要循環(huán)通知, 相當(dāng)繁瑣!
除非迫不得以(如服務(wù)可以是多線程運(yùn)行), 實(shí)在不建議使用AIDL!
客戶端與服務(wù)在不同進(jìn)程時(shí), 建議服務(wù)單線程運(yùn)行,
使用Messenger通信, 這也是Android官方推薦的!
簡(jiǎn)書: http://www.itdecent.cn/p/aec29a98bc1e
CSDN博客: http://blog.csdn.net/qq_32115439/article/details/72760479
GitHub博客:http://lioil.win/2017/05/25/Android_bindService.html
Coding博客:http://c.lioil.win/2017/05/25/Android_bindService.html