Service進程間通信AIDL

AIDL是Android Interface Definition Language的縮寫,意思就是安卓接口定義語言。

IPC是Interprocess Communication的縮寫,意思就是進程間通信。

類似於其他你使用過的接口定義語言,AIDL允許你使用接口來實現客戶端和服務端的進程通信(IPC)。

在Android系統中,一個進程是不能訪問另一個進程的內存的,也就是無法數據或方法共用。所以,我們要把對象分解爲系統可以識別的原始數據,從而達到數據共通。而這個代碼的編寫是非常枯燥和麻煩的。所以Android系統中我們使用AIDL來實現!

注意:如果你要使多個客戶端訪問服務或者要在服務中使用多線程,那麼使用AIDL是必要的。如果你不需要在不同的應用之間執行併發的IPC,那麼是用Binder的方式就夠了。或者你需要實現IPC,但是不需要用到多線程,那麼使用Messenger的方式就可以實現進程通信了。不管怎樣,在使用AIDL之前,你最好已經明白綁定服務的具體作用和含義!

在你開始設計你的AIDL接口前,注意調用AIDL接口使用的函數。你不應該對調用發生的線程做假設。所發生的不同取決於調用是從本地進程或遠程進程中的線程的,例如abc:

a.本地進程中的調用是在同一個線程中執行的。如果這是你的主線程,該線程在AIDL接口中繼續執行。如果是另一個線程,那就是在服務中執行你的代碼。因此,如果只有本地線程訪問服務,你可以完全是用綁定服務的方式來實現就可以了!

b.從一個遠程線程池中調用方法到你自己的進程中。您必須爲來自未知線程的數據同步做準備,同時可能發生在同一時間發生多個回調。意思就是,AIDL接口的實現必須是線程安全的。

c.當調用遠程的數據時,如果遠程服務並沒有阻塞,它僅僅發送數據並立即返回,接口的實現就將定期收到數據,類似於通過遠程服務得到Binder對象!如果只是單獨的使用本地數據,就沒有關係,數據是同步的。


1.定義一個AIDL接口

a.AS創建一個服務端項目(modle)並新建一個.aidl的文件


AS會創建相應目錄並生成一個AIDL文件,在文件中我們寫上自己需要的方法,類似於普通接口



b.然後我們需要使用Build菜單的Make Project,這個操作千萬不要忘記,用於創建aidl相關的java文件。但是在AS的目錄中你是找不到這個java文件的,因爲它隱藏項目構建的debug目錄中,安裝使用的時候纔會添加進去,所以你每修改一次aidl,就需要make project一下!


c.創建一個Service服務,實例化aidl並具體實現其中的方法,通過它的Stub()方法得到stub對象(myBinder),最後在service的onBind()方法中返回它就可以與客戶端建立聯繫了。


d.最後,還需要在AndroidManifest.xml中配置service



2.在客戶端建立AIDL進行通信

a.我們新建一個項目(modle),並把Service中建立的aidl文件連同包都複製過來


b.少不了的,客戶端也需要Make Project

c.在客戶端的一個Activity中,綁定遠程服務,注意setPackage就是服務端apk文件的包名


d.最後,在建立連接的方法中得到IBinder對象,通過它實例化aidl,就可以調用其方法了

package cq.cake.service.client;

import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.TextView;

import butterknife.Bind;
import butterknife.ButterKnife;
import butterknife.OnClick;
import cq.cake.servicetest.IMyAidlInterface;

public class MainActivity extends AppCompatActivity {
    public static boolean mBind = false;
    @Bind(R.id.tv_text)
    TextView tvText;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ButterKnife.bind(this);
    }

    @OnClick(R.id.btn_bindservice)
    public void doClick(View view) {
        Log.d("TAG", "點擊了綁定 ");
        //.首先要綁定服務,這裏的Intent參數就是服務端AndroidManifest.xml中配置的action名稱
        Intent intent = new Intent("cq.cake.servicetest.MyAIDL_ACTION");
        intent.setPackage("cq.cake.servicetest");
        bindService(intent, connection, BIND_AUTO_CREATE);
    }

    private ServiceConnection connection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {

            IMyAidlInterface iMyAidlInterface = IMyAidlInterface.Stub.asInterface(service);
            try {
                int result = iMyAidlInterface.plus(50, 50);
                String upperStr = iMyAidlInterface.toUpperCase("comes from ClientTest");
                tvText.setText("調用遠程服務運行方法後" + "\n" + "50+50 =  " + result + "\n"
                        + "comes from ClientTest 轉換大寫爲 " + "\n" + upperStr);
            } catch (RemoteException e) {
                e.printStackTrace();
            }

            mBind = true;
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            mBind = false;
        }
    };
    
    @Override
    protected void onDestroy() {
        super.onDestroy();
        Log.d("TAG", "onDestroy ");
        if (mBind) {
            unbindService(connection);
            mBind = false;
        }
    }



}

3.實踐:安裝服務端,安裝客戶端。服務端就算沒有啓動,我們也可以通過客戶端來調用服務端的方法。並且多個客戶端共用此服務的方法!




到此關於AIDL進程間通信就介紹完成了,還有不明白的同學可以去看看官方文檔:

https://developer.android.com/guide/components/aidl.html



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章