English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
Introduzione
In precedenza, ho chiarito la comunicazione tra thread in Android <Quale è la relazione tra Thread, Handler e HandlerThread?>, tutti questi sono nello stesso processo, quindi come implementare la comunicazione tra processi, o la comunicazione tra diverse applicazioni? In questo caso, è necessario utilizzare AIDL (Android Interface Definition Language, linguaggio di definizione delle interfacce Android).
Metodo di utilizzo (AndroidStudio)
Ho notato che attualmente la maggior parte delle guide su AIDL sono ancora basate su Eclipse, ma l'uso di AIDL in AndroidStudio presenta alcune differenze. Vediamo come farlo, per prima cosa creiamo un progetto come server:
Dopo aver creato, con un clic destro su qualsiasi cartella, seleziona New-->AIDL-->AIDL File, dopo aver modificato il nome del file, verrà creato automaticamente una cartella aidl sotto src/main, la struttura della directory del pacchetto è la seguente:
main
aidl
com.example.tee.testapplication.aidl
java
com.example.tee.testapplication
res
AndroidManifest.xml
The automatically generated aidl file is as follows:
// AidlInterface.aidl package com.example.tee.testapplication.aidl; // Dichiarare qualsiasi tipo non predefinito qui con le dichiarazioni di importazione 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); }
We can see that the code format of the aidl file is very similar to Java, supporting Java's basic types as well as List, Map, etc. If it is a custom class, it needs to be manually imported; we will talk about it later. Let's start with the simplest, create an IMyAidlInterface.aidl file and modify it as follows:
package com.example.tee.testapplication.aidl; interface IMyAidlInterface { String getValue(); }
Define a getValue method in the interface that returns a string, now you can compile the project, find the app/build/generated/source/aidl/debug directory, and under your application package name, you will find a generated Interface class with the same name as the aidl file you defined. This indicates that the aidl file will eventually be converted into an interface to implement, and this file does not need to be maintained by us; it is automatically generated after compilation.
Then create a new class that inherits from 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(); } }
In the MAIDLService class, define an inner class that inherits from IMyAidlInterface.Stub and overrides the getValue method that we defined in aidl, returning the string 'get value'.
Arrivati a questo punto, abbiamo creato il servizio server, il cui scopo è restituire una stringa dopo la chiamata, infine dichiararlo nel file AndroidManifest:}
<service android:name=".MAIDLService" android:process=":remote"//aggiungere questa frase significa che la chiamata client creerà un nuovo processo android:exported="true"//di default è già true, può essere omesso, dichiarare se è possibile effettuare chiamate remote > <intent-filter> <categoria android:name="android.intent.category.DEFAULT" /> <azione android:name="com.example.tee.testapplication.aidl.IMyAidlInterface" /> </intent-filter> </service>
l'azione di android:process=":remote" serve a dichiarare se viene creato un nuovo processo durante la chiamata, quindi scrivere il codice client, creare un nuovo progetto, copiare il file aidl creato poco fa in questo progetto, notare che anche in questo caso deve essere collocato nella cartella aidl, quindi scrivere il codice seguente in 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(); } }
Attenzione, la stringa di parametro passata all'Intent è personalizzata nel manifest come etichetta action, e ricordati di disconnettere il servizio in onDestroy().
Il risultato dell'esecuzione è che quando clicchiamo sul TextView, viene visualizzato il valore di get value restituito dal server.
Oggetto personalizzato
Abbiamo usato un tipo di base String, ma quando usiamo la nostra classe personalizzata, il metodo sopra non è applicabile. Dobbiamo importare manualmente la nostra classe personalizzata e modificare il progetto che abbiamo creato come server.
Prima di tutto, crea un nuovo file Student.java nel pacchetto generato all'inizio (tutti i file relativi a aidl devono essere messi in questo pacchetto).
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); } }
Deve implementare l'interfaccia di serializzazione Parcelable, AndroidStudio genererà automaticamente la classe interna statica CREATOR e il metodo describeContents, queste parti non dobbiamo modificarle, possiamo utilizzare quelle generate automaticamente. Poi ricorda di riscrivere il metodo writeToParcel e definire il metodo readFromParcel, presta attenzione che l'ordine degli attributi deve essere identico nei due metodi, uno per scrivere e uno per leggere. Nel costruttore Student(Parcel in) chiama il metodo readFromParcel(in).
Quindi crea un nuovo file Student.aidl (anch'esso nella directory aidl):
// Student.aidl package com.example.tee.testapplication.aidl; // Dichiarare qualsiasi tipo non predefinito qui con le dichiarazioni di importazione parcelable Student;
Attenzione, la lettera iniziale della parola chiave parcelable prima di Student è minuscola, modifica il file IMyAidlInterface.aidl come segue:
// IMyAidlInterface.aidl package com.example.tee.testapplication.aidl; // Dichiarare qualsiasi tipo non predefinito qui con le dichiarazioni di importazione import com.example.tee.testapplication.aidl.Student; interface IMyAidlInterface { Student getStudent(); void setStudent(in Student student); String getValue(); }
Sono stati definiti due metodi, uno per impostare Student e uno per ottenere Student, nel metodo setStudent presta attenzione che il parametro ha una parola chiave in prima posizione prima del tipo di dato, nei parametri di aidl si distinguono in input e output
Ora, nel file MAIDLService.java, ricorda di riscrivere i due metodi aggiunti di recente:
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(); } }
Il codice del server è stato modificato, ora passiamo al progetto client, copiamo e sovrascriviamo i file della cartella aidl del server, mantenendo le due parti coerenti, quindi modifica come segue in 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 进程通信的资料整理,后续将继续补充相关资料,感谢大家对本站的支持!
声明:本文内容来自网络,版权属于原作者,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未进行人工编辑处理,也不承担相关法律责任。如果您发现涉嫌版权的内容,请发送邮件至:notice#oldtoolbag.com(发送邮件时,请将#替换为@)进行举报,并提供相关证据,一经查实,本站将立即删除涉嫌侵权内容。