編輯:關於Android編程
之前提到過:如果站在Service與觸發Service運行的那個組件的角度,根據它們的關系進行分類,有兩種:本地Service,遠程Service。
本地Service就是同一個應用的組件的調用本地應用中的Service組件;
遠程Service就是其它應用的組件跨進程調用其它應用中的Service組件。
對於使用Start Service
的方式遠程運行Service
是很簡單的。和本地Service幾乎完全一樣,只是要采用隱式調用的方式調用。
這裡主要講講跨進程通過Bind Service
的方式遠程綁定Service
。
跨進程調用自定義Service
有兩種方式:Messager和AIDL。要讓兩個不同的進程之間進行函數調用,就要使用進程間通信IPC,這兩種方式都使用了IPC技術。在安卓系統當中,它實際上是由Binder
來實現的。
在源碼目錄下創建一個以aidl
為後綴的文件,例如IRemoteCall.aidl
,將Service
要提供給其他進程使用的接口函數定義在裡面,例如,
package xxx.xxx.xxx;
interface IRemoteCall {
void remoteFunc(int param);
}
Android Studio編譯器會根據AIDL接口文件,自動生成對應的java源代碼。它產生的java類可以直接拿來使用。
繼承Service
類,創建自己的Service
,並實現由IRemoteCall.aidl
定義的Binder
,
public class MyService extends Service {
......
//實現IRemoteCall.aidl定義的Binder-IRemoteCall.Stub()由編譯器自動產生
private final IBinder mBinder = new IRemoteCall.Stub() {
@Override
public void remoteFunc(int param) throws RemoteException {
//調用Service中真正實現功能的方法
innerRemoteFunc(param);
}
};
//真正實現功能的方法
private void innerRemoteFunc(int param)
{
}
@Override
public IBinder onBind(Intent intent) {
//當組件bindService()之後,將這個Binder返回給組件使用
return mBinder;
}
......
}
在AndroidManifest.xml
文件中,用隱式的方式聲明新創建的Service
;
......
......
這裡要把android:exported
屬性設置成true
,其他進程中的組件才能夠使用它,否則只有同一個進程的組件能使用。
在另一個應用中,要遠程調用Service
也很簡單,
創建一個ServiceConnection
,當綁定Service
之後在onServiceConnected()
中會得到Service
返回的Binder
;如果Service遇到異常情況退出時,會通過onServiceDisconnected
通知已經綁定過它的組件,綁定斷開。
如果用戶主動解除綁定,這個onServiceDisconnected()
是不會被觸發的。
private ServiceConnection mServiceConnection = new ServiceConnection()
{
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
//這裡的service參數,就是Service當中onBind()返回的Binder
IRemoteCall remoteCall = IRemoteCall.Stub.asInterface(service);
try {
//通過AIDL中定義的接口-IRemoteCall,就可以調用到Service提供到函數了
remoteCall.remoteFunc(0);
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
//當Service遇到異常情況退出時,會通過這裡通知已經綁定過它的組件
}
};
假設Activity A中有個按鈕,點擊之後就用隱式調用的方式調用bindService
;還有個按鈕B,點擊之後就調用unbindService
。
可以看到,通過AIDL進行遠程調用與不使用遠程調用基本一樣,只是它們產生和獲取Binder
的方式不同,
Binder
; 非遠程調用是通過繼承Binder
類產生Binder
;
Messenger
方式是一種進程間消息傳遞到方式,可以讓組件B發送消息M到Service,讓Service根據消息的類型進行相關的操作,
在Service
中,創建一個內部的Handler類
,
public class MessengerService extends Service {
static final int MSG_REMOTE_FUNC = 1;
class IncomingHandler extends Handler {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_REMOTE_FUNC:
//獲取到組件A發出的命令
innerRemoteFunc(msg.arg1)
break;
default:
super.handleMessage(msg);
}
}
}
//真正實現功能的方法
private void innerRemoteFunc(int param)
{
......
}
......
}
創建一個用來傳遞消息的Messenger,將Messenger作為Binder返回給調用者,今後調用者就可以用這個給Service發消息了。消息的內容在IncomingHandler
的handleMessage()
函數中得到。
public class MessengerService extends Service {
......
//創建一個用來傳遞消息的Messenger
final Messenger mMessenger = new Messenger(new IncomingHandler());
@Override
public IBinder onBind(Intent intent) {
//將Messenger作為Binder返回給調用者,今後調用者就可以用這個給Service發消息了,
//消息的內容在`IncomingHandler`的`handleMessage()`函數中得到
return mMessenger.getBinder();
}
......
}
組件A那邊在使用的時候可以,
創建一個ServiceConnection
,當綁定Service
之後在onServiceConnected()
中會得到Service
返回的Binder
;如果Service遇到異常情況退出時,會通過onServiceDisconnected
通知已經綁定過它的組件,綁定斷開。
private ServiceConnection mServiceConnection = new ServiceConnection()
{
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
//這裡的service參數,就是Service當中onBind()返回的Messenger的Binder,
//這裡我們通過這個Binder,把它還原成一個可以向Service發送消息的Messenger
Messenger remoteCall = new Messenger(service);
//通過Messenger,就可以向Service發送消息了
Message msg = Message.obtain(null, MessengerService.MSG_REMOTE_FUNC, 0, 0);
try {
remoteCall.send(msg);
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
//當Service遇到異常情況退出時,會通過這裡通知已經綁定過它的組件
}
};
假設Activity A中有個按鈕,點擊之後就用隱式調用的方式調用bindService
;還有個按鈕B,點擊之後就調用unbindService
。
這樣以來,組件A就可以向Service
發送消息了,Service
一收到消息,就會根據消息的類型,去執行對應的操作了。
可以看出,因為對Service
操作的請求是通過Handler
進行的,所以組件們請求都會按照先來後到一個一個順序執行; 只有其它組件可以向Service
發送執行某個操作的消息,而Service
無法主動匯報數據。
使用Messenger
要比使用AIDL
更簡單,Messenger
會將所有調用排入隊列,按照順序一個一個執行;而AIDL
方式允許多個組件同時向Service
發送請求,所以Service
需要考慮同步的問題。
對於大多數應用,Service
不需要執行多線程處理,不需要數據的主動回報,因此使用Messenger
可讓服務一次處理一個調用;否則就使用AIDL
方式吧。
繼承TabActivity並以activity布局先查看下最終效果圖:再看下代碼結構:其中black.gif顧名思義就是一個黑背景圖片,grey.gif就是一張灰色的背景
import android.content.Context; import android.graphics.Bitmap; import android.grap
去年谷歌 I/O大會上介紹了一個非常厲害的新框架DataBinding, 數據綁定框架給我們帶來了很大的方便,以前我們可能需要在每個Activity裡寫很多的findVi
在eclipse中file菜單中選中new--->Android Application Program-->Next --&
測試環境: win7 64 g++ 4.8.1 /*