Android: inter-process communication
Intent ComponentName broadcast-BroadcastReceiver ContentProvider AIDL
ComponentName of Intent
Intent is our most commonly used data transmission channel, especially opening an Activity through Intent, so everyone will be familiar with it. We usually use Intent to open the internal Activity of the same process (App). To achieve cross-process communication, we need to send the Intent object to another App, and parse it out, then ComponentName is required to do this for us. Since data can be sent to another process, interaction between different processes can be realized.
Note: To enable Activity B in another process, set the exported of the Activity to true in the AndroidManifest file of Project B. Otherwise, an error is reported.
android:exported="true"
The constructor that will use ComponentName is as follows:
public ComponentName(String pkg, String cls) { if (pkg == null) throw new NullPointerException("package name is null"); if (cls == null) throw new NullPointerException("class name is null"); mPackage = pkg; mClass = cls; }
It requires two parameters. The first parameter is an existing pakage (package), and the second parameter is the name of the class you want to open in this package (note that it includes the complete package name ), the following is an example:
MainActivity in the AndroidAIDL (com. example. androidaidl) Process
@ Override protected void onCreate (Bundle savedInstanceState) {super. onCreate (savedInstanceState); setContentView (R. layout. activity_main); // receives the passed Intent if (getIntent ()! = Null) {System. out. println ("----------" + getIntent (). getIntExtra ("id", 0) + "----------");}}
Another process, AndroidTest, writes the following code in MainActivity:
/** Specify the name of the Activity with the package name */ComponentName componentName = new ComponentName ("com. example. androidaidl "," com. example. androidaidl. mainActivity "); Intent intent = new Intent (); intent. putExtra ("id", 1001); intent. setComponent (componentName); startActivity (intent );
After running the above Code, you will see that 1001 is printed in LogCat, indicating that the Intent sent from the AndroidTest process is normal.
Note: In the code above, we pass the basic data type. for basic data types, such as Int and String, you can directly read the data as above, however, if a complex object is sent, the object must implement the Serializable or Parcelable interface.
For example, we define a SendData object as the passing object, which implements the Parcelable interface:
public class SendData implements Parcelable{ int id; String content; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getContent() { return content; } public void setContent(String content) { this.content = content; } public static final Parcelable.Creator
CREATOR = new Parcelable.Creator
() { @Override public SendData createFromParcel(Parcel source) { // TODO Auto-generated method stub SendData data = new SendData(); data.setId(source.readInt()); data.setContent(source.readString()); return data; } @Override public SendData[] newArray(int size) { // TODO Auto-generated method stub return new SendData[size]; } }; @Override public int describeContents() { // TODO Auto-generated method stub return 0; } @Override public void writeToParcel(Parcel dest, int flags) { // TODO Auto-generated method stub dest.writeInt(id); dest.writeString(content); }}
Sending code:
Intent intent = new Intent (); SendData data = new SendData (); data. setId (1001); data. setContent ("hellow world"); // sends the serialized object intent. putExtra ("data", data); startActivity (intent );
Receive code
Protected void onCreate (Bundle savedInstanceState) {super. onCreate (savedInstanceState); setContentView (R. layout. activity_main); if (getIntent ()! = Null) {if (getIntent (). getParcelableExtra ("data") = null) return; // read the serialized object and convert it to SendData type SendData data = (SendData) getIntent (). getParcelableExtra ("data"); System. out. println ("----------" + data. getContent () + "-----------");}}
If you are in the same process, the above method has no problems. If you are in different processes, pay attention to it,The package name of the SendData bean must be the same in each project.Otherwise, the receiver cannot be parsed.
Broadcast-BroadcastReceiver
Android broadcast is system-level. As long as the same Action is passed (Action_Test is used in the following example), messages broadcast by other processes can be received, data can be transmitted through Intent in broadcast.
Sender code:
Intent intent = new Intent("Action_Test");SendData data = new SendData();data.setId(1001);data.setContent("hellow world");intent.putExtra("data", data);intent.putExtra("id", 1001);getActivity().sendBroadcast(intent);
Receiver code (Dynamic register broadcast ):
innerReceiver = new InnerReceiver();IntentFilter filter = new IntentFilter("Action_Test");registerReceiver(innerReceiver, filter);class InnerReceiver extends BroadcastReceiver{ @Override public void onReceive(Context context, Intent intent) { // TODO Auto-generated method stub if (intent.getAction().equals("Action_Test")){ SendData data = (SendData)intent.getParcelableExtra("data"); System.out.println("-----------"+data.getContent()+"------------"); } } }
Because data is transmitted through Intent, the requirements for complex objects are the same as those for the first method, requiring the same package name of the bean
ContentProvider
ContentProvider is usually used to operate datasets. Android itself provides a lot of ContentProvider access, such as contacts and albums.
To access ContentProvider, you must use Uri and start with "content. Let's take a look at the usage:
In the process AndroidAIDL (com. example. androidaidl), we define a class inherited from ContentProvider and need to reload its method. Here we take query as an example.
Public class ProviderTest extends ContentProvider {private static final UriMatcher MATCHER = new UriMatcher (UriMatcher. NO_MATCH); static {// Add the access string, corresponding to the android: authorities attribute MATCHER in the configuration file. addURI ("com. mh. getdata "," stock ", 10001) ;}@ Override public boolean onCreate () {// TODO Auto-generated method stub return false ;} @ Override/*** @ param uri URI path * @ param projection the column set to be protected. If null is passed, all columns will be included in Remove. * @ param selection is used to filter the dataset rules. null indicates that the dataset is not filtered. * @ param selectionArgs is formatted like a string. Can the selection parameter contain? S, which will be replaced by the content of selectionArgs * @ param sortOrder sorting. */public Cursor query (Uri uri, String [] projection, String selection, String [] selectionArgs, String sortOrder) {// TODO Auto-generated method stub System. out. println ("-------------------- query --------------------"); return null ;}@ Override public String getType (Uri uri) {// TODO Auto-generated method stub return null ;} @ Override public Uri insert (Uri uri, ContentValues values) {// TODO Auto-generated method stub return null;} @ Override public int delete (Uri uri, String selection, string [] selectionArgs) {// TODO Auto-generated method stub return 0;} @ Override public int update (Uri uri, ContentValues values, String selection, String [] selectionArgs) {// TODO Auto-generated method stub return 0 ;}}
After defining this class, you must declare it in AndroidManifest,Android: exported = true, Remember to write, otherwise a permission error will be prompted
The preceding configuration has two attributes:
Android: name is the class name
Android: authorities: This is the Uri mentioned above. You need to access the Provider through this Uri.
Let's take a look at the caller. In another process, we have the following code:
ContentResolver resolver = getActivity (). getContentResolver ();/** com. mh. getdata/stock must be consistent with the Uri added in the process where the Provider is located */Uri uri = Uri. parse ("content: // com. mh. getdata/stock "); Cursor cursor = resolver. query (uri, null, null );
After the above Code is called, the "query" text is printed in LogCat. The table name Provider is successfully called, and we can interact with the Provider object in the AndroidAIDL process through resolver.
AIDL
An Interface Definition Language. Android automatically generates communication code. With AIDL, we can call methods in another process in one process, it is said that some big companies use the AIDL to keep their services alive, so we can study them well. I personally think that AIDL is more suitable for plug-in systems, or multiple apps can form a system. For example, due to memory leakage, some companies encapsulate WebView into an app separately, you can use the AIDL technology to call the interface in this app to operate WebView behavior.
The following describes how to use it:
Create a common File in two projects (new-> General-> File in Eclipse). Remember to write the suffix (aidl) at the same time ), the package names of the files in the two projects must be the same and the content must be the same,
After compilation, a file with the same name and suffix of java is automatically generated under the gen directory. There is the Stub class we will use.
public static abstract class Stub extends android.os.Binder implements com.example.aidl.AidlFunctions
In the interface file AIDLFunctions. aidl, we define a method named show
interface AidlFunctions{ void show();}
Server:
The use of AIDL requires a Service, so we need to declare a Service on the server.
Public class AIDLService extends Service {// stub is the AidlFunctions automatically generated by the system. stub binder; @ Override public void onCreate () {// TODO Auto-generated method stub super. onCreate () ;}@ Override public IBinder onBind (Intent intent) {// TODO Auto-generated method stub binder = new AidlFunctions. stub () {@ Override // here is the implementation of the method declared in the interface public void show () throws RemoteException {// TODO Auto-generated method stub System. out. println ("-------------------- received ----------------------") ;}; return binder ;}}
Declare Service in AndroidManifest
Client:
// To bind a service, you must use ServiceConnection private ServiceConnection serviceConnection; // custom interface, which is the same as private AidlFunctions aidlFunctions; serviceConnection = new ServiceConnection () {@ Override public void onServiceDisconnected (ComponentName name) {// TODO Auto-generated method stub System. out. println ("-------------------- ServiceDisconnected --------------------") ;}@ Override public void onServiceConnected (ComponentName, IBinder service) {// TODO Auto-generated method stub System. out. println ("-------------------- ServiceConnected ----------------------"); aidlFunctions = AidlFunctions. stub. asInterface (service) ;}}; Intent intent = new Intent ("com. example. androidaidl. AIDLService "); bindService (intent, serviceConnection, Context. BIND_AUTO_CREATE); // call the show method try {aidlFunctions. show ();} catch (RemoteException e) {// TODO Auto-generated catch block e. printStackTrace ();}