Android-AIDL Learning

Source: Internet
Author: User
Tags mremote

Android-AIDL Learning
Definition 1 and AIDL: Android Interface Definition Language (Android Interface Definition Language. Android uses AIDL to support inter-process communication (IPC) between services and application components, including components running in different applications or individual processes. This enables the Service to easily support multiple applications across processes. To transfer objects between processes, you need to resolve the data to OS-level primitives, which are implemented through the Parcelable interface. Http://blog.csdn.net/woliuyunyicai/article/details/45286731)
2. Steps for creating AIDL: (1) create a file with the aidl extension in the Java package directory of the Eclipse Android project. The syntax of this file is similar to Java code, but it will be slightly different. (2) If the content of the aidl file is correct, ADT will automatically generate a Java interface file (*. java ). (3) create a Service class ). (4) Implement the Java interface generated by the aidl file. (5) In AndroidManifest. configure the AIDL service in the xml file. In particular, the attribute value of android: name in the tag is the ID of the service to be referenced by the client, that is, the parameter value of the Intent class.
3. Data Types supported by AIDL: 1) Java simple type (int, char, boolean, etc ). Import is not required. 2) String and CharSequence; no need to import 3) List and Map. However, the element types of List and Map objects must be the data types supported by AIDL. You do not need to import 4) the API automatically generated by AIDL. Required import 5) class that implements the android. OS. Parcelable interface. Import required
The following is an analysis based on the project: the communication between processes creates an eclipse project for the client and the server respectively to send requests from the client to the server. Source code structure:
1. For the passed data class type definition, note that the first custom class to be passed must be implements Parcelable interface Person Class Object source code:

Package com. aidl; import android. OS. parcel; import android. OS. parcelable; public class Person implements Parcelable {// data of the custom type. In this example, the data is age and name. Private intage = 0; private String name = null; // This constructor facilitates the creation of related objects in the client, and use it as the public Person () {}/* parameter for calling methods in the interface connection to provide constructors for creating objects from Parcel, that is, the read process. Private is set here. External calls */private Person (Parcel in) {readFromParcel (in) ;}@ Override publicint describeContents () {return 0;} are prohibited ;} /** [2] to implement the Parcelable interface, you need to implement writeToParcel () and readFromParcel () to write the object (data) to Parcel, * and read the object from Parcel *. Note that the write sequence must be consistent with the read sequence, because the Parcel class is a fast serialization and deserialization Mechanism *. Unlike bundle, there is no index mechanism and linear data storage and reading. * Note that readFromParcel () is not an overrider, but a method provided by us. If we do not provide it, we must go to private * Person (Parcel in) {age = in. readInt (); name = in. readString ();} * given that the actual data type is more complex than the small example and easier to read code, we give the readFromParcel () name following writeToParcel () * // @ Override public void writeToParcel (Parcel out, int flag) {out. writeInt (age); // write data to age out first. writeString (name); // Second, such as name} public void readFromParcel (Parcel in) {age = in. readInt (); // read a first Ge, keep the same order as write name = in. readString (); // second, read the name and keep it in the same order as write.}/** the class that implements the Parcelable interface must have a static * field called CREATOR to implement Parcelable. object of the Creator interface *. In the Java interface automatically generated by the AIDL file, IBinder calls Parcelable. creator to get the passed object: _ arg1 = * cn. wei. flowingflying *. proandroidservice. person. CREATOR. createFromParcel (data); */public static final Parcelable. creator
 
  
CREATOR = new Parcelable. Creator
  
   
() {@ Override public Person createFromParcel (Parcel source) {return new Person (source) ;}@ Override public Person [] newArray (int size) {return new Person [size] ;}};/* a series of getter, setter Methods */publicint getAge () {returnage;} public String getName () {returnname ;} publicvoid setAge (intage) {this. age = age;} publicvoid setName (String name) {this. name = name ;}}
  
 

To pass non-local objects between processes, you must implement the Parcelable interface. Override public void writeToParcel (Parcel out, int flag) to save the object attributes to the passed Parcel object. In addition, a public static Creator Domain: Parcelable. Creator must be implemented. CREATOR, used to create a Person object.


2. The AIDL service needs to create an AIDL file. Create the same aidl file on the client and server, and note that the package name and file name must be exactly the same. Pay attention to the import. Person. aidl source code in the aidl file for custom classes:
package com.aidl; parcelable Person;

IMyService. aidl source code:
package com.aidl;import com.aidl.Person;interface IMyService{    Map getPersonAll(in String tag, in Person person);    Person getPerson();}

 

Similar to defining interfaces, You can provide corresponding attributes and methods again. The method can also accept zero to multiple parameters. The parameters must be modified using (in, out, inout.
3. After the aidl file is created, Eclipse will automatically generate the com. aidl. IMyService. java file:
/* * This file is auto-generated.  DO NOT MODIFY. * Original file: F:\\Android Workspace\\AIDLServer\\src\\com\\aidl\\IMyService.aidl */package com.aidl; public interface IMyService extends android.os.IInterface {    /** Local-side IPC implementation stub class. */    public static abstract class Stub extends android.os.Binder implements            com.aidl.IMyService {        private static final java.lang.String DESCRIPTOR = "com.aidl.IMyService";         /** Construct the stub at attach it to the interface. */        public Stub() {            this.attachInterface(this, DESCRIPTOR);        }         /**         * Cast an IBinder object into an com.aidl.IMyService interface,         * generating a proxy if needed.         */        public static com.aidl.IMyService asInterface(android.os.IBinder obj) {            if ((obj == null)) {                return null;            }            android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);            if (((iin != null) && (iin instanceof com.aidl.IMyService))) {                return ((com.aidl.IMyService) iin);            }            return new com.aidl.IMyService.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_getPersonAll: {                data.enforceInterface(DESCRIPTOR);                java.lang.String _arg0;                _arg0 = data.readString();                com.aidl.Person _arg1;                if ((0 != data.readInt())) {                    _arg1 = com.aidl.Person.CREATOR.createFromParcel(data);                } else {                    _arg1 = null;                }                java.util.Map _result = this.getPersonAll(_arg0, _arg1);                reply.writeNoException();                reply.writeMap(_result);                return true;            }            case TRANSACTION_getPerson: {                data.enforceInterface(DESCRIPTOR);                com.aidl.Person _result = this.getPerson();                reply.writeNoException();                if ((_result != null)) {                    reply.writeInt(1);                    _result.writeToParcel(reply,                            android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);                } else {                    reply.writeInt(0);                }                return true;            }            }            return super.onTransact(code, data, reply, flags);        }         private static class Proxy implements com.aidl.IMyService {            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 java.util.Map getPersonAll(java.lang.String tag,                    com.aidl.Person person) throws android.os.RemoteException {                android.os.Parcel _data = android.os.Parcel.obtain();                android.os.Parcel _reply = android.os.Parcel.obtain();                java.util.Map _result;                try {                    _data.writeInterfaceToken(DESCRIPTOR);                    _data.writeString(tag);                    if ((person != null)) {                        _data.writeInt(1);                        person.writeToParcel(_data, 0);                    } else {                        _data.writeInt(0);                    }                    mRemote.transact(Stub.TRANSACTION_getPersonAll, _data,                            _reply, 0);                    _reply.readException();                    java.lang.ClassLoader cl = (java.lang.ClassLoader) this                            .getClass().getClassLoader();                    _result = _reply.readHashMap(cl);                } finally {                    _reply.recycle();                    _data.recycle();                }                return _result;            }             @Override            public com.aidl.Person getPerson()                    throws android.os.RemoteException {                android.os.Parcel _data = android.os.Parcel.obtain();                android.os.Parcel _reply = android.os.Parcel.obtain();                com.aidl.Person _result;                try {                    _data.writeInterfaceToken(DESCRIPTOR);                    mRemote.transact(Stub.TRANSACTION_getPerson, _data, _reply,                            0);                    _reply.readException();                    if ((0 != _reply.readInt())) {                        _result = com.aidl.Person.CREATOR                                .createFromParcel(_reply);                    } else {                        _result = null;                    }                } finally {                    _reply.recycle();                    _data.recycle();                }                return _result;            }        }         static final intTRANSACTION_getPersonAll = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);        static final intTRANSACTION_getPerson = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);    }     public java.util.Map getPersonAll(java.lang.String tag,            com.aidl.Person person) throws android.os.RemoteException;     public com.aidl.Person getPerson() throws android.os.RemoteException;}


 

Note that stub class: abstract class is implemented in the source code and inherits the Binder

Public static abstract class Stub extends android. OS. Binder implements com. aidl. IMyService

4. Implement the service on the server:

 

Package com. aidl; public class MyService extends Service {/* Service extends Stub and implements required functions, which is equivalent to IMyService generated by implements. java */public class MyServiceImpl extends IMyService. stub {@ Override public Map getPersonAll (String tag, Person person) throws RemoteException {Map
 
  
Map = new HashMap
  
   
(); Map. put ("tag", tag); map. put ("name", person. getName (); map. put ("age", String. valueOf (person. getAge (); map. put ("person", person. toString (); return map;} @ Override public Person getPerson () throws RemoteException {return new Person () ;}@ Override public IBinder onBind (Intent intent) {return new MyServiceImpl ();}}
  
 

 

Register the service in the mainfest file:

 

                
               
                                            
          
 

 

5. Bind and use Service in Client Activity

 

 

Package com. example. aidlclient; import com. aidl. IMyService; import com. aidl. person; public class MainActivity extends Activity {private Button mybu; private final static String ACTION_TAG = "com. aidl. action. IMyService "; // MyService can be used as a normal Service to call private IMyService iMyService; private ServiceConnection serviceConnection = new ServiceConnection () {@ Override public void onServiceConnected (ComponentName name, IBinder service) {// obtain the service instance iMyService = IMyService. stub. asInterface (service) ;}@ Override public void onServiceDisconnected (ComponentName name) {iMyService = null ;};@ Override protected void onCreate (Bundle savedInstanceState) {super. onCreate (savedInstanceState); setContentView (R. layout. activity_main); mybu = (Button) findViewById (R. id. mybu); // bindService (new Intent (ACTION_TAG), serviceConnection, Context. BIND_AUTO_CREATE); mybu. setOnClickListener (new OnClickListener () {@ Override public void onClick (View v) {try {doWithService () ;}catch (RemoteException e ){}}});} /******* Operation Service * @ throws RemoteException *************/private void doWithService () throws RemoteException {Person person = iMyService. getPerson (); person. setAge (10); person. setName ("Mary"); Log. I ("doWithService", "getName:" + person. getName (); Log. I ("doWithService", "getAge:" + String. valueOf (person. getAge (); Log. I ("doWithService", "getPersonAll:" + iMyService. getPersonAll ("Map", person) ;}@ Override public boolean onCreateOptionsMenu (Menu menu) {getMenuInflater (). inflate (R. menu. main, menu); return true ;}@ Override public boolean onOptionsItemSelected (MenuItem item) {intid = item. getItemId (); if (id = R. id. action_settings) {return true;} return super. onOptionsItemSelected (item );}}

 

BindService (new Intent (ACTION_TAG), serviceConnection, Context. BIND_AUTO_CREATE); is used to bind the Service.

In onServiceConnected, obtain the instance through iMyService = IMyService. Stub. asInterface (service); and then call related services through the Service.

When the client executes the bindService and successfully binds the service, it calls back the onServiceConnected () of the mConnection and returns the communication interface IBinder of the server. This IBinder is the IBinder returned when the service onBind, for more information, see mAIDLService. java.

On onServiceConnected (), the client successfully obtains the server-side communication interface, which is actually a local proxy object. This object exists in the client process space and the client only interacts with the proxy object, real IPC communication is the communication between the local proxy object and the server.


Note: bindService is implemented asynchronously. Binding takes some time. You cannot perform iMyService operations immediately after bindService. iMyService is still empty because it may be too late to bind.

The interaction process is as follows:

1. The client obtains the Service handle (local proxy object) by binding the service );

2. The client executes onClick () and calls the get () function of the local proxy object. The local proxy object calls mRemote. transact () to send a remote call request;

3. The server responds to onTransact () and executes this. get () and returns the execution result;

 

Because the client only communicates with the local proxy object, that is, the Service handle, and the proxy object performs real IPC operations, the IPC process is transparent to the client, call a remote operation is the same as calling a local operation. When the client calls transact (), it will write the service description dashes into the data, and it will verify when the client onTransact. If the two are different, it cannot communicate. Dashes are automatically generated based on the mInterface package name and interface name, which is why the aidl files in the two projects are in the same package.

In this process, aidl serves as a bridge and stipulates that the communication interfaces between the client and the server are unified, so that the client and the server can successfully communicate.

The specific communication process of transact and onTransact is the process of using Binder to drive communication.


 

 

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.