Service proficiency


Introduction to this section:

In this section, we continue to study the Service component. In this section we will learn some of the AIDL cross-process communication in Android The concept does not go deep into the source code level. Just know what it is and know how to use it! Start this section~ This section corresponds to the official document: Binder


1. First introduction to the Binder mechanism


1) What are IBinder and Binder?

Let’s see what the official documentation says:

1.png

Chinese translation:

IBinder is the basic interface of remote objects. It is the core part of the lightweight remote calling mechanism designed for high performance. But he Not only for remote calls, but also for in-process calls. This interface defines the protocol for interaction with remote objects. But don’t implement it directly This interface, insteadinherits(extends)Binder.

The main API of IBinder is transact(), and the corresponding API is Binder.onTransact(). Through the former, you can Sends calls to a remote IBinder object, which enables your remote object to respond to incoming calls. IBinder's APIs are all Syncronous executed, such as transact() until the other party's Binder.onTransact() method is called. Only later did he return. This is undoubtedly the case when the call occurs within a process, and when it is inter-process, with the help of IPC, the same effect is achieved.

The data sent through transact() is Parcel. Parcel is a general buffer. In addition to data, it also contains Some metadata describing its contents. Metadata is used to manage references to IBinder objects so that buffers can be moved from one process to another. Save these references when going to another process. This ensures that when an IBinder is written to a Parcel and sent to another process, If another process sends a reference to the same IBinder back to the original process, then the original process can receive the sent A reference to that IBinder. This mechanism enables IBinder and Binder to be managed across processes like unique identifiers.

The system maintains a thread pool for each process to store interactive threads. These interactive threads are used to dispatch all IPCs sent from other processes transfer. For example: when an IPC is sent from process A to process B, the calling thread in A (this should not be in the thread pool) is blocked. In transact(). A thread in the interactive thread pool in process B receives this call. It calls Binder.onTransact() and returns a Parcel as the result after completion. Then the waiting thread in process A Execution can continue after receiving the returned Parcel. In fact, the other process looks like a thread of the current process, But it is not created by the current process.

The Binder mechanism also supports recursive calls between processes. For example, process A executes its own IBinder's transact() call to process B Binder, and process B uses transact() in its Binder.onTransact() to initiate a call to process A, then process A While waiting for the call it issued to return, it will also respond to process B's transact() with Binder.onTransact(). In short, the result of Binder is that we feel that there is no difference between cross-process calls and intra-process calls.

When operating remote objects, you often need to check whether they are valid. There are three methods you can use:

  • 1 The transact() method will throw when the process where IBinder is located does not exist. A RemoteException exception occurred.
  • 2 If the target process does not exist, then return false when calling pingBinder().
  • 3 You can use the linkToDeath() method to register an IBinder.DeathRecipient with IBinder. Called when the process represented by IBinder exits.

PS: Chinese translation is excerpted from: Android Development: What is IBinder

##Okay, I guess you may be confused after reading this list of things In the fog, here is a brief summary:

IBinder is an interface for inter-process communication provided by Android, but we generally do not implement this interface directly, Instead, inter-process communication is achieved by inheriting the Binder class! It is a way to implement IPC (inter-process communication) in Android!


2) Brief analysis of Binder mechanism

2.png

The Binder mechanism in Android consists of a series of system components:

Client, Server, Service Manager and Binder driver

The approximate calling process is as follows. In addition, Service Manager is more complicated and will not be studied in detail here!

Process analysis:

-> When the Client calls a method in a proxy interface, the method of the proxy interface will The parameters passed by the Client are packaged into Parcel objects;
-> Then the proxy interface sends the Parcel object to the Binder driver in the kernel;;
-> Then Server will read the request data in the Binder Driver. If it is sent to itself, unpack the Parcel object. Process and return the results; PS: The methods defined in the proxy interface correspond to the methods defined in the Server. In addition, the entire calling process is synchronous, that is, while the Server is processing, the Client will be Blocked (locked)! The definition of the proxy interface mentioned here is
AIDL (Android Interface Description Language) that I will talk about later!


3) Why does Android use the Binder mechanism to achieve inter-process communication?

  1. Reliability: On mobile devices, Client-Server-based communication is usually used to achieve internal communication between the Internet and the device. Currently, Linux supports IPC including traditional pipes, System V IPC, namely message queue/shared memory/semaphore, and only socket supports Client-Server communication method. The Android system provides developers with rich functional interfaces for inter-process communication, media playback, sensors, and wireless transmission. These functions are managed by different servers. Developers only care about establishing communication between the client and server of their own application to use this service. There is no doubt that if a set of protocols are set up at the bottom to implement Client-Server communication, it will increase the complexity of the system. When implementing this complex environment on a mobile phone with limited resources, reliability is difficult to guarantee.
  2. Transmission performance: Socket is mainly used for inter-process communication across the network and inter-process communication on the local machine, but the transmission efficiency is low and the overhead is high. The message queue and pipeline adopt a store-and-forward method, that is, the data is first copied from the sender buffer area to a buffer area opened by the kernel, and then copied from the kernel buffer area to the receiver buffer area. The process involves at least two copies. Although shared memory does not require copying, the control is complicated. Compare the number of data copies of various IPC methods. Shared memory: 0 times. Binder: 1 time. Socket/Pipeline/Message Queue: 2 times.
  3. Security: Android is an open platform, so it is important to ensure application security. Android assigns a UID/PID to each installed application, and the UID of the process can be used to identify the process identity. Traditionally, the user can only fill in the UID/PID in the data packet, which is unreliable and easily exploited by malicious programs. Instead we require the kernel to add a reliable UID. Therefore, for reliability, transmission, and security. Android has established a new method of inter-process communication. ——Excerpted from:A brief understanding of the Binder mechanism in Android

Of course, as a junior developer we don’t care about the above, the Binder mechanism brings us The most direct benefit is: We don’t need to care about how to implement the underlying layer. We only need to customize an interface file according to the rules of AIDL, and then call the method in the interface to complete the two tasks. Inter-process communication!


2. Detailed explanation on the use of AIDL


1) What is AIDL?

Hey, we talked about the noun IPC earlier, its full name is: cross-process communication (interprocess communication), Because in the Android system, each application runs in its own process, data generally cannot be exchanged directly between processes. In order to achieve cross-process, Android provides us with the Binder mechanism mentioned above, and the interface language used by this mechanism is: AIDL (Android Interface Definition Language). Its syntax is very simple, and this interface Language is not really programming Language just defines the communication interface between two processes! The Java code that conforms to the communication protocol is generated by the Android SDK The aidl.exe tool is generated in the platform-tools directory, and the corresponding interface file is generated in the :gen directory, usually the interface of: Xxx.java! The interface contains an internal class of Stub, which implements the IBinder interface and the custom communication interface. This class will be used as the callback class of the remote Service - it implements the IBinder interface, so it can be used as the return value of the Service's onBind() method!


2) AIDL implements simple communication between two processes

Before starting to write the AIDL interface file, we need to understand some precautions when writing AIDL:

Notes on AIDL:

  • The interface noun needs to be the same as the aidl file name
  • Do not add access in front of the interface and method Permission modifiers : public, private, protected, etc., static final cannot be used!
  • AIDL’s default supported types include Java basic types, String, List, Map, CharSequence, all other types are An import statement is required. For using custom types as parameters or return values, the custom types need to implement the Parcelable interface. For details, please see the following section on transferring complex data types
  • Custom types and other interface types generated by AIDL should be explicitly imported in the aidl description file, even in the class and definition of packages in the same package.

In addition, if the compiler you use to write aidl is: Eclipse, please note: Don't create new file directly! In this case, the file cannot be opened and code cannot be written!
① Directly create a new txt file, save it in .aidl format after writing, and then copy it to the corresponding path
② Because aidl is similar to the interface, so directly new interface, after writing the content, come to the corresponding java file Modify the file suffix name in the directory;

If you are using Android Studio, unlike Eclipse, if you create an AIDL file like Eclipse, you will find The corresponding XXX.java file is not compiled and generated. To create AIDL under AS, you need to create a new aidl folder in the main directory and then define an For a package with the same name as the aidl package, finally create an aidl file, then press ctrl + f9 to recompile, and that’s it!

3.png

The results of successful compilation of the above two are as follows. You can find the corresponding AIDL files in the corresponding directories

4.png5.png


1. Server:

Step 1: Create AIDL file:

IPerson.aidl

package com.jay.aidl;

interface IPerson {
String queryPerson(int num);
}

Let’s open IPerson.java and take a look at the code inside:

IPerson.java

/*
 * This file is auto-generated.  DO NOT MODIFY.
 * Original file: C:\\Code\\ASCode\\AIDLServer\\app\\src\\main\\aidl\\com\\jay\\aidl\\IPerson.aidl
 */
package com.jay.aidl;
public interface IPerson extends android.os.IInterface
{
/** Local-side IPC implementation stub class. */
public static abstract class Stub extends android.os.Binder implements com.jay.aidl.IPerson
{
private static final java.lang.String DESCRIPTOR = "com.jay.aidl.IPerson";
/** Construct the stub at attach it to the interface. */
public Stub()
{
this.attachInterface(this, DESCRIPTOR);
}
/**
 * Cast an IBinder object into an com.jay.aidl.IPerson interface,
 * generating a proxy if needed.
 */
public static com.jay.aidl.IPerson asInterface(android.os.IBinder obj)
{
if ((obj==null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof com.jay.aidl.IPerson))) {
return ((com.jay.aidl.IPerson)iin);
}
return new com.jay.aidl.IPerson.Stub.Proxy(obj);
}
@Override public android.os.IBinder asBinder()
{
return this;
}
@Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
{
switch (code)
{
case INTERFACE_TRANSACTION:
{
reply.writeString(DESCRIPTOR);
return true;
}
case TRANSACTION_queryPerson:
{
data.enforceInterface(DESCRIPTOR);
int _arg0;
_arg0 = data.readInt();
java.lang.String _result = this.queryPerson(_arg0);
reply.writeNoException();
reply.writeString(_result);
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
private static class Proxy implements com.jay.aidl.IPerson
{
private android.os.IBinder mRemote;
Proxy(android.os.IBinder remote)
{
mRemote = remote;
}
@Override public android.os.IBinder asBinder()
{
return mRemote;
}
public java.lang.String getInterfaceDescriptor()
{
return DESCRIPTOR;
}
@Override public java.lang.String queryPerson(int num) throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
java.lang.String _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeInt(num);
mRemote.transact(Stub.TRANSACTION_queryPerson, _data, _reply, 0);
_reply.readException();
_result = _reply.readString();
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
}
static final int TRANSACTION_queryPerson = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
}
public java.lang.String queryPerson(int num) throws android.os.RemoteException;
}

Here we only focus on **asInterface(IBinder)** and the **queryPerson()** method in the interface we defined!

This method will convert the IBinder type object into the IPerson type , generate a proxy object to return the result if necessary!

We can skip the others without reading them and proceed to the next step.

Step 2: **Customize our Service class and complete the following operations:

1) Inherit the Service class and also customize a PersonQueryBinder class for use ComeInherit the IPerson.Stub classThat isimplement the IPerson interface and IBinder interface

2) Instantiate the custom Stub class and override the onBind method of Service, Return a binder object!

AIDLService.java

package com.jay.aidlserver;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
import com.jay.aidl.IPerson.Stub;

/ **
 * Created by Jay on 2015/8/18 0018.
 */
public class AIDLService extends Service {

private IBinder binder = new PersonQueryBinder();
private String[] names = {"B神","艹神" ,"Ji Shen","J God","Xiang Shen"};

private String query(int num)
{
if(num > 0 && num < 6){
RETURN NAMES [NUM-1]; ##}
Return null;
}

@Override
Public iBinder Onbind (intent Intent) {
RETURN NULL;
}

private final class PersonQueryBinder extends Stub{
@Override
public String queryPerson(int num) throws RemoteException {
return query(num);
      }
}
}

Step 3:在AndroidManifest.xml文件中注册Service

<service android:name=".AIDLService">
            <intent-filter>
                <action android:name="android.intent.action.AIDLService" />
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
        </service>

We do not provide an Activity interface here, but the Service provided by the application can be called by other apps!


2. Client
Copy the aidl file from the server directly, and then we complete it directly in MainActivity and bind the local Service
Somewhat similar, the process is as follows:
1) Customize the PersonConnection class Implement the ServiceConnection interface
2) Use the PersonConnection object as a parameter to call bindService to bind the remote Service
bindService(service ,conn,BIND_AUTO_CREATE);
ps: The third parameter is to set the automatic creation if the service is not started.
3) Different from the local Service, ServiceConnection binding to the remote Service cannot be directly Obtaining the IBinder object returned by Service's onBind() method
can only return the proxy object returned by the onBind() method. The following processing needs to be done:
iPerson = IPerson.Stub.asInterface(service);
Then complete the initialization, and button events, etc.

The specific code is as follows:

MainActivity.java

package com.jay.aidlclient;

import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;

import com.jay.aidl.IPerson;

public class MainActivity extends AppCompatActivity implements View.OnClickListener{

    private EditText edit_num;
    private Button btn_query;
    private TextView txt_name;
    private IPerson iPerson;
    private PersonConnection conn = new PersonConnection();


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        bindViews();
        //绑定远程Service
        Intent service = new Intent("android.intent.action.AIDLService");
        service.setPackage("com.jay.aidlserver");

        bindService(service, conn, BIND_AUTO_CREATE);
        btn_query.setOnClickListener(this);
    }

    private void bindViews() {
        edit_num = (EditText) findViewById(R.id.edit_num);
        btn_query = (Button) findViewById(R.id.btn_query);
        txt_name = (TextView) findViewById(R.id.txt_name);
    }

    @Override
    public void onClick(View v) {
        String number = edit_num.getText().toString();
        int num = Integer.valueOf(number);
        try {
            txt_name.setText(iPerson.queryPerson(num));
        } catch (RemoteException e) {
            e.printStackTrace();
        }
        edit_num.setText("");
    }

    private final class PersonConnection implements ServiceConnection {
        public void onServiceConnected(ComponentName name, IBinder service) {
            iPerson = IPerson.Stub.asInterface(service);
        }
        public void onServiceDisconnected(ComponentName name) {
            iPerson = null;
        }
    }
}

Next, start AIDLServivce, then start AIDLClient, enter the query serial number, and you can get the corresponding name! Of course, you can also start AIDLClient directly, and you will get the same effect:

The rendering is as follows:

6.gif


##3) AIDL Service that passes complex data

In the above example, we only pass int type parameters, and then the server returns a String type parameter, which seems to satisfy Our basic needs, but in actual development, we may need to consider passing complex data types! Let’s learn next How to pass data of complex data types to the server! Before we start, let’s first understand

Parcelable interface!

——Introduction to Parcelable interface:

I believe that those who have used serialization basically know this interface. In addition to it, there is another Serializable, the same is used for serialization, It’s just that Parcelable is more lightweight and faster! But it’s a bit troublesome to write. Of course, if you use as, you can use it. Plug-in to complete serialization, such as:

Android Parcelable Code GeneratorOf course, here we still teach you how to implement this interface~

Firstneeds to implement:writeToParcel and readFromPacel methods The write method writes the object to the parcel, while the read method reads the object from the parcel. Please note that the order of writing attributes needs to be the same as the order of reading

Thenneeds to add a static final# named CREATOR to this class ##Attributes To change the properties, you need to implement: android.os.Parcelable.CreatorInterface

And then

need to write two methods in the interface:createFromParcel (Parcel source) method: implements the function of creating a JavaBean instance from source newArray(int size): creates an array of type T and length size, with only a simple return new T[size]; (T here is the Person class)

Finally, describeContents()

: I don’t know what this is used for, just return 0! Ignore him

——In addition,

, are non-primitive types, except String and CharSequence, the rest are A direction indicator is required. Direction indicators include in, out, , and inout. in means that it is set by the client, out means that it is set by the server, and inout means that the value is set by both the client and the server. Okay, let’s try writing code (there is a problem with the custom type here in AS, which has not been solved yet, so I will use Eclipse~):


Code example :

Customize two object types: Person and Salary, Person is used as a parameter for calling the remote Service, and Salary is used as the return value! Then the first thing to do is to create the Person and Salary classes, and also need to implement the Parcelable interface

1.——Server side

Step 1: Create the files of Person.aidl and Salary.aidl, because they need to implement the Parcelable interface, so The following statement:

Person.aidl:     parcelable Person; 
Salary.aidl:     parcelable Salary;
Step 2: Create the Person class and the Salary class respectively. You need to implement the Parcelable interface and rewrite the corresponding methods!


PS: Because we later obtain the data in the Map collection based on the Person object, we rewrote hashcode and equals in Person.java method; while the Salary class does not need it!

Person.java:

package com.jay.example.aidl;

import android.os.Parcel;
import android.os.Parcelable;

/**
 * Created by Jay on 2015/8/18 0018.
  */
public class Person implements Parcelable{

private Integer id;
private String name;

public Person() {}

public Person(Integer id, String name) {
this.id = id;
this.name = name;
}

public Integer getId() {
return id;
}

public void setId(Integer id) {
this.id = id;
}

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

public String getName() {
return name;
}


//Method that must be implemented to implement Parcelable, I don’t know what to use it for Yes, just return 0.
@Override
public int describeContents() {
return 0;
}


//Method to write data into Parcel
@Override
public void writeToParcel(Parcel dest, int flags) {
//Write the data contained in the object to parcel
dest.writeInt(id);
dest. writeString(name);
}

//A static final attribute named CREATOR must be provided. This attribute needs to implement
//android.os.Parcelable.Creator<T>interface
public static final Parcelable.Creator<Person> CREATOR = new Parcelable.Creator<Person>() {
        //Read data from Parcel and return Person object
                                                                                       public Person createFromParcel(Parcel source) {
return new Person(source.readInt(),source.readString());
@Override
public Person[] newArray(int size) {
Return New Person [SIZE];
}
};

// Because when we gather the element of the element, it is obtained according to the Person object, so it is more troublesome,
// We need to override the hashCode() and equals() methods
@Override
public int hashCode()
{
final int prime = 31;
int result = 1;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
@Override
public boolean equals(Object obj)
{
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
          return false;
             Person other = (Person) obj;
                                                                                                      return false;
       }
        else if (!name.equals(other.name))
                                                                                                                                                                                                                                    <pre><p><strong>Salary.java</strong>~照葫芦画瓢</p>

<pre>
package com.jay.example.aidl; 

import android.os.Parcel;
import android.os.Parcelable;

/**
 * Created by Jay on 2015/8/18 0018.
 */
public class Salary implements Parcelable {

    private String type;
    private Integer salary;

    public Salary() {
    }

    public Salary(String type, Integer salary) {
        this.type = type;
        this.salary = salary;
    }

    public String getType() {
        return type;
    }

    public Integer getSalary() {
        return salary;
    }

    public void setType(String type) {
        this.type = type;
    }

    public void setSalary(Integer salary) {
        this.salary = salary;
    }

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

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(type);
        dest.writeInt(salary);
    }

    public static final Parcelable.Creator<Salary> CREATOR = new Parcelable.Creator<Salary>() {
        //从Parcel中读取数据,返回Person对象
        @Override
        public Salary createFromParcel(Parcel source) {
            return new Salary(source.readString(), source.readInt());
        }

@Override
Public Salary [] NewArray (int Size) {
Return New Salar [size];
}
# Public string tostring () {
Return "Job:" + type + " Salary: " + salary;
}
}

Step 3

: Create an ISalary.aidl file and put it in it Write a simple method to obtain salary information:

package com.jay.example.aidl;
import com.jay.example.aidl.Salary;
import com .jay.example.aidl.Person;
interface ISalary
{
//Define a Person object as an incoming parameter
//When defining a method in the interface, you need to formulate the delivery mode of the new parameter, here It is passed in, so there is an in
Salary getMsg(in Person owner);
}

ps:You can remember here that if you are using a custom data type, you need to import it! ! ! Remember! ! !

Step 4: Preparation of core Service: Define a SalaryBinder class that inherits Stub to implement the ISalary and IBinder interfaces; define a Map collection to store information! Restart the onBind method and return the object instance of the SalaryBinder class!

AidlService.java

package com.jay.example.aidl_complexservice;

import java.util.HashMap;
import java.util.Map;
import com.jay.example.aidl. ISalary.Stub;
import com.jay.example.aidl.Person;
import com.jay.example.aidl.Salary;
import android.app.Service;
import android.content. Intent;
import android.os.IBinder;
import android.os.RemoteException;

public class AidlService extends Service {

private SalaryBinder salaryBinder;
private static Map< ;Person,Salary> ss = new HashMap<Person, Salary>();
//Initialize the Map collection, here it is initialized in the static code block, of course you can also complete the initialization in the constructor
static
                                                                                                    ss.put(                                 ss.put (                                                                   ss.put (                        . new Salary("Singer", 20000));
ss.put(new Person(3, "XM"), new Salary("Student", 20));
ss.put(new Person(4 , "MrWang"), new Salary("Teacher", 2000));
      salaryBinder = new SalaryBinder();


//It also inherits Stub, that is, it implements both the ISalary interface and the IBinder interface
public class SalaryBinder extends Stub
{
        @Override  
        public Salary getMsg(Person owner) throws RemoteException {  
            return ss.get(owner);  
        }  
    }  
      
    @Override  
    public void onDestroy() {  
        System.out.println("服务结束!");  
        super.onDestroy();  
    }  
}

注册下Service:

<service android:name=".AidlService">  
    <intent-filter>    
        <action android:name="android.intent.action.AIDLService" />  
        <category android:name="android.intent.category.DEFAULT" />  
    </intent-filter>    
</service>

2——Client writing

Step 1:Copy the AIDL file of the server. The directory after copying is as follows:

7.jpg

Step 2: Write a simple layout, and then implement the core MainActvitiy Define a ServiceConnection object and override the corresponding method, similar to the previous ordinary data Then in bindService, then get the Salary object in the Button's click event and display it!

MainActivity.java

package com.jay.example.aidl_complexclient;  
  
import com.jay.example.aidl.ISalary;  
import com.jay.example.aidl.Person;  
import com.jay.example.aidl.Salary;  
  
import android.app.Activity;  
import android.app.Service;  
import android.content.ComponentName;  
import android.content.Intent;  
import android.content.ServiceConnection;  
import android.os.Bundle;  
import android.os.IBinder;  
import android.os.RemoteException;  
import android.view.View;  
import android.view.View.OnClickListener;  
import android.widget.Button;  
import android.widget.EditText;  
import android.widget.TextView;  
  
  
public class MainActivity extends Activity {  
  
    private ISalary salaryService;  
    private Button btnquery;  
    private EditText editname;  
    private TextView textshow;  
    private ServiceConnection conn = new ServiceConnection() {  
          
        @Override  
        public void onServiceDisconnected(ComponentName name) {  
            salaryService = null;  
        }  
          
        @Override  
        public void onServiceConnected(ComponentName name, IBinder service) {  
            //返回的是代理对象,要调用这个方法哦!  
            salaryService = ISalary.Stub.asInterface(service);  
        }  
    };  
      
      
    @Override  
    protected void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.activity_main);  
          
        btnquery = (Button) findViewById(R.id.btnquery);  
        editname = (EditText) findViewById(R.id.editname);  
        textshow = (TextView) findViewById(R.id.textshow);  
          
        Intent it = new Intent();  
        it.setAction("com.jay.aidl.AIDL_SERVICE");  
        bindService(it, conn, Service.BIND_AUTO_CREATE);  
          
        btnquery.setOnClickListener(new OnClickListener() {           
            @Override  
            public void onClick(View v) {  
                try  
                {  
                    String name = editname.getText().toString();  
                    Salary salary = salaryService.getMsg(new Person(1,name));  
                    textshow.setText(name + salary.toString());  
                }catch(RemoteException e){e.printStackTrace();}  
            }  
        });  
          
    }  
    @Override  
    protected void onDestroy() {  
        super.onDestroy();  
        this.unbindService(conn);  
    }  
      
}

Running screenshot:

8.jpg

##PS: The code here was written in Eclipse before Code, there is a problem with custom types under Android Studio. I haven't found a solution yet. If anyone knows, please let me know! ! ! Thank you very much! ! ! The problems that arise are as follows:

9.png

Code download for two instances (based on Eclipse):

1) Use AIDL to complete simple communication between processes
2) Implementation of AIDL Service that transfers complex data


3. Complete cross-process communication directly through Binder's onTransact

As mentioned above, Android can complete communication through Binder's onTrensact method. Here is Let’s try it briefly, based on the previous one Example of serial number query name:

Server-side implementation:

/**
 * Created by Jay on 2015/8/18 0018.
 */
public class IPCService extends Service{

    private static final String DESCRIPTOR = "IPCService";
    private final String[] names = {"B神","艹神","基神","J神","翔神"};
    private MyBinder mBinder = new MyBinder();


    private class MyBinder extends Binder {
        @Override
        protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
            switch (code){
                case 0x001: {
                    data.enforceInterface(DESCRIPTOR);
                    int num = data.readInt();
                    reply.writeNoException();
                    reply.writeString(names[num]);
                    return true;
                }
            }
            return super.onTransact(code, data, reply, flags);
        }
    }

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

Client implementation:

public class MainActivity extends AppCompatActivity implements View.OnClickListener{

    private EditText edit_num;
    private Button btn_query;
    private TextView txt_result;
    private IBinder mIBinder;
    private ServiceConnection PersonConnection  = new ServiceConnection()
    {
        @Override
        public void onServiceDisconnected(ComponentName name)
        {
            mIBinder = null;
        }

        @Override
        public void onServiceConnected(ComponentName name, IBinder service)
        {
            mIBinder = service;
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        bindViews();

        //绑定远程Service
        Intent service = new Intent("android.intent.action.IPCService");
        service.setPackage("com.jay.ipcserver");
        bindService(service, PersonConnection, BIND_AUTO_CREATE);
        btn_query.setOnClickListener(this);
    }

    private void bindViews() {
        edit_num = (EditText) findViewById(R.id.edit_num);
        btn_query = (Button) findViewById(R.id.btn_query);
        txt_result = (TextView) findViewById(R.id.txt_result);
    }

    @Override
    public void onClick(View v) {
int num = Integer.parseInt(edit_num.getText().toString());
if (mIBinder == null)
{
Toast.makeText(this, "The server is not connected or the server is blocked "Abnormally kill", toast.Length_short) .show ();
} else {#steid.os.parcel _data = Android.os.parcel.obtain (); android.os.Parcel.obtain();
String _result = null;
try{
_data.writeInterfaceToken("IPCService");
_data.writeInt(num );
mIBinder. transact(0x001, _data, _reply, 0);
_reply.readException();
_result = _reply.readString();
txt_result.setText (_result);
                           edit_num.setText("" ;
                                                                                                                                                       
     ;
                                                                         

The code is relatively simple, so I won’t explain it much~just use it and modify it yourself! PS: Code reference: A brief analysis of Android aidl Binder framework


4. Some things to pay attention to in Service after Android 5.0:

Today when I started the Service implicitly, I encountered such a problem

10.png

Then the program crashed as soon as it was started, and it took a long time to figure it out. Here’s what’s wrong with Android 5.0, It turns out that there is a new feature after 5.0, which is: Service Intent must be explitict! Well, the Service cannot be started implicitly, and the solution is very simple! For example, StartService:

startService(new Intent(getApplicationContext(), "com.aaa.xxxserver")); If you write the program like this, it will crash directly. You should write it as follows: startService(new Intent(getApplicationContext(), LoadContactsService.class));

If it is BindService:Intent service = new Intent("android.intent.action.AIDLService");# On the basis of ##, add the package name: service.setPackage("com.jay.ipcserver");That’s it~

Official document:

http://developer.android.com/intl/zh-cn/guide/components/intents-filters.html#TypesDocumentation:

11.png


Summary of this section:

Okay, that’s the last section about Service. This section explains the basic concepts of Binder and how to implement inter-process communication. Two ways: cross-process communication through AIDL and Binder.onTransact()! Finally, we also explained the post-Android 5.0 Note that Service cannot be started implicitly! That’s it, thank you~