In Android, general interprocess communication, data transfer, which we use a lot, is also very simple. So what if one application wants to access data in another application, or interact with it?

Don’t worry, Android has already provided us with a solution in the form of AIDL (Android Interface Definition Language).

Content:

  • Start Service across applications
  • Cross-application Communication with Service (1)
  • Cross-application Communication with Service (2)

Start Service across applications

1. The same process starts the Service

MainActivity :

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

        startService(new Intent(this,MyService.class));
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        stopService(new Intent(this,MyService.class));
    }Copy the code

MyService :

@Override
    public IBinder onBind(Intent intent) {
        // TODO: Return the communication channel to the service.
        throw new UnsupportedOperationException("Not yet implemented");
    }

    @Override
    public void onCreate() {
        super.onCreate();

        Log.e("MyService","Started Service");
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.e("MyService","Destroy Service");
    }Copy the code

Operation effect:

You can see that our Log started and stopped the Service when starting and exiting the MainActivity, respectively. That’s easy. Now let’s look at cross-process boot.

2. Start the Service across processes

  • Create a new Module (anotherApp)
  • Start the service in the app created above in anotherApp

Let’s look at the first one, after we create the Module

Modify MainActivity in AnotherApp:

@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); findViewById(R.id.btn_startAppService).setOnClickListener(this); findViewById(R.id.btn_stopAppService).setOnClickListener(this); } @Override public void onClick(View view) { switch (view.getId()){ case R.id.btn_startAppService: break; case R.id.btn_stopAppService: break; }}Copy the code

So the question is, how do we launch services in our App? Obviously, it is impossible to get the definition of a given class directly in the same process

Instead, we can use Intent. Configure the intent-filter for the service directly in the configuration file. Note: Android5.0 and later cannot do this. Starting with 5.0 (including 5.0), you must start with an Intent.

We could write this in the AnotherApp code:

 private Intent Serviceintent;

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

        Serviceintent = new Intent();
        Serviceintent.setComponent(new   ComponentName("com.example.mirgao.startservicefromanotherapp","com.example.mirgao.startservicefromanotherapp.MyService"));

        findViewById(R.id.btn_startAppService).setOnClickListener(this);
        findViewById(R.id.btn_stopAppService).setOnClickListener(this);
    }

    @Override
    public void onClick(View view) {
        switch (view.getId()){
            case R.id.btn_startAppService:
                startService(Serviceintent);
                break;

            case R.id.btn_stopAppService:
                break;
        }
    }Copy the code

We new the Intent and give it a setComponent, where the first parameter passes the package name of the app to launch and the second parameter passes the class name to launch.

Results of running AnotherApp:

You can see that starting and stopping the Service in the App in AnotherApp is still successful.

Note that the red line should be adjusted to the name of the application package you want to start, otherwise you will not see the corresponding log.

Cross-application Communication with Service (1)

Start the service. Now let’s bind the service.

We know that A program B wants to bind to A service. We can’t get the IBind object defined in A. How can we do this? Don’t worry, our problem with the Android system as well as giving us a method, AIDL came into being!

  • Create an ADIL file in your App
  • Override the onBind method in Service in App
  • Modify the main function logic in AnotherApp

After the AIDL file is created, the system automatically generates related classes.

interface AppServiceBinder {
    /**
     * 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);
}Copy the code

In this case, we can return the aidl method directly in MyService onBind method and implement aidl method :(note, please Build — Rebuild Project before using it)

public class MyService extends Service { public MyService() { } @Override public IBinder onBind(Intent intent) { // TODO: Return the communication channel to the service. return new AppServiceBinder.Stub() { @Override public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException { } }; } @Override public void onCreate() { super.onCreate(); Log.e("MyService","Started Service"); } @Override public void onDestroy() { super.onDestroy(); Log.e("MyService","Destroy Service"); }}Copy the code

Finally, we modify the logic in AnotherApp:

public class MainActivity extends AppCompatActivity implements View.OnClickListener, ServiceConnection { private Intent Serviceintent; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Serviceintent = new Intent(); Serviceintent.setComponent(new ComponentName("com.example.mirgao.startservicefromanotherapp","com.example.mirgao.startservicefromanotherapp.MyService") ); findViewById(R.id.btn_startAppService).setOnClickListener(this); findViewById(R.id.btn_stopAppService).setOnClickListener(this); findViewById(R.id.btn_bindAppService).setOnClickListener(this); findViewById(R.id.btn_unbindAppService).setOnClickListener(this); } @Override public void onClick(View view) { switch (view.getId()){ case R.id.btn_startAppService: startService(Serviceintent); break; case R.id.btn_stopAppService: stopService(Serviceintent); break; case R.id.btn_bindAppService: bindService(Serviceintent,this, Context.BIND_AUTO_CREATE); break; case R.id.btn_unbindAppService: unbindService(this); break; } } @Override public void onServiceConnected(ComponentName componentName, IBinder iBinder) { Log.e("anotherApp","Bind Service"); Log.e("anotherApp", String.valueOf(iBinder)); } @Override public void onServiceDisconnected(ComponentName componentName) { } }Copy the code

We need to pay attention to several issues when we run:

App log:

So if we click on start, stop, bind, touch bind in AnotherApp, we’re going to call MyService in our App

At this point, let’s switch the package name and look at AnotherApp’s log:



As you can see, at this point AnotherApp already knows that the service in the binding App was successful, and it also got IBind.

At this point, we are bound to the service, so how do we communicate with it? Since there is no communication, it makes no sense for us to bind the service. Well, don’t worry, look below:

Cross-application Communication with Service (2)

Purpose: Modify data in App.

Steps:

  • Add the modify data method to the AIDL file
  • MyService overrides the new method in App
  • Start a circular data thread in the OnCreate method of MyService in your App
  • Perform operations in AnotherApp to synchronize data to App

Add method setData () to AIDL and rewrite MyService OnBind:

interface AppServiceBinder {
    /**
     * 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);

    void setData(String data);
}Copy the code
@Override public IBinder onBind(Intent intent) { // TODO: Return the communication channel to the service. return new AppServiceBinder.Stub() { @Override public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException { } @Override public void setData(String data) throws RemoteException { MyService.this.data = data; }}; }Copy the code

Start a loop of data in the OnCreate method of MyService in App, output data once every 1s, the entire MyService code:

public class MyService extends Service { public MyService() { } @Override public IBinder onBind(Intent intent) { // TODO: Return the communication channel to the service. return new AppServiceBinder.Stub() { @Override public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException { } @Override public void setData(String data) throws RemoteException { MyService.this.data = data; }}; } @Override public void onCreate() { super.onCreate(); new Thread(){ @Override public void run() { super.run(); running = true; while (running) { Log.e("MyService",data); try { sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } }.start(); } @Override public void onDestroy() { super.onDestroy(); Log.e("MyService","Destroy Service"); running = false; } private String data = "AIDL "; private boolean running = false; }Copy the code

Let’s change AnotherApp:

public class MainActivity extends AppCompatActivity implements View.OnClickListener, ServiceConnection { private Intent Serviceintent; private EditText et; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Serviceintent = new Intent(); Serviceintent.setComponent(new ComponentName("com.example.mirgao.startservicefromanotherapp","com.example.mirgao.startservicefromanotherapp.MyService") ); findViewById(R.id.btn_startAppService).setOnClickListener(this); findViewById(R.id.btn_stopAppService).setOnClickListener(this); findViewById(R.id.btn_bindAppService).setOnClickListener(this); findViewById(R.id.btn_unbindAppService).setOnClickListener(this); findViewById(R.id.btn_Sync).setOnClickListener(this); et = (EditText) findViewById(R.id.et); } @Override public void onClick(View view) { switch (view.getId()){ case R.id.btn_startAppService: startService(Serviceintent); break; case R.id.btn_stopAppService: stopService(Serviceintent); break; case R.id.btn_bindAppService: bindService(Serviceintent,this, Context.BIND_AUTO_CREATE); break; case R.id.btn_unbindAppService: unbindService(this); break; case R.id.btn_Sync: break; } } @Override public void onServiceConnected(ComponentName componentName, IBinder iBinder) { Log.e("anotherApp","Bind Service"); Log.e("anotherApp", String.valueOf(iBinder)); } @Override public void onServiceDisconnected(ComponentName componentName) { } }Copy the code

Now, the question is, how do we use it when we synchronize. We need to have an IBinder, and how can we easily execute a remote function through IBinder?

We need to create an AIDL file for AnotherApp as well. And make sure the package name is the same:

How to create package name in AnotherApp:

Then create a package in this file with the same name as your App’s AIDL package, and copy that AIDL file.

At this point, AnotherApp has the same AIDL file, meaning the same AIDL-related definitions can be generated in it. (Rebuild)

In this way, we modify the MainActivity of AnotherApp:

public class MainActivity extends AppCompatActivity implements View.OnClickListener, ServiceConnection { private Intent Serviceintent; private EditText et; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Serviceintent = new Intent(); Serviceintent.setComponent(new ComponentName("com.example.mirgao.startservicefromanotherapp","com.example.mirgao.startservicefromanotherapp.MyService") ); findViewById(R.id.btn_startAppService).setOnClickListener(this); findViewById(R.id.btn_stopAppService).setOnClickListener(this); findViewById(R.id.btn_bindAppService).setOnClickListener(this); findViewById(R.id.btn_unbindAppService).setOnClickListener(this); findViewById(R.id.btn_Sync).setOnClickListener(this); et = (EditText) findViewById(R.id.et); } @Override public void onClick(View view) { switch (view.getId()){ case R.id.btn_startAppService: startService(Serviceintent); break; case R.id.btn_stopAppService: stopService(Serviceintent); break; case R.id.btn_bindAppService: bindService(Serviceintent,this, Context.BIND_AUTO_CREATE); break; case R.id.btn_unbindAppService: unbindService(this); break; case R.id.btn_Sync: if (binder ! = null){ try { binder.setData(et.getText().toString()); } catch (RemoteException e) { e.printStackTrace(); } } break; } } @Override public void onServiceConnected(ComponentName componentName, IBinder iBinder) { Log.e("anotherApp","Bind Service"); Log.e("anotherApp", String.valueOf(iBinder)); binder = AppServiceBinder.Stub.asInterface(iBinder); } @Override public void onServiceDisconnected(ComponentName componentName) { } private AppServiceBinder binder = null; }Copy the code

Attention:…!!

In onServiceConnected ected, binder = (AppServiceBinder) iBinder; Binder and iBnder are in two applications and occupy two different addresses in memory.

Note: Comment out the start and stop service code in the App before running

Let’s look at the results:

So in our App, every 1S we output one piece of data, and then we click sync data, and we see that the data has changed

At this point, we have successfully passed data to the service in the current application by remote method in another application!

Source code there is a need for private message me