Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> 四大組件之Service(三)-Service的跨進程調用

四大組件之Service(三)-Service的跨進程調用

編輯:關於Android編程

第4節 遠程調用

之前提到過:如果站在Service與觸發Service運行的那個組件的角度,根據它們的關系進行分類,有兩種:本地Service,遠程Service。

本地Service就是同一個應用的組件的調用本地應用中的Service組件;

\

遠程Service就是其它應用的組件跨進程調用其它應用中的Service組件。

\

對於使用Start Service的方式遠程運行Service是很簡單的。和本地Service幾乎完全一樣,只是要采用隱式調用的方式調用。

這裡主要講講跨進程通過Bind Service的方式遠程綁定Service

跨進程調用自定義Service有兩種方式:Messager和AIDL。要讓兩個不同的進程之間進行函數調用,就要使用進程間通信IPC,這兩種方式都使用了IPC技術。在安卓系統當中,它實際上是由Binder來實現的。

4.1 AIDL實現進程間調用

在源碼目錄下創建一個以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的方式不同,

遠程調用是通過AIDL產生Binder; 非遠程調用是通過繼承Binder類產生Binder

4.2 Messenger實現進程間調用

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發消息了。消息的內容在IncomingHandlerhandleMessage()函數中得到。


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無法主動匯報數據。

4.3 AIDL與Messenger怎麼選

使用Messenger要比使用AIDL更簡單,Messenger 會將所有調用排入隊列,按照順序一個一個執行;而AIDL方式允許多個組件同時向Service發送請求,所以Service需要考慮同步的問題。

對於大多數應用,Service不需要執行多線程處理,不需要數據的主動回報,因此使用Messenger可讓服務一次處理一個調用;否則就使用AIDL方式吧。

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved