跨程序通訊之AIDL-----不同應用程式之間跨程序
AIDL,通俗來說就是兩個Android應用要進行通訊,且不能通過網路雲伺服器的方式進行資料互動,只能呼叫本地函式庫的機制來實現,這時Android系統提供AIDL的機制來實現Android的跨程序通訊(使用者程序之間是相對封閉的,無法直接訪問資料)。
我們先不管任何原理,把demo跑出來再說其他的:
準備材料:一個Service、一個Client、連線S—C的橋樑(AIDL檔案)
第一步: 連線S—C的橋樑(AIDL檔案),這個aidl檔案是客戶端和伺服器端都需要的,在服務端或者客戶端的專案中生成都可以,如果傳遞基本資料型別就直接使用,如果是引用資料型別,先宣告這個實體類,專案包結構如下
①Person類中主要是實現Parcelable介面,程式碼如下
package com.testaidl.model; import android.os.Parcel; import android.os.Parcelable; /** * Created by Administrator on 2018\10\31 0031. */ public class Person implements Parcelable { private String name; protected Person(Parcel in) { name = in.readString(); } public static final Creator<Person> CREATOR = new Creator<Person>() { @Override public Person createFromParcel(Parcel in) { return new Person(in); } @Override public Person[] newArray(int size) { return new Person[size]; } }; public Person(String name) { this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public int describeContents() { return 0; } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeString(name); } @Override public String toString() { return "Person{" + "mName='" + this.getName() + '\'' + '}'; } }
②然後再專案的main結構下建立aidl資料夾,建立Person的aidl字尾檔案,必須要和上面Person的包名(結構)相同,這個Person類很簡單就是宣告一下parcelable 介面,
③IMyAidl這個介面的方法是提供給C-S呼叫的,
// IMyAidl.aidl package com.testaidl; // 這個引用型別必須是全類名的才能使用 import com.testaidl.model.Person; interface IMyAidl { /** * Demonstrates some basic types that you can use as parameters * and return values in AIDL. */ void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString); void addPerson(in Person person); List<Person> getPersonList(); }
這樣子,AIDL這個中介軟體就做好了,把它分別放到代表:客戶端和伺服器專案中(例如我們在客戶端的專案中生成AIDL檔案,然後copy給伺服器,但是要注意包名必須完全一致,C-S兩端都要一致的,有點童鞋會說我想將客戶端或者服務端放到之前的專案中,這時包名是定好的,不方便修改怎麼辦,在與當前包名同級的地方建立Person類,這樣就保證了C-S兩端包名都是一致的)
第二部:建立服務端,在新的專案中copyAIDL檔案(放到專案中main結構的aidl資料夾中),一定要注意包名相同!!!,然後在完全相同的包結構下複製Person這個實體類,編譯一下程式,服務端其實就是Android四大元件中的Service,
package com.my_project.test_aidl;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
import android.support.annotation.Nullable;
import android.util.Log;
import com.testaidl.IMyAidl;
import com.testaidl.model.Person;
import java.util.ArrayList;
import java.util.List;
/**
* Created by Administrator on 2018\10\31 0031.
* 服務端 service
*/
public class MyAidlService extends Service {
private final String TAG = this.getClass().getSimpleName();
public ArrayList<Person> mPersons;
/**
* 建立生成的本地 Binder 物件,實現 AIDL 制定的方法
*/
private IBinder mIBinder = new IMyAidl.Stub() {
@Override
public void addPerson(Person person) throws RemoteException {
Log.e("11111111111",person.toString());
mPersons.add(person);
}
@Override
public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {
}
@Override
public List<Person> getPersonList() throws RemoteException {
return mPersons;
}
};
/**
* 客戶端與服務端繫結時的回撥,返回 mIBinder 後客戶端就可以通過它遠端呼叫服務端的方法,即實現了通訊
*
* @param intent
* @return
*/
@Nullable
@Override
public IBinder onBind(Intent intent) {
mPersons = new ArrayList<>();
Log.e(TAG, "MyAidlService onBind");
return mIBinder;
}
}
然後咱們再清單檔案中宣告service的時候要設定其action(這個名字可以隨意取的):
第三步:建立客戶端專案:同樣的方式copyAIDL檔案和Person實體類,這個是和服務端一樣的,然後編譯生成Stub,做好準備工作以後,在客戶端上繫結這個服務,bingService(…)
package com.testaidl;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
import android.os.RemoteException;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import com.testaidl.model.Person;
import java.util.List;
import java.util.Random;
/**
* 客戶端client 程式碼
* */
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent intent1 = new Intent();
intent1.setPackage("com.my_project");
intent1.setAction("com.test_aidl.aidl");
bindService(intent1, mConnection, BIND_AUTO_CREATE);
final Button btn_test = findViewById(R.id.btn_test);
final TextView tv_test = findViewById(R.id.tv_test);
btn_test.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Random random = new Random();
Person person = new Person("shixin" + random.nextInt(10));
try {
mAidl.addPerson(person);
List<Person> personList = mAidl.getPersonList();
tv_test.setText(personList.toString());
} catch (RemoteException e) {
e.printStackTrace();
}
}
});
}
private IMyAidl mAidl;
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
//連線後拿到 Binder,轉換成 AIDL,在不同程序會返回個代理
mAidl = IMyAidl.Stub.asInterface(service);
}
@Override
public void onServiceDisconnected(ComponentName name) {
mAidl = null;
}
};
@Override
protected void onDestroy() {
super.onDestroy();
unbindService(mConnection);
}
}
這樣客戶端生成好了,可以通過客戶端發訊息給服務端,親測服務端可以收到訊息