編輯:關於Android編程
什麼是AIDL
aidl是 Android Interface definition language的縮寫,也就是安卓接口定義語言
為什麼要有AIDL
AIDL允許你定義客戶端與服務端達成一致的程序接口使用進程間通信相互交流。 在Android上面,一個進程不能正常的訪問另一個進程的內存。 所以說,他們需要分解他們的對象為操作系統可以理解的基本單位,然後為你把這些對象按次序跨越進程邊界 ,書寫這些代碼是單調冗長的,所以android使用AIDL為你處理這個問題。
注意:使用AIDL只有在你允許來自不同應用的客戶端跨進程通信訪問你的service,並且想要在你的service種處理多線程的時候才是必要的。 如果你不需要執行不同應用之間的IPC並發,你應該通過實現Binder建立你的接口,或者如果你想執行IPC,但是不需要處理多線程。那麼使用Messenger實現你的接口。
如何使用aidl完成進程間通信
1.建立.aidl文件
AIDL使用一個簡單的語法讓你聲明一個帶有一個或者多個帶有參數和返回值方法的接口 參數和返回值可以是任何類型,甚至是AIDL生成的接口
你必須使用java語言構建.aidl文件 每一個.aidl文件必須定義一個簡單的接口並且要求只有接口聲明和方法簽名
默認的,AIDL支持下面數據類型
ava語言中的所有基本數據類型(比如int、long、char、boolean等等)
String CharSequence List當定義你的service接口的時候,注意:
方法可以接收0或多個參數,並且有返回值或者返回void 所有非基本數據類型要求要求一個定向的tag來指定數據是去往哪個方向的 無論是輸入、輸出,還是輸入輸出(參加下面的例子) 基本數據類型是默認支持的,並且不能是其他的。 .aidl文件中的所有的代碼注釋都在生成的IBinder接口中(除了在import和包聲明之前的注釋) 只支持方法,你不可以在AIDL暴露靜態域下面給出代碼
以Android Stduio為例,我們看看如何使用AIDL進行進程間通信
1.創建IRemoteService .aidl文件
package com.example.aidlserver;
interface IRemoteService {
int getPid();
void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
double aDouble, String aString);
}
但是此時並沒有AIDL的java文件產生,其實android studio也是帶有自動生成的,只不過需要確認一些信息後才能生成。此時,我們可以在目錄 build–>generated–>source–>aidl–>test–>debug下面發現還沒有任何文件
此時,打開AndroidManifest.xml,確認package的值,如我這個<喎?/kf/ware/vc/" target="_blank" class="keylink">vcD4NCjxwcmUgY2xhc3M9"brush:java;">
關鍵性的一步,確認aidl文件所在的包名和AndroidMainifest.xml的package名是否一致。如果一致,點擊 Build–>Make Project,生成相應的java文件。如果不一致,則改aidl的包名,改成一致,再點擊生成,生成效果如圖。
我們看看生成的IRemoteService.java的內容
public interface IRemoteService extends android.os.IInterface {
/**
* Local-side IPC implementation stub class.
*/
public static abstract class Stub extends android.os.Binder implements com.example.aidlserver.IRemoteService {
private static final java.lang.String DESCRIPTOR = "com.example.aidlserver.IRemoteService";
/**
* Construct the stub at attach it to the interface.
*/
public Stub() {
this.attachInterface(this, DESCRIPTOR);
}
/**
* Cast an IBinder object into an com.example.aidlserver.IRemoteService interface,
* generating a proxy if needed.
*/
public static com.example.aidlserver.IRemoteService asInterface(android.os.IBinder obj) {
if ((obj == null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin != null) && (iin instanceof com.example.aidlserver.IRemoteService))) {
return ((com.example.aidlserver.IRemoteService) iin);
}
return new com.example.aidlserver.IRemoteService.Stub.Proxy(obj);
}
@Override
public android.os.IBinder asBinder() {
return this;
}
@Override
public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException {
switch (code) {
case INTERFACE_TRANSACTION: {
reply.writeString(DESCRIPTOR);
return true;
}
case TRANSACTION_getPid: {
data.enforceInterface(DESCRIPTOR);
int _result = this.getPid();
reply.writeNoException();
reply.writeInt(_result);
return true;
}
case TRANSACTION_basicTypes: {
data.enforceInterface(DESCRIPTOR);
int _arg0;
_arg0 = data.readInt();
long _arg1;
_arg1 = data.readLong();
boolean _arg2;
_arg2 = (0 != data.readInt());
float _arg3;
_arg3 = data.readFloat();
double _arg4;
_arg4 = data.readDouble();
java.lang.String _arg5;
_arg5 = data.readString();
this.basicTypes(_arg0, _arg1, _arg2, _arg3, _arg4, _arg5);
reply.writeNoException();
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
private static class Proxy implements com.example.aidlserver.IRemoteService {
private android.os.IBinder mRemote;
Proxy(android.os.IBinder remote) {
mRemote = remote;
}
@Override
public android.os.IBinder asBinder() {
return mRemote;
}
public java.lang.String getInterfaceDescriptor() {
return DESCRIPTOR;
}
@Override
public int getPid() throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
int _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(Stub.TRANSACTION_getPid, _data, _reply, 0);
_reply.readException();
_result = _reply.readInt();
} finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
@Override
public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, java.lang.String aString) throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeInt(anInt);
_data.writeLong(aLong);
_data.writeInt(((aBoolean) ? (1) : (0)));
_data.writeFloat(aFloat);
_data.writeDouble(aDouble);
_data.writeString(aString);
mRemote.transact(Stub.TRANSACTION_basicTypes, _data, _reply, 0);
_reply.readException();
} finally {
_reply.recycle();
_data.recycle();
}
}
}
static final int TRANSACTION_getPid = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
static final int TRANSACTION_basicTypes = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
}
public int getPid() throws android.os.RemoteException;
public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, java.lang.String aString) throws android.os.RemoteException;
}
我們只看重點部分,這裡有一個內部類Stub繼承Binder,實現了IRemoteService接口,這個類中有一個方法asInterface,接收一個IBinder對象,並且返回一個IRemoteService類型的對象。
定義遠程服務,暴漏接口給客戶端
public class RemoteService extends Service {
@Nullable
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
private final IRemoteService.Stub mBinder = new IRemoteService.Stub() {
@Override
public int getPid() throws RemoteException {
return Process.myPid();
}
@Override
public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {
}
};
}
同時,我們需要在清單文件中注冊這個服務,並且添加一個action,因為我們是通過遠程來調用服務的,所以必須指定一個action,用來隱式啟動。
現在,當一個客戶端(比如一個activity)調用bindService()來連接到這個service,這個客戶端的onServiceConnected()回調函數接收service中onBind()方法返回的mBinder實例
客戶端必須可以訪問接口類,所以如果客戶端和服務端在不同的應用中,那麼客戶端所在的應用必須有一份.aidl文件的副本,同樣,在客戶端我們創建一個aidl文件夾,然後把服務器端的aidl文件拷貝到這個目錄下,注意:這個時候要保證文件所在的包名和服務器端aidl的包名一樣,而不是和當前應用的包名一樣,否則會報錯。
當客戶端在onServiceConnected()回調方法中接收到IBinder時,它必須調用你的ServiceInterface.Stub.asInterface(service)來把返回參數映射到你的ServiceInterface類型上。例如:
private IRemoteService remoteService;
private ServiceConnection conn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
remoteService = IRemoteService.Stub.asInterface(service);
try {
int pid = remoteService.getPid();
int currentPid = Process.myPid();
System.out.println("currentPid: "+currentPid+", remotePid: "+pid);
remoteService.basicTypes(1,12,true,3,3,"aa");
} catch (RemoteException e) {
e.printStackTrace();
}
System.out.println("=====bind Success");
}
@Override
public void onServiceDisconnected(ComponentName name) {
Toast.makeText(MainActivity.this, "service disConneted unexpected", Toast.LENGTH_SHORT).show();
remoteService = null;
}
};
完整代碼
服務端:
public class RemoteService extends Service {
@Nullable
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
private final IRemoteService.Stub mBinder = new IRemoteService.Stub() {
@Override
public int getPid() throws RemoteException {
System.out.println("=====Thread getPid: "+Thread.currentThread().getName());
return Process.myPid();
}
@Override
public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {
System.out.println("=====Thread basicTypes: "+Thread.currentThread().getName());
}
};
}
客戶端:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void bindService(View view){
System.out.println("=====begin bindService");
Intent service = new Intent("com.lxn.remote");
//通過bindService綁定服務
bindService(service,conn,BIND_AUTO_CREATE);
}
private IRemoteService remoteService;
private ServiceConnection conn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
remoteService = IRemoteService.Stub.asInterface(service);
try {
int pid = remoteService.getPid();
int currentPid = Process.myPid();
System.out.println("===currentPid: "+currentPid+", remotePid: "+pid);
remoteService.basicTypes(1,12,true,3,3,"aa");
} catch (RemoteException e) {
e.printStackTrace();
}
System.out.println("=====bind Success");
}
@Override
public void onServiceDisconnected(ComponentName name) {
Toast.makeText(MainActivity.this, "service disConneted unexpected", Toast.LENGTH_SHORT).show();
remoteService = null;
}
};
@Override
protected void onDestroy() {
super.onDestroy();
unbindService(conn);
}
}
我們點擊客戶端的綁定服務按鈕,然後在控制台進行結果的輸出
那麼AIDL是什麼原理呢?
AIDL其實通過我們寫的aidl文件,幫助我們生成了一個接口,一個Stub類用於服務端,一個Proxy類用於客戶端調用。關於詳細的細節,我在這裡就不討論了
現在網絡直播越來越火,網絡主播也逐漸成為一種新興職業,對於網絡直播,彈幕功能是必須要有的,如下圖:首先來分析一下,這個彈幕功能是怎麼實現的,首先在最下面肯定是一個游戲界面
先上預覽圖:流程1.一個勻速圓周運動的點 2.多個勻速圓周運動的點 3.多個圓周運動的點,速度由快到慢 4.點與點之間的間距線性減少,動畫的最後合為一個點 5.為了讓動畫
Android會為每個apk進程分配一個單獨的空間(比如只能訪問/data/data/自己包名下面的文件),一般情況下apk之間是禁止相互訪問數據的。通過Shared U
解決 INSTALL FAILED CONFLICTING PROVIDER的問題方法 在安裝Android應用時出現INSTALL FAILED