Android 使用AIDL進行兩個APP之間通訊以及相互消息回調(一)

前言:

AIDL:Android Interface Definition Language,翻譯過來就是Android接口定義語言。是用於定義服務器和客戶端通信接口的一種描述語言,可以拿來生成用於IPC的代碼。所以使用AIDL需要一個服務端和客戶端
作用:可以在一個進程中獲取另一個進程的數據和調用其暴露出來的方法,從而滿足進程間通信的需求。

1.AIDL支持的基本數據類型

  1. 八種基本數據類型:byte、char、short、int、long、float、double、boolean
  2. String,CharSequence
  3. 實現了Parcelable接口的數據類型
  4. List 類型。List承載的數據必須是AIDL支持的類型,或者是其它聲明的AIDL對象
  5. Map類型。Map承載的數據必須是AIDL支持的類型,或者是其它聲明的AIDL對象

2.服務端的實現

   創建工程,以及所需aidl文件

  • 使用Android Studio新建一個工程,命名爲TestAidlDemo1
  • 右鍵New一個AIDL文件,取名爲IAidlInterface,AS會自動在工程目錄生成一個路徑完全一樣的aidl文件夾
  • 既然是要回調消息,那就還需要一個回調接口,同樣的方法,創建IAidlCallBack.aidl文件,那麼接下來就進行代碼編寫

實現代碼邏輯

  • 編寫IAidlInterface.aldi代碼,因爲我們需要回調消息,那麼我們需要註冊回調以及註銷回調接口,一個發送消息的接口,一個獲取歷史消息的接口,代碼如下(AIDL文件不會自動導包,一些不是基本支持數據類型需要我們自己手動import,)
    import com.pgc.testaidldemo1.IAidlCallBack;
    interface IAidlInterface {
        /**
         * Demonstrates some basic types that you can use as parameters
         * and return values in AIDL.
         */
        void registerCallBack(IAidlCallBack iAidlCallBack);
        void unregisterCallBack(IAidlCallBack iAidlCallBack);
        void sendMessage(String message);
        List<String> getMessages();
    }
    

     

  • 編寫IAidlCallBack.aidl代碼:既然是回調接口,那麼我們只需要一個消息發送成功的回調接口就行,代碼如下

    interface IAidlCallBack {
        /**
         * Demonstrates some basic types that you can use as parameters
         * and return values in AIDL.
         */
        void onMessageSuccess(String message);
    }

     

  • 既然是服務端,我們需要實現接收消息已經處理消息的邏輯代碼,所以我們創建一個AidlService,繼承Service,因爲Service不能直接接收Callback,但是提供了RemoteCallbackList來註冊回調

    private RemoteCallbackList<IAidlCallBack> callbackList= new RemoteCallbackList<>();

    同時RemoteCallbackList提供了beginBroadcast來獲取當前註冊的回調數,因此我們可以通過這個方法進行回調處理(再使用了beginBroadcast之後必須調用finishBroadcast不然會報beginBroadcast() called while already in a broadcast錯誤)

    final int num=callbackList.beginBroadcast();
    for (int i=0;i<num;i++){
         IAidlCallBack iAidlCallBack=callbackList.getBroadcastItem(i);
         iAidlCallBack.onMessageSuccess(message);
        }
    callbackList.finishBroadcast();

     接下來實例化binder對象並返回給客戶端,

    @Override
        public IBinder onBind(Intent intent) {
            return binder;
        }
    
        private final IAidlInterface.Stub binder=new IAidlInterface.Stub() {
            @Override
            public void registerCallBack(IAidlCallBack iAidlCallBack) throws RemoteException {
                callbackList.register(iAidlCallBack);
            }
    
            @Override
            public void unregisterCallBack(IAidlCallBack iAidlCallBack) throws RemoteException {
                callbackList.unregister(iAidlCallBack);
            }
    
            @Override
            public void sendMessage(String message) throws RemoteException {
                messages.add(message);
                final int num=callbackList.beginBroadcast();
                for (int i=0;i<num;i++){
                    IAidlCallBack iAidlCallBack=callbackList.getBroadcastItem(i);
                    iAidlCallBack.onMessageSuccess(message);
                }
                callbackList.finishBroadcast();
            }
    
            @Override
            public List<String> getMessages() throws RemoteException {
                return messages;
            }
        };

      

  • 在AndroidManifest.xml註冊Service

    <service android:name=".AidlService"
             android:enabled="true"
             android:exported="true"
                >
        <intent-filter android:priority="1000">
                <action android:name="AIDL.service"></action>
       </intent-filter>
    </service>

     

  • AidlService全部代碼

    package com.pgc.testaidldemo1;
    
    import android.annotation.SuppressLint;
    import android.app.Service;
    import android.content.Intent;
    import android.os.IBinder;
    import android.os.RemoteCallbackList;
    import android.os.RemoteException;
    
    import androidx.annotation.Nullable;
    
    import java.util.ArrayList;
    import java.util.List;
    
    
    /**
     * Created by PengGuiChu on 2020/4/11.
     */
    @SuppressLint("Registered")
    public class AidlService extends Service {
        private RemoteCallbackList<IAidlCallBack> callbackList= new RemoteCallbackList<>();
        private List<String> messages=new ArrayList<>();
        @Nullable
        @Override
        public IBinder onBind(Intent intent) {
            return binder;
        }
    
        private final IAidlInterface.Stub binder=new IAidlInterface.Stub() {
            @Override
            public void registerCallBack(IAidlCallBack iAidlCallBack) throws RemoteException {
                callbackList.register(iAidlCallBack);
            }
    
            @Override
            public void unregisterCallBack(IAidlCallBack iAidlCallBack) throws RemoteException {
                callbackList.unregister(iAidlCallBack);
            }
    
            @Override
            public void sendMessage(String message) throws RemoteException {
                messages.add(message);
                final int num=callbackList.beginBroadcast();
                for (int i=0;i<num;i++){
                    IAidlCallBack iAidlCallBack=callbackList.getBroadcastItem(i);
                    iAidlCallBack.onMessageSuccess(message);
                }
                callbackList.finishBroadcast();
            }
    
            @Override
            public List<String> getMessages() throws RemoteException {
                return messages;
            }
        };
    
        @Override
        public void onCreate() {
            super.onCreate();
        }
    }
    

     

  • 因爲是服務端和客戶端實現相互消息回調,因此在服務端也需要通過binderService來獲取binder,相對客戶端,因爲服務端和AidlService是在同一線程,我們可以直接binderService

    Intent intent=new Intent(getApplicationContext(),AidlService.class);
    bindService(intent,serviceConnection,BIND_AUTO_CREATE);

    然後實例化ServiceConnection

    private ServiceConnection serviceConnection=new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
                
            }
    
            @Override
            public void onServiceDisconnected(ComponentName componentName) {
    
            }
    };

    然後在onServiceConnected中獲取binder

    iAidlInterface=IAidlInterface.Stub.asInterface(iBinder);
    try {
          iAidlInterface.asBinder().linkToDeath(mDeathRecipient, 0);//監聽進程是否消失
          iAidlInterface.registerCallBack(iAidlCallBack);//註冊消息回調
          messages.addAll(iAidlInterface.getMessages());//獲取歷史消息
          listView.setAdapter(arrayAdapter=new ArrayAdapter<> 
          (getApplicationContext(),android.R.layout.simple_list_item_1,messages));
    } catch (RemoteException e) {
           e.printStackTrace();
    }

    DeathRecipient實例

        private IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() {
            //當承載IBinder的進程消失時接收回調的接口
            @Override
            public void binderDied() {
                if (null == iAidlInterface) {
                    return;
                }
                try {
                    iAidlInterface.unregisterCallBack(iAidlCallBack);//註銷
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
                iAidlInterface.asBinder().unlinkToDeath(mDeathRecipient, 0);
                iAidlInterface = null;
            }
        };

    iAidlCallBack實例

        private IAidlCallBack iAidlCallBack=new IAidlCallBack.Stub() {
            @Override
            public void onMessageSuccess(String message) {
                if (messages!=null&&arrayAdapter!=null){
                    messages.add(message);
                    handler.sendEmptyMessage(1);
                }
            }
        };

     MainActivity全部代碼

    package com.pgc.testaidldemo1;
    
    
    
    import android.annotation.SuppressLint;
    import android.content.ComponentName;
    import android.content.Intent;
    import android.content.ServiceConnection;
    import android.os.Bundle;
    import android.os.Handler;
    import android.os.IBinder;
    import android.os.Message;
    import android.os.RemoteException;
    import android.view.View;
    import android.widget.ArrayAdapter;
    import android.widget.ListView;
    
    import androidx.annotation.NonNull;
    import androidx.appcompat.app.AppCompatActivity;
    import java.util.ArrayList;
    import java.util.List;
    
    import butterknife.BindView;
    import butterknife.ButterKnife;
    import butterknife.OnClick;
    
    public class MainActivity extends AppCompatActivity {
        @BindView(R.id.list_view)
        ListView listView;
        private IAidlInterface iAidlInterface;
        private int num;
        private List<String> messages=new ArrayList<>();
        private ArrayAdapter arrayAdapter;
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            ButterKnife.bind(this);
            Intent intent=new Intent(getApplicationContext(),AidlService.class);
            bindService(intent,serviceConnection,BIND_AUTO_CREATE);
        }
    
    
        @OnClick(R.id.send_message)
        public void onViewClicked(View view) {
            if (iAidlInterface!=null){
                try {
                    iAidlInterface.sendMessage("消息"+num);
                    num++;
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
        }
    
        private ServiceConnection serviceConnection=new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
                iAidlInterface=IAidlInterface.Stub.asInterface(iBinder);
                try {
                    iAidlInterface.asBinder().linkToDeath(mDeathRecipient, 0);//監聽進程是否消失
                    iAidlInterface.registerCallBack(iAidlCallBack);//註冊消息回調
                    messages.addAll(iAidlInterface.getMessages());//獲取歷史消息
                    listView.setAdapter(arrayAdapter=new ArrayAdapter<>(getApplicationContext(),android.R.layout.simple_list_item_1,messages));
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
    
            @Override
            public void onServiceDisconnected(ComponentName componentName) {
    
            }
        };
    
        private IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() {
            //當承載IBinder的進程消失時接收回調的接口
            @Override
            public void binderDied() {
                if (null == iAidlInterface) {
                    return;
                }
                try {
                    iAidlInterface.unregisterCallBack(iAidlCallBack);//註銷
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
                iAidlInterface.asBinder().unlinkToDeath(mDeathRecipient, 0);
                iAidlInterface = null;
            }
        };
    
        private IAidlCallBack iAidlCallBack=new IAidlCallBack.Stub() {
            @Override
            public void onMessageSuccess(String message) {
                if (messages!=null&&arrayAdapter!=null){
                    messages.add(message);
                    handler.sendEmptyMessage(1);
                }
            }
        };
    
        @SuppressLint("HandlerLeak")
        private Handler handler=new Handler(){
            @Override
            public void handleMessage(@NonNull Message msg) {
                arrayAdapter.notifyDataSetChanged();
            }
        };
    
        @Override
        protected void onDestroy() {
            //解除註冊
            if (null != iAidlInterface && iAidlInterface.asBinder().isBinderAlive()) {
                try {
                    iAidlInterface.unregisterCallBack(iAidlCallBack);
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
            //解除綁定服務
            unbindService(serviceConnection);
            super.onDestroy();
        }
    }
    

    到此我們的服務端就編碼完成,實現效果

3.客戶端實現

   創建client工程

  •      選中TestAidlDemo1工程右鍵NEW一個model,命名爲client
  • 要想client項目能夠連接上Service,我們直接複製上面工程的aidl文件到client工程的main文件裏,這樣是爲了保證兩個項目的aidl文件路徑一致

       

  • 而調用邏輯基本和上面MainActivity一樣,需要注意一點的是,因爲是兩個不同進程,在這裏我們不能直接bindService來調起服務端,而是通過以下代碼實現
    Intent intent=new Intent();
    String ACTION = "AIDL.service";//對應服務端AndroidManifest.xml配置service action:name
    intent.setAction(ACTION);
    intent.setPackage("com.pgc.testaidldemo1");//對應服務端AndroidManifest.xml package
    bindService(intent,serviceConnection,BIND_AUTO_CREATE);

     

  • client的MainActivity全部代碼

    package com.pgc.client;
    
    import android.annotation.SuppressLint;
    import android.content.ComponentName;
    import android.content.Intent;
    import android.content.ServiceConnection;
    import android.os.Bundle;
    import android.os.Handler;
    import android.os.IBinder;
    import android.os.Message;
    import android.os.RemoteException;
    import android.view.View;
    import android.widget.ArrayAdapter;
    import android.widget.ListView;
    
    import androidx.annotation.NonNull;
    import androidx.appcompat.app.AppCompatActivity;
    
    import com.pgc.testaidldemo1.IAidlCallBack;
    import com.pgc.testaidldemo1.IAidlInterface;
    
    import java.util.ArrayList;
    import java.util.List;
    
    import butterknife.BindView;
    import butterknife.ButterKnife;
    import butterknife.OnClick;
    
    public class MainActivity extends AppCompatActivity {
        @BindView(R.id.list_view)
        ListView listView;
        private IAidlInterface iAidlInterface;
        private int num;
        private List<String> messages=new ArrayList<>();
        private ArrayAdapter arrayAdapter;
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            ButterKnife.bind(this);
            Intent intent=new Intent();
            String ACTION = "AIDL.service";
            intent.setAction(ACTION);
            intent.setPackage("com.pgc.testaidldemo1");
            bindService(intent,serviceConnection,BIND_AUTO_CREATE);
        }
    
    
        @OnClick(R.id.send_message)
        public void onViewClicked(View view) {
            if (iAidlInterface!=null){
                try {
                    iAidlInterface.sendMessage("消息"+num);
                    num++;
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
        }
    
        private ServiceConnection serviceConnection=new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
                iAidlInterface=IAidlInterface.Stub.asInterface(iBinder);
                try {
                    iAidlInterface.asBinder().linkToDeath(mDeathRecipient, 0);
                    iAidlInterface.registerCallBack(iAidlCallBack);
                    messages.addAll(iAidlInterface.getMessages());
                    listView.setAdapter(arrayAdapter=new ArrayAdapter<>(getApplicationContext(),android.R.layout.simple_list_item_1,messages));
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
    
            @Override
            public void onServiceDisconnected(ComponentName componentName) {
    
            }
        };
    
        private IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() {
            //當承載IBinder的進程消失時接收回調的接口
            @Override
            public void binderDied() {
                if (null == iAidlInterface) {
                    return;
                }
                iAidlInterface.asBinder().unlinkToDeath(mDeathRecipient, 0);
                iAidlInterface = null;
                //斷線重來邏輯
            }
        };
    
        private IAidlCallBack iAidlCallBack=new IAidlCallBack.Stub() {
            @Override
            public void onMessageSuccess(String message) {
                if (messages!=null&&arrayAdapter!=null){
                    messages.add(message);
                    handler.sendEmptyMessage(1);
                }
            }
        };
    
        @SuppressLint("HandlerLeak")
        private Handler handler=new Handler(){
            @Override
            public void handleMessage(@NonNull Message msg) {
                arrayAdapter.notifyDataSetChanged();
            }
        };
    
        @Override
        protected void onDestroy() {
            //解除註冊
            if (null != iAidlInterface && iAidlInterface.asBinder().isBinderAlive()) {
                try {
                    iAidlInterface.unregisterCallBack(iAidlCallBack);
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
            //解除綁定服務
            unbindService(serviceConnection);
            super.onDestroy();
        }
    }
    

     

  • 運行效果

源碼下載地址

https://github.com/pengkongkong/TestAidlDemo1

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