編輯:關於Android編程
前言
前面梳理了Android的線程間的通信《Thread、Handler和HandlerThread關系何在?》 ,這些都是在同一個進程中,那進程間的通信,或者說不同的應用間的通信該如何實現呢?這個時候就要用到AIDL(Android Interface Definition LanguageAndroid接口定義語言 )。
使用方法(AndroidStudio)
我發現現在AIDL的教程基本上還是eclipse的,但是在AndroidStudio裡面使用AIDL還是有一些不同的,來看看怎麼用,首先新建一個工程當做server服務端:
創建好後在任意文件夾右鍵New-->AIDL-->AIDL File,編輯文件名後會自動在src/main目錄下面新建aidl文件夾,包的目錄結構如下:
main
aidl
com.example.tee.testapplication.aidl
java
com.example.tee.testapplication
res
AndroidManifest.xml
自動生成的aidl文件如下:
// AidlInterface.aidl
package com.example.tee.testapplication.aidl;
// Declare any non-default types here with import statements
interface AidlInterface {
/**
* 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);
}
我們可以看到aidl文件的代碼格式跟java很像,支持java的基礎類型以及List、Map等,如果是自定義類的話需要手動導入,我們後面再說,先來最簡單的,新建一個 IMyAidlInterface.aidl文件,修改如下:
package com.example.tee.testapplication.aidl;
interface IMyAidlInterface {
String getValue();
}
在接口中定義一個getValue方法,返回一個字符串,現在可以編譯一下工程,找到app/build/generated/source/aidl/debug目錄,在我們應用包名下會發現生成了一個Interface類,名字跟我們定義的aidl的文件名字一樣,這說明其實aidl文件在最後還是會轉換成接口來實現,而且這個文件不需要我們維護,在編譯後自動生成。
然後新建一個類繼承Service:
public class MAIDLService extends Service{
public class MAIDLServiceImpl extends IMyAidlInterface.Stub{
@Override
public String getValue() throws RemoteException {
return "get value";
}
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return new MAIDLServiceImpl();
}
}
在MAIDLService類中定義一個內部類繼承IMyAidlInterface.Stub,並且重寫我們在aidl也就是在接口中定義的getValue方法,返回字符串get value。
到了這裡,我們就新建好了這個服務端,作用是在調用後返回一個字符串,最後在AndroidManifest文件中聲明:
<service android:name=".MAIDLService" android:process=":remote"//加上這句的話客戶端調用會創建一個新的進程 android:exported="true"//默認就為true,可去掉,聲明是否可以遠程調用 > <intent-filter> <category android:name="android.intent.category.DEFAULT" /> <action android:name="com.example.tee.testapplication.aidl.IMyAidlInterface" /> </intent-filter> </service>
android:process=":remote"這一行的作用是聲明是否調用時新建進程,接下來寫客戶端代碼,新建一個工程,將剛才創建的aidl文件拷貝到這個工程中,注意同樣也是要放在aidl文件夾下,然後在MainActivity中編寫代碼如下:
public class MainActivity extends AppCompatActivity {
private TextView mValueTV;
private IMyAidlInterface mAidlInterface = null;
private ServiceConnection mServiceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mAidlInterface = IMyAidlInterface.Stub.asInterface(service);
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
Intent intent = new Intent("com.example.tee.testapplication.aidl.IMyAidlInterface");
bindService(intent, mServiceConnection, BIND_AUTO_CREATE);
mValueTV = (TextView) findViewById(R.id.tv_test_value);
mValueTV.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
try {
mValueTV.setText(mAidlInterface.getValue());
} catch (RemoteException e) {
e.printStackTrace();
}
}
});
}
@Override
protected void onDestroy() {
if(mAidlInterface != null){
unbindService(mServiceConnection);
}
super.onDestroy();
}
}
注意這裡新建Intent的傳入的參數字符串是在manifest裡面自定義的action標簽,並且在onDestroy記得取消綁定服務。
執行結果就是我們在點擊TextView時會顯示服務端給我們返回的get value字符串
自定義的對象
剛才我們使用的是基礎類型String,在使用我們自己定義的類的時候用上面的方法是不行的,用我們自定義的類需要手動導入,修改剛才我們創建的作為服務端的工程
首先在開始生成的aidl包下(所有aidl相關的文件都要放在這個包下)新建Student.java
public class Student implements Parcelable{
public String name;
public int age;
protected Student(Parcel in) {
readFromParcel(in);
}
public Student() {
}
public static final Creator<Student> CREATOR = new Creator<Student>() {
@Override
public Student createFromParcel(Parcel in) {
return new Student(in);
}
@Override
public Student[] newArray(int size) {
return new Student[size];
}
};
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(age);
dest.writeString(name);
}
public void readFromParcel(Parcel in){
age = in.readInt();
name = in.readString();
}
@Override
public String toString() {
return String.format(Locale.ENGLISH, "STUDENT[%s:%d]", name, age);
}
}
需要實現Parcelable序列化接口,AndroidStudio會自動生成靜態內部類CREATOR和describeContents方法,這些部分我們都不需要修改,用自動生成的就好。然後重寫writeToParcel方法,自定義readFromParcel方法,注意這兩個方法裡面的屬性順序必須一致,一個是寫入,一個是讀取。在構造方法Student(Parcel in)中調用readFromParcel(in)方法。
接下來新建Student.aidl文件(也是在aidl包中):
// Student.aidl package com.example.tee.testapplication.aidl; // Declare any non-default types here with import statements parcelable Student;
注意這裡Student前面的關鍵字parcelable首字母是小寫哦,再修改IMyAidlInterface.aidl文件如下:
// IMyAidlInterface.aidl
package com.example.tee.testapplication.aidl;
// Declare any non-default types here with import statements
import com.example.tee.testapplication.aidl.Student;
interface IMyAidlInterface {
Student getStudent();
void setStudent(in Student student);
String getValue();
}
定義了兩個方法,一個是設置Student,一個是獲取Student,在setStudent這個方法注意參數在類型前面有個in關鍵字,在aidl裡參數分為in輸入,out輸出
現在在MAIDLService.java中重寫新加的兩個方法:
private Student mStudent;
public class MAIDLServiceImpl extends IMyAidlInterface.Stub{
@Override
public Student getStudent() throws RemoteException {
return mStudent;
}
@Override
public void setStudent(Student student) throws RemoteException {
mStudent = student;
}
@Override
public String getValue() throws RemoteException {
return "get value : " + Thread.currentThread().getName() + Thread.currentThread().getId();
}
}
服務端代碼修改完畢,來到客戶端工程,同樣要把剛才的aidl包下的文件拷貝覆蓋過來,保持兩邊一致,然後在MainActivity.java中修改如下:
mValueTV = (TextView) findViewById(R.id.tv_test_value);
mStudentTV = (TextView) findViewById(R.id.tv_test_student);
mValueTV.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
try {
mValueTV.setText(mAidlInterface.getValue());
} catch (RemoteException e) {
e.printStackTrace();
}
}
});
mStudentTV.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
try {
Student student = new Student();
student.age = 10;
student.name = "Tom";
mAidlInterface.setStudent(student);
mStudentTV.setText(mAidlInterface.getStudent().toString());
} catch (RemoteException e) {
e.printStackTrace();
}
}
});
現在編譯工程,會發現工程會報錯,找不到類Student,我們需要在app目錄下的build.gradle文件添加代碼如下:
android {
sourceSets {
main {
manifest.srcFile 'src/main/AndroidManifest.xml'
java.srcDirs = ['src/main/java', 'src/main/aidl']
resources.srcDirs = ['src/main/java', 'src/main/aidl']
aidl.srcDirs = ['src/main/aidl']
res.srcDirs = ['src/main/res']
assets.srcDirs = ['src/main/assets']
}
}
}
也就是指定一下文件目錄,現在再編譯就沒有問題了
總結
Android的IPC使用起來還是挺簡單的,AIDL文件的語法也跟我們平時使用接口的時候很相似,但是它只支持基礎類型,只能引用AIDL文件,需要使用自定義類的時候要稍微麻煩一點。
以上就是對Android IPC 進程通信的資料整理,後續繼續補充相關資料謝謝大家對本站的支持!
Android使用GridView實現日歷的簡單功能
簡單的日歷實現,只是顯示了每一個月,沒有顯示當天和記事這些功能主要是計算月初是周幾,月末是周幾,然後相應的顯示上一月多少天和下一月多少天。先看一下關於日期的用到的幾個工具
Android開發之監聽手機來電
TelephonyManager是一個管理手機通話狀態、電話網絡信息的服務類,該類提供了大量的getXxx(),方法獲取電話網絡的相關信息。關於TelephonyMana
VLC for Android 基於 Opencv 對 RTSP視頻 實時人臉檢測
最近項目上需要在Android客戶端 通過獲取 RTSP 的視頻進行實時人臉檢測, 要做就就是以下幾點:1、通過VLC 獲取 獲取RTSP2、對VLC中播放的視頻進行實時
Android 實現全屏和無標題欄的顯示
在Android實現沒有標題欄的方法有兩種:在代碼中添加requestWindowFeature(Window.FEATURE_NO_TITLE); 在清單文件Andro