學習筆記-Android AIDL傳遞對象數據

AIDL (Android Interface definition language)是一種android內部進程通信接口的描述語言,通過它我們可以定義進程間的通信接口

ICP :interprocess communication :內部進程通信;

AIDL 其實大傢並不陌生,應用裡面應用場景很多,如一鍵分享功能,將數據分享到第三方平臺,這都需要用到跨進程通信,這裡我主要介紹如何用AIDL傳遞對象型數據;

這裡需要創建兩個moudle ,一個用來模擬服務應用(被調用方),一個用來模擬客戶應用(調用方),這裡我使用的是 Android studio IDE , 在mian 文件夾下創建 aidl 文件夾,在裡面創建兩個 adil 文件, 一個是 提供服務的aidl 文件,另一個是 自定義的對象aidl 文件,另外再在裡面創建一個 對象文件,bean類,你可以把這個java文件直接

放在aidl 文件夾下,也可以放在java 文件夾下(不過必須確保所在包名和 aidl文件的包名一致),然後把aidl 目錄還有java bean 文件直接復制到 客戶端(client moudle)相同的位置,結構圖如下:

直接上文件代碼瞭;

IMsg.aidl

 

// IMsg.aidl
package com.example.server;

// Declare any non-default types here with import statements
import com.example.server.User;

interface IMsg {

/*如果傳遞自定義對象, 必須加上 in , out ,inout 修飾符之一;
  意思如下: in 表示從客戶端向服務端傳遞數據 
           out 表示從服務端向客戶端傳遞數據
           inout 則表示雙向都可以傳遞
*/

    void sendMsg(in User user);
}

 

User.aidl

 

//User.aidl
package com.example.server;

// Declare any non-default types here with import statements

parcelable User;

 

User.java

這裡要註意一下,如果你用到 out 修飾符,需要在 User.java 裡面添加 readFromParcel(Parcel source);方法,如果不手動添加, IMsg.java 文件會報錯;

 

package com.example.server;

import android.os.Parcel;
import android.os.Parcelable;
import android.util.Log;

/**
 * Created by JR on 2017/8/28.
 */

public class User implements Parcelable {

    public String name;
    public int age;
    private static final String TAG = "Main";

    public User() {
    }

    public User(String name, int age) {
        this.name = name;
        this.age = age;
    }


    public static final Creator CREATOR = new Creator() {
        @Override
        public User createFromParcel(Parcel in) {
            //Log.d(TAG, "client: --------"+in.readString()+"-------------"+in.readInt());
            //這裡需要註意, in.readXXX();方法執行完後,IMsg.java 文件裡面會執行 recycle();操作,就是清空數據
            //如果數據被清空,你的服務裡面就收不到 傳遞的數據,服務裡面會接收到一個空對象 User={"name"= null,"age" = 0};
           return new User(in);
        }

        @Override
        public User[] newArray(int size) {
            return new User[size];
        }
    };

    public User(Parcel in) {
        name = in.readString();
        age = in.readInt();
    }

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(this.name);
        dest.writeInt(this.age);
    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

同步編譯一下,會在build 目錄下生成對應的 IMsg.java 接口文件

 

在 server 端創建一個 服務;

RemoteService.java

 

package com.example.server;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;


/**
 * Created by JR on 2017/8/28.
 */

public class RemoteService extends Service {

    private static final String TAG = "MainActivity";

    @Override
    public void onCreate() {
        super.onCreate();
        Log.d(TAG, "onCreate: ------------------服務開啟");
    }

    @Override
    public IBinder onBind(Intent intent) {
        return new MyBinder();
    }

    class MyBinder extends IMsg.Stub {

        @Override
        public void sendMsg(User user) throws RemoteException {
            Log.d(TAG, "user:" + user.toString());
        }
    }
}

在服務端的manifiest文件裡面註冊服務,並添加一個action;

 

 


            
                
            
        

上面 服務端的就配置完成瞭,接下來開始配置 客戶端;

 

客戶端MainActivity.java

 

package com.example.jr.myaidl;

import android.app.Activity;
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.util.Log;
import android.view.View;

import com.example.server.IMsg;
import com.example.server.User;

public class MainActivity extends Activity {

    public static final String SERVICE_PACKAGE_NAME = "com.example.server";//遠程服務所在包名
    public static final String SERVICE_REFERENCE_NAME = "com.example.server.RemoteService";//遠程服務全名
    private IMsg iMsg;
    private static final String TAG = "MainActivity";

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

    }

    public void bind(View v) {
            Intent intent = new Intent();
            intent.setAction("remote");//對應 服務端service 的action
            intent.setComponent(new ComponentName(SERVICE_PACKAGE_NAME,SERVICE_REFERENCE_NAME));
            bindService(intent,connection,BIND_AUTO_CREATE);
            Log.d(TAG, "bind: ------------------"+"綁定成功");
    }

    public void unbind(View v){
        unbindService(connection);
        Log.d(TAG, "unbind: -----------------------解除綁定");
    }

    public void send(View v){
        try {
            iMsg.sendMsg(new User("張三",18));
            Log.d(TAG, "send: --------------------發送信息.....");
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }

    ServiceConnection connection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            iMsg = IMsg.Stub.asInterface(service);
            Log.d(TAG, "onServiceConnected: ------------鏈接成功");
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            iMsg = null;
            Log.d(TAG, "onServiceDisconnected: ----------------鏈接斷開");
        }
    };
}

接下裡就是測試瞭,先將server 服務端運行起來,再運行客戶端client (必須保證服務運行),在客戶端先連接服務端,再發送數據,服務端就能收到數據瞭.如果想從服務端拿數據,就用 out 修飾符,加上 IMsg.java 裡面提示的方法,運行起來,就可以瞭,就介紹到這裡!

You May Also Like