Multiprocess in Android
Why use multi-process
Multiprocess can avoid the method limitation of 65535, and because Android system has memory size limitation for each individual App application, it can increase the available memory through a multi-process approach of App.
Open multi-process
Opening multiple processes in Android is simple, but there are many things to consider when multiple processes are opened, including communication between processes, usage scenarios for creating and destroying processes, and unexpected errors after opening multiple processes.
<!--Main process-->
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<!--Open multiple processes, pass process Property to specify the process name-->
<activity
android:name=".Main2Activity"
android:process=":remote">
</activity>
The drawbacks of multi-process initiation
First, the singleton pattern and static members fail completely after using multiple processes
Thread Synchronization Failure
Shared Preference is less reliable because concurrent reading and writing of XML files can be problematic
Application s are created many times
Multiprocess Communication in Android
Android provides a variety of interprocess communication methods:
Using Bundle
Using shared files
Using Messenger
Use ContentProvider
Using Socket
Using Binder (AIDL)
Using Bundle
Because Bundle implements the Parcelable interface, it can transfer some data that can be wrapped between different processes, but there is no interaction, that is to say, it can only transfer the incoming data in one way when starting another process.
Using file sharing
Two files can exchange data by reading and writing the same shared file, which can achieve interactivity. However, because multiple processes in Android can not synchronize the reading and writing of files, this cross-process communication will lead to reading and writing errors.
Using Messenger
Messenger is a lightweight IPC mechanism implemented by Android. It can transmit some lightweight data Message objects. The actual underlying implementation is Binder. It only encapsulates AIDL to make it easier to use. It also handles message objects serially, so there is no concurrency problem.
Server-side code
public class MessengerService extends Service {
private static final String TAG = "MessengerService";
//Declare Messenger on the Service Side
private final Messenger mMessenger = new Messenger(new MessageHandler());
/**
* Construct a Handler for processing messages on the Service side
*/
private static class MessageHandler extends Handler {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case Contast.MSG_FROM_CLIENT:
Log.i(TAG, "handleMessage: "+msg.getData().getString(Contast.MSG_CONTENT));
break;
default:
super.handleMessage(msg);
}
}
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
//Return Binder from it
return mMessenger.getBinder();
}
}
Client Code
public class Main2Activity extends AppCompatActivity {
private Messenger mMessenger;
private ServiceConnection mServiceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mMessenger = new Messenger(service);
//Construct Message for Sending
Message message = Message.obtain(null, Contast.MSG_FROM_CLIENT);
Bundle data = new Bundle();
data.putString(Contast.MSG_CONTENT,"This is the message from the client.");
message.setData(data);
try {
mMessenger.send(message);
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
mMessenger = null;
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
}
public void serviceStart(View view){
//Start the Server Service
Intent intent = new Intent(this, MessengerService.class);
bindService(intent, mServiceConnection, BIND_AUTO_CREATE);
}
@Override
protected void onDestroy() {
//Unbind
unbindService(mServiceConnection);
super.onDestroy();
}
}
Use ContentProvider
ContentProvider is originally suitable for inter-process communication, and its underlying implementation is also the Binder mechanism. ContentProvider mainly defines some excuses for external applications to access this application, defines access interfaces through ContentProvider, and accesses data through ContentResolver.
Custom Implementation ContentProvider
/**
* Customized Content Provider to Realize Addition, Deletion and Change Checking Method
*/
public class PipContentProvider extends ContentProvider {
@Override
public boolean onCreate() {
return false;
}
@Nullable
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
return null;
}
@Nullable
@Override
public String getType(Uri uri) {
return null;
}
@Nullable
@Override
public Uri insert(Uri uri, ContentValues values) {
return null;
}
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
return 0;
}
@Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
return 0;
}
}
Register a custom ContentProvider
<provider
<!--Declare that you want to visit theContentProviderRequired permissions-->
android:permission="com.wei.piechart.PROVIDER"
<!--ContentProvider Unique ID-->
android:authorities="com.wei.piechart.PipContentProvider"
<!--Declaring to be registered ContentProvider-->
android:name=".PipContentProvider"
android:process=":provider"/>
Accessing the specified ContentProvider through ContentResolver and Uri in the program
//Get ContentResolver
ContentResolver contentResolver = getContentResolver();
//Specify the object to be accessed through Uri
Uri uri = Uri.parse("content:com.wei.piechart.PipContentProvider");
//Similar to the SQL database, query operations can be performed, and the results are placed in the Cursor result set.
Cursor cursor = contentResolver.query(uri, null, null, null, null);
Using Socket
Socket socket book is a way of network communication, but it can also be used for two processes in the local machine by using port number.
Socket is divided into Service Socket and Socket, one for the server, one for the client, and Bluetooth through the Socket interaction principle is the same.
Using Binder (AIDL)
To be precise, AIDL is not an IPC mechanism, but an AIDL (Android Interface Definition Language) Android Interface Definition Language, through which we can easily create an IPC model for communication through Binder. In fact, Binder is Android's most mainstream way of inter-process communication. It is also the underlying implementation principle of some mechanisms in front of us. AIDL just gives us a convenient way to implement Binder mechanism.
Read this article about the Binder mechanism in Android Detailed explanation of Android Binder mechanism
Usage restriction
Type restriction
First of all, not all data types can be used in AIDL files. The following types can be used in AIDL files:
Basic data type (int long... ).
String and CharSequence
List: Only ArrayList is supported, and the elements in the List must be able to be supported by AIDL
Map: Only HashMap is supported, and the elements in the Map must be able to be supported by AIDL
Parcelable: All objects that implement the Parcelable interface
AIDL: All AIDL interfaces themselves can also be used in AIDL files
Type declaration restrictions
In addition to basic types, all types need to be directed, input type parameters are represented by in, output type parameters are represented by out, and input and output type parameters are represented by in out.
Explicit import s are required for custom arcelable and AIDL types used
Technological process
Define AIDL interface
Book.aidl
// Book.aidl
package com.wei.piechart;
// Declare any non-default types here with import statements
parcelable Book;
IBookManager.aidl
// IBookManager.aidl
package com.wei.piechart;
// Declare any non-default types here with import statements
import com.wei.piechart.Book;
interface IBookManager {
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
double aDouble, String aString);
List<Book> getBookList();
void addBook(in Book book);
}
Book.java
public class Book implements Parcelable{
int id;
String name;
protected Book(Parcel in) {
id = in.readInt();
name = in.readString();
}
public static final Creator<Book> CREATOR = new Creator<Book>() {
@Override
public Book createFromParcel(Parcel in) {
return new Book(in);
}
@Override
public Book[] newArray(int size) {
return new Book[size];
}
};
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(id);
dest.writeString(name);
}
}
Generate IBookManager.java
After defining the interface and rebuilding the project, AS automatically generates the IBookManager.java class. This is the main function of AIDL. By defining the required fields and methods in the Aidl file, the class that implements Binder can be quickly generated.
Implementing Server
public class BookManagerService extends Service{
private static final String TAG = "BookManagerService";
//A list of books on the Service side, supporting multiple processes
private CopyOnWriteArrayList<Book> mBookList = new CopyOnWriteArrayList<>();
//Binder for returning to the client
private Binder mBinder = new IBookManager.Stub(){
@Override
public List<Book> getBookList() throws RemoteException {
return mBookList;
}
@Override
public void addBook(Book book) throws RemoteException {
if(!mBookList.contains(book)){
mBookList.add(book);
}
}
};
@Nullable
@Override
public IBinder onBind(Intent intent) {
//Return the Binder created by the server to the client
return mBinder;
}
}
Implementing Client
//Declare Service Connection
private ServiceConnection mServiceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
//Converting the Binder returned from the server into interface usage on the client side
IBookManager bookManager = IBookManager.Stub.asInterface(service);
try {
bookManager.addBook(new Book(1, "First book"));
List<Book> books = bookManager.getBookList();
Log.i(TAG, "onServiceConnected: "+books.toString());
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
public void serviceStart(View view) {
//Start the Server Service
Intent intent = new Intent(this, BookManagerService.class);
bindService(intent, mServiceConnection, BIND_AUTO_CREATE);
}