📜 ⬆️ ⬇️

AIDL (Android Interface Definition Language) and Inter-Process Communication (IPC)

In this article we will try to describe your experience with AIDL in Android IPC.
It contains an example of an application with a service that is running in a separate process.

The article should be considered as:

Basic concepts


Service is a component of an Android application without a user interface that is designed for demanding and / or long-running operations.

Types of Android services


The service can be launched in a separate process from the Activity.
')
Benefits:

Disadvantages:

AIDL

Literally translated - the language of the description of the interfaces Android. It is used to describe the composition and decomposition of Java objects into OS primitives for direct transfer between processes.
AIDL files are very similar to standard interfaces in java except for:

Using AIDL, java code is automatically generated to generate stabs.

Application architecture


The application we developed is an Android gallery that allows you to view photos from a memory card and photo-sharing networks.
The main tasks of the service in this application are: obtaining metadata (information about albums, photos, friends), monitoring their updates and everything else associated with them. The service constantly stores up-to-date information and is ready at any moment to give away its main Activity for display.
Below are the key sections of the code and the process of creating a primitive service is described:
The following AIDL files are used to communicate between the service and the Activity:

IDataSourceService.aidl - service interface:
packagecom.umobisoft.habr.aidlexample.common; import com.umobisoft.habr.aidlexample.common.IDataSourceServiceListener; interfaceIDataSourceService{ voidloadAlbums(in IDataSourceServiceListener listener); … } 


IDataSourceServiceListener.aidl - interface of message listeners from the service:
  package com.umobisoft.habr.aidlexample.common; import com.umobisoft.habr.aidlexample.common.pojo.Album; interface IDataSourceServiceListener{ oneway void albumItemLoaded(in Album a); } 


The data is transferred using two classes that implement the Parcelable interface - Album and Photo. The declaration of aidl files for these classes is required. When converting from OS primitives to java Objects, the Creator class is used.
To write data, use the Parcelable interface's writeToParcel method:
  @Override public void writeToParcel(Parcel out, int flags) { try{ out.writeLong(id); out.writeString(name); out.writeTypedList(photos); }catch (Exception e) { Log.e(TAG, "writeToParcel", e); } } 


There is also a describeContents helper method, its task is to describe special cases / states of an object that can be used during serialization and descripting:

  @Override public int describeContents() { // TODO Auto-generated method stub return 0; } 


Data reading methods turned out to be unworthy of putting them into the Parcelable interface, but the standard practice is to use Creator along with:

  private void readFromParcel(Parcel in) { try{ id = in.readLong(); name = in.readString(); photos.clear(); in.readTypedList(photos, Photo.CREATOR); }catch (Exception e) { Log.e(TAG, "readFromParcel", e); } } 


Activity starts the service (making it thus StartedService) in the onCreate method

 @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); textView = (TextView)findViewById(R.id.album_text); Intent serviceIntent = newIntent(this, DataSourceService.class); startService(serviceIntent); connectToService(); } 


At the same stage of the life cycle, it connects to the service:

  private void connectToService() { Intent intent = newIntent(this, DataSourceService.class); this.bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE); } 


The process of connecting to the service is asynchronous, it is affected by the implementation of the ServiceConnection interface. During the connection with the server, the Activity is registered in the service as a message listener using the implementation of IDataSourceServiceListener.Stub:

  private ServiceConnection serviceConnection = newServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { Log.i(TAG, "Service connection established"); serviceApi = IDataSourceService.Stub.asInterface(service); try { mainListener = newIDataSourceServiceListener.Stub() { @Override publicvoidalbumItemLoaded(final Album a) throwsRemoteException { mToastHandler.post(new Thread(){ publicvoid run(){ Toast.makeText(HabrahabrAIDLExampleActivity.this, a.toString(), Toast.LENGTH_LONG).show(); textView.setText(a.toString()); } }); } }; serviceApi.loadAlbums(mainListener); } catch (RemoteException e) { Log.e(TAG, "loadAlbums", e); } } @Override publicvoidonServiceDisconnected(ComponentName name) { Log.i(TAG, "Service connection closed"); serviceApi = null; connectToService(); } }; 


While StartedService is running, if the amount of free memory decreases to a certain threshold, the system can kill the service without warning. After that, the system must restart the service. Thus, in the onServiceDisconnected method, we again initialize the connection with the service.

I hope the posted source code will help developers to get acquainted with AIDL. Archive with a full example here .
The main application is available for review in the Android Market .

Official documentation on AndroidDevelopers:
Services: developer.android.com/guide/topics/fundamentals/services.html
AIDL: developer.android.com/guide/developing/tools/aidl.html

Source: https://habr.com/ru/post/139432/


All Articles