Android service (2)

In the previous article, we learned about the important aspects of the Android Service, including the basic usage of the Service, the communication between Service and Activity, the way the Service was destroyed, the relationship between Service and Thread, and how to create the front service. The above mentioned knowledge points, basically covered most of the daily development work which may be used to the Service technology. However, there is actually a more high-end on the use of skills did not introduce, that is, the use of remote Service. Use the remote service can even achieve the function of Android cross-process communication, let us look at the following specific.

If you have not read the previous article, it is recommended to read Android service (1), because this article is involved in the code on the basis of the previous article To be modified.

In the previous article we know, Service is actually running in the main thread, if directly in the Service to deal with some time-consuming logic, it will lead to the program ANR.

Let’s take an experiment to verify it, modify the ServiceTest project created in the previous article, let the thread sleep for 60 seconds in MyService’s onCreate () method, as follows:

Let’s take an experiment to verify it, modify the ServiceTest project created in the previous article, let the thread sleep for 60 seconds in MyService’s onCreate () method, as follows:

public class MyService extends Service {  
  
    ......  
  
    @Override  
    public void onCreate() {  
        super.onCreate();  
        Log.d(TAG, "onCreate() executed");  
        try {  
            Thread.sleep(60000);  
        } catch (InterruptedException e) {  
            e.printStackTrace();  
        }  
    }  
      
    ......  
  
}

After re-running, click the Start Service button or Bind Service button, the program will block and can not carry out any other operation, after a period of time will pop up ANR prompt box.

Before we mentioned that you should open the thread in the service to perform time-consuming tasks, so that you can effectively avoid the emergence of ANR.

Then the theme of this article is to introduce the use of remote Service, if the MyService into a remote Service, there will be no ANR situation? Let’s try it out.

Will be a common Service into a remote Service is actually very simple, only need to register the Service when it android: process attribute specified as: remote on it, the code is as follows:

<?xml version="1.0" encoding="utf-8"?>  
<manifest xmlns:android="http://schemas.android.com/apk/res/android"  
    package="com.example.servicetest"  
    android:versionCode="1"  
    android:versionName="1.0" >  
  
    ......  
      
    <service  
        android:name="com.example.servicetest.MyService"  
        android:process=":remote" >  
    </service>  
  
</manifest>  

Will be a common Service into a remote Service is actually very simple, only need to register the Service when it android: process attribute specified as: remote on it, the code is as follows:

Why will the conversion of MyService into a remote service will not lead to the procedure ANR? This is because, after using the remote Service, MyService has been running in another process, so it will only block the process of the main thread, and will not affect the current application.

In order to confirm that MyService is now running in another process, we are in the MainActivity onCreate () method and MyService onCreate () method to add a log, print out their respective process id, as follows:

Log.d("TAG", "process id is " + Process.myPid());  

Re-run the program again, and then click the Start Service button, you will find a different print id.

You can see that not only the process id is different, and even the application package name is not the same, MyService print the log, package name followed by: remote logo.

That since the remote Service so easy to use, simply after we put all the Service are converted into a remote Service bar, but also save and then open the thread. In fact, the remote Service is not only easy to use, or even can be called more difficult to use. In general, if you can not use the remote Service, try not to use it.

Here to look at its drawbacks, first of all MyService onCreate () method to allow the thread to sleep code removed, and then re-run the program, and click on the Bind Service button, you will find the program crashes! Why click on the Start Service button program will not crash, and click the Bind Service button will crash it? This is due to the Bind Service button in the click event which we will make MainActivity and MyService to establish association, but the current MyService is a remote service, Activity and Service running in two different processes, then you can no longer use the traditional The way to establish the association, the program will collapse.

So how can we let Activity and a remote service to establish a link? This will use AIDL for cross-process communication (IPC).

AIDL (Android Interface Definition Language) is the meaning of the Android interface definition language, it can be used to allow a service and multiple application components between the cross-process communication, which can achieve multiple applications share the same service function.

Here we take a step by step to see what the use of AIDL in the end is what First need to create a new AIDL file, in this document defines the need to Communicate with the Service method. Create a new MyAIDLService.aidl file with the following code:

package com.example.servicetest;  
interface MyAIDLService {  
    int plus(int a, int b);  
    String toUpperCase(String str);  
} 

Click Save, gen directory will generate a corresponding Java file, as shown below:

And then modify the code in MyService, which we have just defined the MyAIDLService interface, as follows:

public class MyService extends Service {  
  
    ......  
  
    @Override  
    public IBinder onBind(Intent intent) {  
        return mBinder;  
    }  
  
    MyAIDLService.Stub mBinder = new Stub() {  
  
        @Override  
        public String toUpperCase(String str) throws RemoteException {  
            if (str != null) {  
                return str.toUpperCase();  
            }  
            return null;  
        }  
  
        @Override  
        public int plus(int a, int b) throws RemoteException {  
            return a + b;  
        }  
    };  
  
}  

Here first MyAIDLService.Stub was implemented, rewrite the toUpperCase () and plus () these two methods. The two methods are to convert all the strings into an uppercase format, and add the two incoming integers, respectively. And then returns the implementation of MyAIDLService.Stub in the onBind () method. Why can you write here? Because Stub is actually a subclass of Binder, so in the onBind () method can be directly returned to the implementation of Stub.

Next, modify the code in MainActivity as follows:

public class MainActivity extends Activity implements OnClickListener {  
  
    private Button startService;  
  
    private Button stopService;  
  
    private Button bindService;  
  
    private Button unbindService;  
      
    private MyAIDLService myAIDLService;  
  
    private ServiceConnection connection = new ServiceConnection() {  
  
        @Override  
        public void onServiceDisconnected(ComponentName name) {  
        }  
  
        @Override  
        public void onServiceConnected(ComponentName name, IBinder service) {  
            myAIDLService = MyAIDLService.Stub.asInterface(service);  
            try {  
                int result = myAIDLService.plus(3, 5);  
                String upperStr = myAIDLService.toUpperCase("hello world");  
                Log.d("TAG", "result is " + result);  
                Log.d("TAG", "upperStr is " + upperStr);  
            } catch (RemoteException e) {  
                e.printStackTrace();  
            }  
        }  
    };  
  
    ......  
  
}  

We just modified the code in the ServiceConnection. As you can see, here first use the MyAIDLService.Stub.asInterface () method to pass the incoming IBinder object into the MyAIDLService object, and then you can call all the interfaces defined in the MyAIDLService.aidl file. Here we first call the plus () method, and passed the 3 and 5 as a parameter, and then call the toUpperCase () method, and pass the hello world string as a parameter, and finally call the method to return the results printed out.

Now rerun the program and click the Bind Service button then you can see;

result is 8
Upperstr is Hello World

Thus, we have indeed successfully achieved cross-process communication, and in a process to access another process in the method.

But you can also see that the current cross-process communication in fact does not have any real effect, because it is only in an Activity called the same application in the Service method. The real meaning of cross-process communication is to allow an application to access another application in the Service, in order to achieve the function of sharing Service. So now we naturally have to learn about how to call in other applications to MyService Lane method.

In the previous article we already know that if you want to make the association between Activity and Service, you need to call the bindService () method, and pass Intent as a parameter, specify the Intent to bind the Service, the sample code as follows:

Intent bindIntent = new Intent(this, MyService.class);  
bindService(bindIntent, connection, BIND_AUTO_CREATE); 

Here in the construction of Intent when using MyService.class to specify which service to bind, but in another application to bind the service when there is no MyService this class, then you must use the implicit Intent The Now modify the code in AndroidManifest.xml to add an action to MyService as follows:

<?xml version="1.0" encoding="utf-8"?>  
<manifest xmlns:android="http://schemas.android.com/apk/res/android"  
    package="com.example.servicetest"  
    android:versionCode="1"  
    android:versionName="1.0" >  
  
    ......  
  
    <service  
        android:name="com.example.servicetest.MyService"  
        android:process=":remote" >  
        <intent-filter>  
            <action android:name="com.example.servicetest.MyAIDLService"/>  
        </intent-filter>  
    </service>  
  
</manifest> 

This means that MyService can respond to an intent with the action com.example.servicetest.MyAIDLService.

Now re-run the program, so that the remote Service side of the work done.

And then create a new Android project, named ClientTest, we try to call this method in the remote method MyService.

Activity in ClientTest If you want to establish association with MyService is not difficult, first of all need to MyAIDLService.aidl file from the ServiceTest project copy over, pay attention to the original package path to copy together.

MyAidlService.png

And then open or create activity_main.xml, in the layout file also add a Bind Service button:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
    android:layout_width="match_parent"  
    android:layout_height="match_parent"  
    android:orientation="vertical"  
     >  
  
   <Button   
       android:id="@+id/bind_service"  
       android:layout_width="match_parent"  
       android:layout_height="wrap_content"  
       android:text="Bind Service"  
       />  
  
</LinearLayout>  

Then open or create a new MainActivity, in which to join and MyService to establish the associated code, as follows:

public class MainActivity extends Activity {  
  
    private MyAIDLService myAIDLService;  
  
    private ServiceConnection connection = new ServiceConnection() {  
  
        @Override  
        public void onServiceDisconnected(ComponentName name) {  
        }  
  
        @Override  
        public void onServiceConnected(ComponentName name, IBinder service) {  
            myAIDLService = MyAIDLService.Stub.asInterface(service);  
            try {  
                int result = myAIDLService.plus(50, 50);  
                String upperStr = myAIDLService.toUpperCase("comes from ClientTest");  
                Log.d("TAG", "result is " + result);  
                Log.d("TAG", "upperStr is " + upperStr);  
            } catch (RemoteException e) {  
                e.printStackTrace();  
            }  
        }  
    };  
  
    @Override  
    protected void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.activity_main);  
        Button bindService = (Button) findViewById(R.id.bind_service);  
        bindService.setOnClickListener(new OnClickListener() {  
            @Override  
            public void onClick(View v) {  
                Intent intent = new Intent("com.example.servicetest.MyAIDLService");  
                bindService(intent, connection, BIND_AUTO_CREATE);  
            }  
        });  
    }  
  
}  

This part of the code we will be very familiar, right? Yes, this is almost exactly the same as the code in the MainActivity of ServiceTest, except that when we associate the Activity and Service with an implicit Intent, specify the Intent action as com.example.servicetest.MyAIDLService.

After the current Activity and MyService are associated, we still call both the plus () and toUpperCase () methods. The remote MyService will process the incoming parameters and return the results, and then print the results.

In this case, the code in ClientTest is all done, and now run the project, and then click the Bind Service button, this time will be and remote MyService to establish association.

I do not have to say, we have seen that our cross-process communication has been a perfect realization.

However, there is a need to note that, because it is in the process of passing data between different processes, Android format support for such data is very limited, basically only can pass Java basic data type, string, List or Map and so on. So what if i want to pass a custom class? This must be made to achieve this class Parcelable interface, and to give this class also defines a name of the AIDL file. This part of the content is not complicated, and the relationship with the Service is not, so no longer explain in detail, and interested friends can check their own relevant information.

Well, combined with the upper and lower, this is what you need to know about Service.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s