IPC解决方案之 AIDL

android interface define language

1,跨进程启动Service

2,跨进程绑定Service

3,跨进程通信,传递基本数据

4,跨进程通信,传递复杂对象

5,常见报错

 

跨进程通信前提:2个进程均已启动

 

1,跨进程启动Service

 

Intent intent = new Intent();
//OTHER_SERVICE 另一进程Service包名+ClassName
intent.setComponent(
new ComponentName(OTHER_PACKAGE, OTHER_SERVICE)); startService(intent);

 

2,跨进程绑定Service

2.1 Service进程创建aidl

2.2 onBind返回绑定对象

 @Override
    public IBinder onBind(Intent intent) {
        return new IMyAidlInterface.Stub() {
            @Override
            public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {

            }
        };
    }

2.3 在第1个进程调用bindService与unbindService

package com.example.superleeq.myapplication;

public class MainActivity extends Activity implements ServiceConnection {

    final static String OTHER_PACKAGE = "com.example.superleeq.myapplication2";
    final static String OTHER_SERVICE = "com.example.superleeq.myapplication2.MyService";
    boolean isbinded;

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

        initView();
    }

    private void initView() {
        findViewById(R.id.activity_main_button1).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent();
                intent.setComponent(new ComponentName(OTHER_PACKAGE, OTHER_SERVICE));
               
                isbinded = bindService(intent, MainActivity.this, Context.BIND_AUTO_CREATE);
            }
        });

        findViewById(R.id.activity_main_button2).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                if (isbinded) {
                    unbindService(MainActivity.this);
                    isbinded = false;
                } else {
                    LogUtil.log("already unbindservice");
                }

            }
        });

     
    }

    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
        LogUtil.log("onServiceConnected ComponentName name =  " + name + " , IBinder service = " + service);

    }

    @Override
    public void onServiceDisconnected(ComponentName name) {
        LogUtil.log("onServiceDisconnected ComponentName name = " + name);
    }
}

 

 

3,跨进程与Service通信(基本数据)

3.1 aidl folder + package + class必须两个工程完全一致

3.2 app2 Service

package com.example.superleeq.myapplication2;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;

public class MyService extends Service {

    private String mData = "default data";
    private boolean running;

    public MyService() {
    }

    @Override
    public void onCreate() {
        super.onCreate();
        Log.e("lq", "MyService.onCreate");

        new Thread(new Runnable() {
            @Override
            public void run() {
                running = true;

                while (running){
                    Log.e("lq", "MyService.mdata=" + mData);

                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }).start();

    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.e("lq", "MyService.onDestroy");
        running = false;
    }

    @Override
    public IBinder onBind(Intent intent) {
        Log.e("lq", "MyService.onBind Intent intent=" + intent);

        return new IMyAidlInterface.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 {
                mData = data;
            }
        };
    }


}

3.3 app1 mainActivity

package com.example.superleeq.myapplication;

import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.View;
import android.widget.EditText;

import com.example.superleeq.myapplication.util.LogUtil;
import com.example.superleeq.myapplication2.IMyAidlInterface;


public class MainActivity extends Activity implements ServiceConnection {

    final static String OTHER_PACKAGE = "com.example.superleeq.myapplication2";
    final static String OTHER_SERVICE = "com.example.superleeq.myapplication2.MyService";
    boolean isbinded;
    IMyAidlInterface binder = null;

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

        initView();
    }

    private void initView() {
        findViewById(R.id.activity_main_button1).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent();
                //android5.0以后仅支持显示意图启动
                intent.setComponent(new ComponentName(OTHER_PACKAGE, OTHER_SERVICE));
                isbinded = bindService(intent, MainActivity.this, Context.BIND_AUTO_CREATE);
            }
        });

        findViewById(R.id.activity_main_button2).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {


                binder = null;

                if (isbinded) {
                    unbindService(MainActivity.this);
                    isbinded = false;
                } else {
                    LogUtil.log("already unbindservice");
                }

            }
        });

        final EditText editText = (EditText) findViewById(R.id.mInput);

        editText.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {

            }

            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {

            }

            @Override
            public void afterTextChanged(Editable s) {
                if (binder != null) {
                    try {
                        binder.setData(s.toString());
                    } catch (RemoteException e) {
                        e.printStackTrace();
                    }
                }
            }
        });

        findViewById(R.id.setdata).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (binder != null) {
                    try {
                        binder.setData(editText.getText().toString());
                    } catch (RemoteException e) {
                        e.printStackTrace();
                    }
                }
            }
        });

    }

    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
        LogUtil.log("onServiceConnected ComponentName name =  " + name + " , IBinder service = " + service);
        //不能强制转换,否则报错
        binder = IMyAidlInterface.Stub.asInterface(service);

    }

    @Override
    public void onServiceDisconnected(ComponentName name) {
        //onServiceDisconnected()方法在正常情况下即使unbindService是不被调用的,它的调用时机是当Service服务被异外销毁时,例如内存的资源不足时
        LogUtil.log("onServiceDisconnected ComponentName name = " + name);
    }
}
   
4,跨进程通信,传递复杂对象

4.1 自定义对象实现
Parcelable接口,AndroidStudio可快速生成

4.2 添加自定义对象的aidl文件,需同包下
1 package com.example.superleeq.myapplication2;
2 //parcelable首字母小写
3 parcelable Person;
View Code

 4.3 将aidl整个package copy到另一工程

 4.4 app2 Service code:

 1 package com.example.superleeq.myapplication2;
 2 
 3 import android.app.Service;
 4 import android.content.Intent;
 5 import android.os.IBinder;
 6 import android.os.RemoteException;
 7 
 8 public class MyService extends Service {
 9 
10     @Override
11     public IBinder onBind(Intent intent) {
12         return new AidlResult();
13     }
14 
15     static final class AidlResult extends IMyAidlInterface.Stub {
16         @Override
17         public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {
18 
19         }
20         @Override
21         public Person getPerson(int whichPerson) throws RemoteException {
22             Person result = null;
23             switch (whichPerson) {
24                 case 0:
25                     result = new Person("name_0", 20);
26                     break;
27                 case 1:
28                     result = new Person("name_1", 21);
29                     break;
30                 case 2:
31                     result = new Person("name_2", 22);
32                     break;
33                 case 3:
34                     result = new Person("name_3", 23);
35                     break;
36             }
37             return result;
38         }
39     }
40 }
View Code

4.5 app1 MainActivity code:

 1 package com.example.superleeq.myapplication;
 2 import android.app.Activity;
 3 import android.content.ComponentName;
 4 import android.content.Context;
 5 import android.content.Intent;
 6 import android.content.ServiceConnection;
 7 import android.os.Bundle;
 8 import android.os.IBinder;
 9 import android.os.RemoteException;
10 import android.view.View;
11 import com.example.superleeq.myapplication.util.LogUtil;
12 import com.example.superleeq.myapplication2.IMyAidlInterface;
13 
14 public class MainActivity extends Activity implements ServiceConnection {
15 
16     final static String OTHER_PACKAGE = "com.example.superleeq.myapplication2";
17     final static String OTHER_SERVICE = "com.example.superleeq.myapplication2.MyService";
18     boolean isbinded;
19     IMyAidlInterface binder = null;
20 
21     @Override
22     protected void onCreate(Bundle savedInstanceState) {
23         super.onCreate(savedInstanceState);
24         setContentView(R.layout.activity_main);
25 
26         initView();
27     }
28 
29     private void initView() {
30         //bind Service
31         findViewById(R.id.activity_main_button1).setOnClickListener(new View.OnClickListener() {
32             @Override
33             public void onClick(View v) {
34                 Intent intent = new Intent();
35                 intent.setComponent(new ComponentName(OTHER_PACKAGE, OTHER_SERVICE));
36                 isbinded = bindService(intent, MainActivity.this, Context.BIND_AUTO_CREATE);
37             }
38         });
39         //unbind Service
40         findViewById(R.id.activity_main_button2).setOnClickListener(new View.OnClickListener() {
41             @Override
42             public void onClick(View v) {
43                 binder = null;
44                 if (isbinded) {
45                     unbindService(MainActivity.this);
46                     isbinded = false;
47                 } else {
48                     LogUtil.log("already unbindservice");
49                 }
50             }
51         });
52         //ipc app1 / app2
53         findViewById(R.id.setdata).setOnClickListener(new View.OnClickListener() {
54             @Override
55             public void onClick(View v) {
56                 if (binder != null) {
57                     try {
58                         LogUtil.log("------------------" + binder.getPerson(0));
59                         LogUtil.log("------------------" + binder.getPerson(1));
60                         LogUtil.log("------------------" + binder.getPerson(2));
61                         LogUtil.log("------------------" + binder.getPerson(0));
62                         LogUtil.log("------------------" + binder.getPerson(3));
63                         LogUtil.log("------------------" + binder.getPerson(4));
64                     } catch (RemoteException e) {
65                         e.printStackTrace();
66                     }
67                 }
68             }
69         });
70     }
71 
72     @Override
73     public void onServiceConnected(ComponentName name, IBinder service) {
74         binder = IMyAidlInterface.Stub.asInterface(service);
75     }
76 
77     @Override
78     public void onServiceDisconnected(ComponentName name) {
79         LogUtil.log("onServiceDisconnected ComponentName name = " + name);
80     }
81 }
View Code

 

5,常见报错

5.1 Android Studio AIDL 自定义类型找不到问题
http://blog.csdn.net/wuyuxing24/article/details/46948961
如果你也是像我一样的新手,也是刚开始接触AIDL,也是在网上找了一些关于AIDL的简单例子,也在Android Studio下面尝试去敲代码来测试这些例子。碰巧和我一样找到了一个保存Person信息的例子,AIDL有个接口传递的是自定义类型Person的参数。(如果我们没有改Android Studio默认的文件结构,新建aidl文件的时候Android Studio 帮我们建了一个aidl的文件夹,因为在使用aidl的时候客户端和服务器端包名也要完全一样我们为了方便直接复制整个aidl文件夹到客户端会把aidl文件和aidl接口中用到的自定义类型都放到这个文件中)。当我们一步一步的进行编译的时候会报aidl接口中用到的自定义类型的包找不到。解决办法如下,我是这么干的。在gradle文件中加    sourceSets {
        main {
            manifest.srcFile 'src/main/AndroidManifest.xml'
            java.srcDirs = ['src/main/java', 'src/main/aidl']
            resources.srcDirs = ['src/main/java', 'src/main/aidl']
            aidl.srcDirs = ['src/main/aidl']
            res.srcDirs = ['src/main/res']
            assets.srcDirs = ['src/main/assets']
        }
    }
把src/main/aidl文件也作为Java.srcDirs, resources.srcDirs。

5.2 inout
AIDL支持java.util.List和java.util.Map,但是有一些限制。集合中项的允许数据类型包括Java原始类型、String、CharSequence或是android.os.Parcelable。无需为List和Map提供import语句,但需要为Parcelable提供import语句。(list<>里可放String,char,Double就不行了)
 非原始类型中,除了String和CharSequence以外,其余均需要一个方向指示符。方向指示符包括in、out、和inout。in表示由客户端设置,out表示由服务端设置,inout表示客户端和服务端都设置了该值。

 

AIDL服务只支持有限的数据类型,因此,如果用AIDL服务传递一些复杂的数据就需要做更一步处理。AIDL服务支持的数据类型如下:

  • Java的简单类型(int、char、boolean等)。不需要导入(import)。

  • String和CharSequence。不需要导入(import)。

  • List和Map。接口中声明即是List Map顶层接口,不能用hashMap这种,但要注意,List和Map对象的元素类型必须是AIDL服务支持的数据类型。不需要导入(import)。

  • AIDL自动生成的接口。需要导入(import)。

  • 实现android.os.Parcelable接口的类。需要导入(import)。而且必须提供相应aidl。

posted @ 2016-04-18 22:28  superleeq  阅读(238)  评论(0)    收藏  举报