Generally speaking, the AIDL technology is not very commonly used in our application development process. Although Sina Weibo provides SSO login, its principle is to use AIDL. This article describes the principles and implementation methods of AIDL in a complete example form.
AIDL (AndRoid interface description language) is an excuse description language; the compiler can generate a piece of code through an aidl file to achieve the purpose of communicating internal processes between two processes through a predefined interface. If you need to access an object in another Service in one Activity, you need to first convert the object into parameters that AIDL recognizes (maybe multiple parameters), and then use AIDL to pass these parameters. At the receiving end of the message, use these parameters to assemble the object you need..
To put it bluntly, AIDL is to define an interface. The client (the caller) connects to the remote server resume through bindService. When the connection is established, an IBinder object will be returned. The object is the BinderProxy of the server Binder. When establishing a connection, the client wraps the BinderProxy object in the local Proxy through the asInterface function, and assigns the BinderProxy object of the remote server to the mRemote field of the Proxy class, which is to execute the remote method call through mRemote. If you need to have a deeper understanding of the Binder mechanism, please refer to Lao Luo’s Android system inter-process communication Binder mechanism’s Java interface source code analysis at the application framework level. Let's look at an AIDL instance.
AIDL interface statement
Create a package in the src directory, and then create a file under the package. Note that the file is created instead of the class or interface type. Declare the interface in the following example:
package ; interface ILogin { String login(); }
Note that the interface and method declaration do not use public, and adding the method to public will prompt an error. After writing, if eclipse enables automatic compilation, a class will be generated under gen/, and the content is roughly as follows:
package ; public interface ILogin extends { /** Local-side IPC implementation stub class. */ public static abstract class Stub extends implements { private static final DESCRIPTOR = ""; /** Construct the stub at attach it to the interface. */ public Stub() { (this, DESCRIPTOR); } /** * Cast an IBinder object into an * interface, generating a proxy if needed. */ public static asInterface( obj) { if ((obj == null)) { return null; } iin = (DESCRIPTOR); if (((iin != null) && (iin instanceof ))) { return (() iin); } return new (obj); } @Override public asBinder() { return this; } @Override public boolean onTransact(int code, data, reply, int flags) throws { switch (code) { case INTERFACE_TRANSACTION: { (DESCRIPTOR); return true; } case TRANSACTION_login: { // 1. Login request, the execution of (); (DESCRIPTOR); _result = (); (); (_result); return true; } } return (code, data, reply, flags); } private static class Proxy implements { private mRemote; Proxy( remote) { mRemote = remote; } @Override public asBinder() { return mRemote; } public getInterfaceDescriptor() { return DESCRIPTOR; } @Override public login() throws // 2. Login in Proxy, implement IPC through the Binder mechanism { _data = (); _reply = (); _result; try { _data.writeInterfaceToken(DESCRIPTOR); (Stub.TRANSACTION_login, _data, _reply, 0); _reply.readException(); _result = _reply.readString(); } finally { _reply.recycle(); _data.recycle(); } return _result; } } static final int TRANSACTION_login = (.FIRST_CALL_TRANSACTION + 0); } public login() throws ; }
It can be seen that the ILogin interface is automatically generated in this class, and another login() function in this interface. But the most important thing is that a Stub class is generated, which integrates a sub-Binder class and implements the ILogin interface. The most important thing in Stub is the function asInterface(). In this function, the type of obj parameter will be judged. If the obj is a local interface similar, it is considered not an IPC and the obj will be converted to ILogin type; otherwise, obj will be wrapped by another internal class Proxy that is automatically generated and assigned to the mRemote property in Proxy. The Proxy class also implements the ILogin interface. In the login() function, Proxy will pass requests and data to the server through the Binder mechanism, such as Comment 2 in the above code. This is the client's work.
Server AIDL interface
The server also needs to create an aidl file with the same name under the same package. We can directly copy the client's package to the server. If a custom type is used, the custom type needs to be available on the client and server. After copying Aidl, the corresponding file will be generated in the gen in the server program, and the content will be the same as that of the client. The key point here is to look at the onTransact function, that is, at comment 1 in the above code. You can see that the() function is executed at case TRANSACTION_login, which means that when the client receives the TRANSACTION_login request, the() function is executed. Through the client's analysis, we know that when we call login(), we actually submit a TRANSACTION_login request to the server through mRemote. Therefore, the two ends are connected through the Binder mechanism. We can simply understand it as the C/S mode.
The server is not finished yet. The most important step is to establish a service, and the content is roughly as follows:
/** * AIDL server interface, LoginStubImpl implements ILogin interface. * * @author mrsimple */ public class LoginService extends Service { /** * */ IBinder mBinder = new LoginStubImpl(); /** * @author mrsimple */ class LoginStubImpl extends Stub { @Override public String login() throws RemoteException { return "This is from" + ().getName() + "Returned string"; } } /* * Returns the Binder instance, that is, the subclass of Stub that implements the ILogin interface, here is LoginStubImpl * [url=?mod=space&uid=133757]@see[/url] #onBind() */ @Override public IBinder onBind(Intent intent) { return mBinder; } }
We hereby named the Service LoginService, inherited from Service, and then create an internal class named LoginServiceImpl. This class inherits from the automatically generated Stub, and then implements the login() method. Declare an IBinder field mBinder in LoginService:
IBinder mBinder = new LoginStubImpl();
And return the mBinder object in the onBind function of LoginService. That is, when the client establishes a connection with the server, the onBind method will be called to return the mBinder object. The object IBinder obtained in the onServiceConnected function of the ServiceConnection class of the client is the mBinder object in the LoginService wrapped by BinderProxy. Therefore, the() function called in onTransact on the server is actually the login() function called in LoginStubImpl.
Register LoginService in the server program as follows:
<!-- aidl server service --> <service android:name="" > <intent-filter> <action android:name="" /> </intent-filter> </service>
Client connection
Add the following code to the Activity:
ServiceConnection mLoginConnection = new ServiceConnection() { @Override public void onServiceDisconnected(ComponentName name) { ("", "### aidl disconnected."); } @Override public void onServiceConnected(ComponentName name, IBinder service) { ("", "### aidl onServiceConnected. service : " + ().getName()); ILogin login = (service); ("", "### after asInterface : " + ().getName()); try { ("", "### login : " + ()); // (, "onServiceConnected : " + // (), // Toast.LENGTH_SHORT).show(); } catch (RemoteException e) { (); } } }; @Override protected void onResume() { (); // Server side action Intent aidlIntent = new Intent(""); bindService(aidlIntent, mLoginConnection, Context.BIND_AUTO_CREATE); } @Override protected void onStop() { (); // unbind unbindService(mLoginConnection); }
run
First run the server program, and then start the client program, you can see that the client outputs the following Log:
09-02 10:40:54.662: D/(9589): ### aidl onServiceConnected. service : 09-02 10:40:54.662: D/(9589): ### after asInterface : $Stub$Proxy 09-02 10:40:54.662: D/(9589): ### login : This is the string returned from $LoginStubImpl
You can see that the service object in onServiceConnected(ComponentName name, IBinder service) is of BinderProxy type, and is wrapped into Proxy type after being converted asInterface. However, when called, the login() function in the server LoginStubImpl is executed. Therefore, the LoginStubImpl instance mBinder is wrapped in BinderProxy type by the server, and then wrapped in Proxy on the client, and data transmission is carried out through the Binder mechanism to realize IPC.
I hope that the description in this article will be helpful for you to further understand Android programming.