preface

Having recently finished the New Year, I decided to tidy up my Android knowledge.

Android Skill Book Series:

Android Basics

Android Skill Tree – Animation summary

Android Skill Tree – View summary

Android Skill Tree – Activity summary

Android Skill Tree – View event system summary

Android Skill Tree – Summary of Android storage paths and I/O operations

Android Skill Tree – Multi-process related summary

Android skill Tree – Drawable summary

Android Skill Tree – Fragment overview

Basic knowledge of data structures

Android Skill Tree – Array, linked list, hash table basic summary

Android Skill Tree — Basic Knowledge of The Tree

Basic knowledge of algorithms

Android Skill Tree – Sorting algorithm basics summary

This is about Android storage path and IO basic operations. Because we often have this convenience requirement during development. I may have written very little of the content of this article. Don’t make fun. O ( ̄)  ̄) O

Without further ado, let’s go to the brain map:

Multi-process summary brain map download

Multiple processes

Processes and threads

Sometimes when I interview people, I will ask them what is multi-process and how to start multi-process, and they will say new Thread. So a lot of people confuse multithreading with multithreading. Let me make a brief explanation: generally speaking, we start an APP, which is a process, and then there are many threads in the APP, the most familiar is our usual main thread (UI) thread. So a process contains threads.

Of course, I’m talking about the more general: can look at other similar article introduction: Android- processes and threads

Enabling Multiple Processes

It’s easy to start multiple processes. Just add Android: Process to the four components of Androidmanifest.xml. It will now run in the process with the name you defined.

Problems after multiple processes are enabled

Simply put, there will be synchronization problems. We just said that when you start an APP, you create a process, and then everything is in that process. You define android: Process for an Activity. It’s running in a different process. At this point, the Application will be recreated again, in the new process. The Activity will also be in the new process. And some of the entity class objects we created are also copies of objects created by different processes. Unrelated.

So we know something about thread synchronization. The singleton pattern is invalid because the object is copied from process to process, and the lock object of the synchronized lock is not the same object. Of course the thread synchronization mechanism fails.

SharePreferences is a file and is not affected by multiple processes. However, because SharePreferences does not support multiple processes to perform write operations at the same time, data loss may occur. Even concurrent reading and writing can be problematic. But if you just have one process writing and one process reading, and not all at the same time, that’s not a problem.

Interprocess communication

Since we are talking about multiple processes, what if we now have two processes communicating with each other? Before we talk about how to communicate, we can look at the basics of serialization and deserialization.

Let’s look at serialization:

Serialization is Serialzable and Parcelable.

It’s very simple at the time. The following is written to outline the use of these two.

Serialzable

User.java (Entity class to be passed)

public class User implements Serializable { private static final long serialVersionUID = 512345678910L; public int userId; public String userName; public boolean isMale; public User(int userId, String userName, boolean isMale) { this.userId = userId; this.userName = userName; this.isMale = isMale; }}Copy the code

We simply implement our class directly into the Serializable interface. Very simple. I’ll mention the serialVersionUID here. Because we don’t usually write that. Also normal use. For example, if I serialized the User object with ObjectOutputStream and wrote it to a local file, I changed the property of the User object. For example, I added a public Boolean haha; And then read it through ObjectInputStream and it throws an exception. Since deserialization is compared to the serialVersionUID of the serialization, if it is different, it will not be deserialized, and an exception will be thrown. But instead of writing this value manually, it will hash the value based on the current class structure. So when we change the structure of the class, deserialization will report an error.

Parcelable

public class User implements Parcelable {

    public int userId;
    public String userName;
    public boolean isMale;


    public User(int userId, String userName, boolean isMale) {
        this.userId = userId;
        this.userName = userName;
        this.isMale = isMale;
    }

    protected User(Parcel in) {

        userId = in.readInt();
        userName = in.readString();
        isMale = in.readInt() == 1;
    }

    public static final Creator<User> CREATOR = new Creator<User>() {
        @Override
        public User createFromParcel(Parcel in) {
            return new User(in);
        }

        @Override
        public User[] newArray(int size) {
            returnnew User[size]; }}; @Override public intdescribeContents() {
        return0; } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeInt(userId); dest.writeString(userName); dest.writeInt(isMale ? 1:0); }}Copy the code

You write a class to implement Parcelable AS will automatically prompt, you can follow his prompt to generate the corresponding code. Here are just a few things to note:

1. We always instantiate the class as an object before serializing it, and then assign the corresponding contents to it, so in the above code, I write a constructor:

public User(int userId, String userName, boolean isMale) {
        this.userId = userId;
        this.userName = userName;
        this.isMale = isMale;
}
Copy the code

New User(10,”dyp”,true) (of course you can also use setXXX method to set this)

2. We’re serializing. We’re writing all the values of our classes to a Parcel, just like we’re taking a book and writing them down line by line and retrieving them line by line later. So we see that. We recorded them in order first, so we need to retrieve the corresponding values in order when restoring them later. So order is important.

@override public void writeToParcel(Parcel dest, int flags) {writeInt dest.writeInt(userId); WriteString dest.writeString(userName); /* Write isMale because it is Boolean, but there is no writeBoolean, only writeBooleanArray, so we use writeInt(), 1 istrue, zero isfalse. Plus, writeBooleanArray actually uses writeInt internally. */ dest.writeInt(isMale ? 1:0); }Copy the code

3. We ended up sending to another process to retrieve our object from the Parcel, definitely by creating a new User object and reassigning the various values we saved in the second step.

public static final Creator<User> CREATOR = new Creator<User>() {
        @Override
        public User createFromParcel(Parcel inCall () {// Call (Parcel); // Call (Parcel);return new User(in);
        }

        @Override
        public User[] newArray(int size) {
            returnnew User[size]; }};Copy the code
protected User(Parcel in) {// Then we regenerate the object, and then assign the attributes of the object, remember to read the assignment in the same order as above. userId = in.readInt(); userName = in.readString(); isMale = in.readInt() == 1; }Copy the code

Binder

The basics of serialization are covered. Binder, actually Binder, I don’t know how to say Binder, just post the other guy’s articles.

Android Binder cross-process communication

Android Binder application layer summary and analysis

And here in particular:

Interprocess communication mode

So we can look at the implementation of inter-process communication in detail.

Use the Bundle

Actually, we use this a lot,

Let me write a Demo so you can see.

MainActivity.java

User user = new User(10,"dongyaoping".true);
Intent intent = new Intent(MainActivity.this,MyService.class);
Bundle bundle = new Bundle();
bundle.putSerializable("data",user);
bundle.putInt("int", 10); bundle.putString("string"."haha");
intent.putExtras(bundle);
startService(intent);
Copy the code

Myservice.java (remember to set the Android: Process attribute in androidmanifest.xml to make it in a different process)

public class MyService extends Service{

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {

        User user = (User) intent.getExtras().getSerializable("data");
        Log.v("dyp"."user:"+user.toString());
        returnsuper.onStartCommand(intent, flags, startId); }}Copy the code

So we see that bundles can put a lot of stuff in, because the Bundle itself implements Parcelable

public final class Bundle extends BaseBundle implements Cloneable, Parcelable {}
Copy the code

Using File Sharing

This is actually a little bit easier. All we need to do is write the data to a file and read it in another process.

To fetch and write in a process:

User user = new User(100,"dyp".true);
try {
     ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(path));
     out.writeObject(user);
     out.close();
} catch (Exception e) {
     e.printStackTrace();
}
Copy the code

Fetch from another process:

try {
     ObjectInputStream inputStream = new ObjectInputStream(new FileInputStream(path));
     User user = (User ) inputStream.readObject();                   
} catch (Exception e) {
     e.printStackTrace();
}
Copy the code

Use the Socket

Directly affixed to the big guy’s article:

Android: This is a very detailed Socket usage walkthrough

The use of Binder

  1. AIDL
  2. Messenger
  3. ContentProvider

We’ll focus on AIDL because Messenger is an AIDL wrapper and is easier to use. AIDL will. Messenger will be used. There are more tutorials for ContentProvider. To be honest, contentProviders are rarely used among the four major components. So I’m not going to write it down, there are a lot of tutorials online.

ContentProvider tutorial:

Android: All about ContentProvider knowledge here!

Post another Messenger tutorial:

Android Advanced 10: Using and parsing Messenger for process communication

Let’s focus on the implementation of AIDL:

You can look at the brain map and I won’t go into the details.

We can see that when the client accesses the server across processes, we have five steps.

Step 1: Create an AIDL file.

One thing we have to be careful about here. To create AIDL in AS, right-click > New > AIDL. It’s going to be under this directory.

At this point, we’ll see something like this.

interface IMyAidlInterface { String getInfor(String s); String getName(char name); // Pass objects. String getBook(in Book book);

}

Copy the code

If we were passing a Book object, book.java would be in the Java package, so we would also create an aiDL file with the same name as the object in the aiDL folder. So it became this:

It is important to remember, however, that the entire book.java and book.aidl package name should be the same. Otherwise, you will be prompted to find the Book class.

Step 2: Declare an IBinder interface instance (or generate it based on AIDL).

Then after we build, AS will automatically generate an IBinder file based on the AIDL we wrote. (Of course, if you don’t write AIDL first, you can write an IBinder file yourself.)

Step 3: Implement ServiceConnection
final ServiceConnection connection = new ServiceConnection() {
      @Override
      public void onServiceConnected(ComponentName name, IBinder service) {
         
      }

      @Override
      public void onServiceDisconnected(ComponentName name) {
         
      }
};
Copy the code
Step 4: Call context.bindService () to pass in your ServiceConnection implementation.
Intent intent = new Intent(MainActivity.this, MyService.class);
bindService(intent, connection, Context.BIND_AUTO_CREATE);
Copy the code
Step 5: Implement it in your onServiceConnected() implementation

In your onServiceConnected() implementation, you will receive an IBinder instance (called Service). Call YourInterfaceName. Stub. AsInterface ((IBinder) service), to the types of parameters can be converted into YourInterface will return.

final ServiceConnection connection = new ServiceConnection() {
      @Override
      public void onServiceConnected(ComponentName name, IBinder service) {
          Log.v("dyp"."It's already connected.");
          IMyAidlInterface iMyAidlInterface = IMyAidlInterface.Stub.asInterface(service);
          try {
              String haha = iMyAidlInterface.getInfor("Hello, I'm the activity");
              Log.v("dyp"."Received string from Service :" + haha);
          } catch (RemoteException e) {
              e.printStackTrace();
          }
      }

      @Override
      public void onServiceDisconnected(ComponentName name) {
           Log.v("dyp"."Disconnected."); }};Copy the code
Step 1 on the server side: instantiate the YourInterfaceName.Stub object
private IBinder binder = new IMyAidlInterface.Stub() {
        @Override
        public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {

        }

        @Override
        public String getInfor(String s) throws RemoteException {
            Log.v("dyp"."Received the Activity string:"+s);
            return "String passed by service";
        }

        @Override
        public String getBook(Book book) throws RemoteException {
            return null;
        }

        @Override
        public String getName(char name) throws RemoteException {
            returnnull; }};Copy the code

Server step 2: return the object generated above in the onBind method

@Nullable
@Override
public IBinder onBind(Intent intent) {
    return binder;
}
Copy the code

Comparison of various communication methods

Copy other people’s pictures directly:

At the end

I still don’t know what to say. Just give me a little squirt…