AIDL Interprocess Communication

Keywords: Android Java

1. Create a Service-side project:
1. Create a new aidl file, the system will create a folder of aidl by default after creation. There is a default method in the aidl file that can be deleted.Change to an aidl file that declares the Parcelable data type.

2. Create a class, Book.java, that contains only the Name property and implements the Parcelable interface.

public class Book implements Parcelable {
private String name;
public Book(){
}
public Book(String name){
    this.name = name;
}

public String getName() {
    return name;
}

public void setName(String name) {
    this.name = name;
}

@Override
public String toString() {
    return "book name: " + name;
}

@Override
public int describeContents() {
    return 0;
}

@Override
public void writeToParcel(Parcel parcel, int i) {
    parcel.writeString(this.name);
}

public void readFromParcel(Parcel parcel){
    parcel.readString();
}

protected Book(Parcel parcel){
    this.name = parcel.readString();
}
public static final Creator<Book> CREATOR = new Creator<Book>() {
    @Override
    public Book createFromParcel(Parcel parcel) {
        return new Book(parcel);
    }

    @Override
    public Book[] newArray(int i) {
        return new Book[i];
    }
};
}

3. The server needs to expose to the client a way to get a list of books and add them. The method needs to be defined in the AIDl file, create a new Aidl file, BookController.aidl file.List requires explicit imports.

// BookController.aidl
package com.text.aidlservice;
import com.text.aidlservice.Book;
interface BookController {
 List<Book> getBookList();
void addBookInOut(inout Book book);
void addBookIn(in Book book);
void addBookOut(out Book book);
}

It is not the aidl file that is really used in the interprocess communication, but the file that the system generates from it, and then the internal static abstract class Stub is used.

4. Create a Service to supply the client with a remote binding.

public class AIDLService extends Service {
private String TAG = "Service";
private List<Book> bookList;
public AIDLService(){

}

@Override
public void onCreate() {
    super.onCreate();
    bookList = new ArrayList<>();
    initData();
}

private void initData() {
    Book book1 = new Book("Murphy's Law");
    Book book2 = new Book("The Scroll Marked");
    Book book3 = new Book("Object-oriented");
    Book book4 = new Book("java");
    Book book5 = new Book("android");
    bookList.add(book1);
    bookList.add(book2);
    bookList.add(book3);
    bookList.add(book4);
    bookList.add(book5);
}
private final BookController.Stub stub = new BookController.Stub() {
    @Override
    public List<Book> getBookList() throws RemoteException {
        return bookList;
    }

    @Override
    public void addBookInOut(Book book) throws RemoteException {
        if (book != null){
            book.setName("Service Changed the name of the new book InOut");
            bookList.add(book);
        }else{
            Log.e(TAG,"Received null object InOut");
        }
    }

    @Override
    public void addBookIn(Book book) throws RemoteException {
        if (book != null) {
            book.setName("The server changed the name of the new book IN");
            bookList.add(book);
        }else{
            Log.e(TAG,"Received null object In");
        }
    }

    @Override
    public void addBookOut(Book book) throws RemoteException {
        if (book != null) {
            Log.e(TAG,"The name of the book from the client:" + book.getName());
            book.setName("The name of the new book from the server Out");
            bookList.add(book);
        }else{
            Log.e(TAG,"Received null object out");
        }
    }
};

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    Log.e(TAG,"onStartCommand");
    return super.onStartCommand(intent, flags, startId);
}

@Nullable
@Override
public IBinder onBind(Intent intent) {
    return stub;
}
}

The service side needs to be remotely bound by the client, and the service can be bound by specifying the package name first, then by configuring the Action value or directly specifying the Service class name.Use the Configuration Action scenario.

<service android:name=".AIDLService"
        android:enabled="true"
        android:exported="true">
        <intent-filter>
            <action android:name="com.text.aidlservice.action" />
            <category android:name="android.intent.category.DEFAULT" />
        </intent-filter>
    </service> 

2. Create a Client project:
1, first copy the aidl file from the server to the same level of java folder without any code changes.
2. You need to create the same package name as the service-side Book class to hold the Book class.Copy Service-side Book.java to Client
3. Modify the layout file and add two Button s.
4. Modify the mainActivity file.

class MainActivity extends AppCompatActivity {
private final String TAG = "Client";
private BookController bookController;
private boolean connected;
private List<Book> bookList;
private ServiceConnection serviceConnection = new ServiceConnection() {
    @Override
    public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
        Log.d(TAG,"onServiceConnected");
        bookController = BookController.Stub.asInterface(iBinder);
        connected = true;
    }

    @Override
    public void onServiceDisconnected(ComponentName componentName) {
        connected = false;
    }
};

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    bindService();
    Log.d(TAG,"onCreate");
    findViewById(R.id.btn1).setOnClickListener(clickListener);
    findViewById(R.id.btn2).setOnClickListener(clickListener);
    findViewById(R.id.btn3).setOnClickListener(clickListener);
    findViewById(R.id.btn4).setOnClickListener(clickListener);

}

private void bindService() {
    Intent intent = new Intent();
    intent.setPackage("com.text.aidlservice");
    intent.setAction("com.text.aidlservice.action");
    startService(intent);
    bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);
    Log.d(TAG,"bindService");
}

private View.OnClickListener clickListener = new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        switch (view.getId()){
            case R.id.btn1:
                Log.d(TAG, "connected = " + connected);
                if (connected){
                    try {
                        bookList = bookController.getBookList();
                    } catch (RemoteException e) {
                        e.printStackTrace();
                    }
                    Log.d(TAG, "log");
                    log();
                }
                break;
            case R.id.btn2:
                if (connected){
                    Book book = new Book("In Out");
                    try {
                        bookController.addBookInOut(book);
                        Log.e(TAG,"To the server InOut How to add a new book,name:" + book.getName());

                    } catch (RemoteException e) {
                        e.printStackTrace();
                    }
                }
                break;
            case R.id.btn3:
                if (connected){
                    Book book = new Book("In");
                    try {
                        bookController.addBookIn(book);
                        Log.e(TAG,"To the server In How to add a new book,name:" + book.getName());

                    } catch (RemoteException e) {
                        e.printStackTrace();
                    }
                }
                break;
            case R.id.btn4:
                if (connected){
                    Book book = new Book("Out");
                    try {
                        bookController.addBookOut(book);
                        Log.e(TAG,"To the server Out How to add a new book,name:" + book.getName());

                    } catch (RemoteException e) {
                        e.printStackTrace();
                    }
                }
                break;
        }
    }
};

@Override
protected void onDestroy() {
    super.onDestroy();
    if (connected){
        unbindService(serviceConnection);
    }
}

private void log(){
    for (Book book: bookList){
        Log.d(TAG, book.toString());
    }
}
}

3. Two ways of starting services
1.startService: Start the service by calling startservice() to run indefinitely.OnCreate->onStartCommand()->onDestory().
Once started, the service can run indefinitely in the background, even if the component that started the service has been destroyed.
The service started with usually performs a single operation and does not return the results to the caller.
startService(intent);
2. Binding: bindService() is bound to a service.OnCreate->onBind()->onDestory
Provides a client-server interface that allows components to interact with services, send requests, get results, and even perform these operations across processes using interprocess communication (IPC).
bindService(intent,ServiceConnection,BIND_AUTO_CREATE);

Posted by JonnyThunder on Wed, 28 Aug 2019 19:46:30 -0700