说到AIDL,每次就配套一个单词就是IPC,到底是怎么一回事,这事得从多进程说起。
有一天,我们写了一个类,类里面有一个静态变量。就像下面这样
public class UserBean {
public static int userCount=0;
}
原本的需求是这样的,通过这个User类的一个静态值,来全局共享一些用户信息,提供给A和B显示用,而这A和B是在两个独立的进程中(非线程)的,同时要求对这个数据有读写的能力。
关于如何开启多进程,估计很多程序是用不到的,因为他的场景不是很广泛,我们有可能是采用别的方案就避免掉了,例如广播之类的。
开启多进程的方法就是在我们的xml配置文件加多process属性,如下:
是不是很简单的感觉就可以开多进程了?
这里有一点需要注意的就是我们在名字前面的符号是什么,一个是“ : ”,另外一个是“. ”
两者导致的就是进程的名字不一样而已,同时如果以“:”开头,表示该进程为当前应用私有,和其他的组件是不会跑在同一个进程中的。后者是全局进程,可以和别的组件跑在同个进程,然后进行数据共享的。具体的内容以后再补充吧,说多有感觉跑远了。
现在假设我们先启动了A进程,然后设置值为1,接着启动B进程,打印数据,理论是等于1才对。
public class A{
UserBean.userCount=1;
}
public class B{
Log.e(TAG, "count="+UserBean.userCount);
}
但我们居然发现打印是0, 这可坏了,这是为啥呢?
我们很当然的要怀疑起这个多进程到底怎么了?
简单的说就是,在安卓上,多进程就代表了”同时运行多个同样的app“。
既然是两个同时运行的A和B,那两者想让就互补影响了。
不知有没映像,以前在诺基亚的塞班S60时代手机上有QQ共存版 ,同时运行多个QQ,每个QQ收到的数据是互不影响的,多进程大抵就是这种样子。
多进程带来的问题当然不知这些啦,我们的单例模式,线程同步等都显然形同虚设了,但需求还在那,我们需要把这事干了啊,那怎么办呢?
我们的不同进程要进行沟通解决啦,所以就有了这样那样的进程间进行通讯的机制(IPC)。
能做进程间通讯的常见的有基于Binder的messenger,AIDL和Socket。据闻基于binder的效率最高,具体怎么比出来的,我也没看过。另外还有SharedPreferences,ContentProvider,Bundle等
我们先写一个接口文件,用来给别的进程调用用的,这里我们提供一对get/set方法。
// UserManagerInterface.aidl
interface UserManagerInterface {
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
int getUserCount();
void setUserCount( in int n);
}
接着我们谷歌说的要求,写这么个独立的类,里面只有下面那个
// UserBean.aidl
package com.example.sanjay.myapplication.aidl;
parcelable UserBean;
最后我们再写一个简单的UserBean类
public class UserBean implements Parcelable {
public static int UserCount=0;
private String userName;
protected UserBean(Parcel in) {
userName = in.readString();
}
public static final Creator CREATOR = new Creator() {
@Override
public UserBean createFromParcel(Parcel in) {
return new UserBean(in);
}
@Override
public UserBean[] newArray(int size) {
return new UserBean[size];
}
};
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(userName);
}
}
然后为了我们的演示方便,我们在service里面加多一个类,如下,很简单,没什么特别要说的
public class AidlService extends Service {
private final UserManagerInterface.Stub mBidnerStub = new UserManagerInterface.Stub() {
@Override
public int getUserCount() throws RemoteException {
return UserBean.UserCount;
}
@Override
public void setUserCount(int n) throws RemoteException {
UserBean.UserCount = n;
}
};
public AidlService() {
}
@Override
public IBinder onBind(Intent intent) {
return mBidnerStub;
}
}
接着在我们的其中一个写下面的内容
public class MainActivity extends BaseActivity {
private static final String TAG = MainActivity.class.getSimpleName();
UserManagerInterface mService;
private ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
Log.e(TAG, "connect service");
mService = UserManagerInterface.Stub.asInterface(service);
try {
Log.e(TAG, "curUserCount=" + mService.getUserCount());
mService.setUserCount(2);
} catch (RemoteException e) {
e.printStackTrace();
}
}
public void onServiceDisconnected(ComponentName className) {
Log.e(TAG, "disconnect service");
mService = null;
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent intent = new Intent(this, AidlService.class);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
}
}
好了,核心的内容就这么点啦。基本都配置好了。
现在我们就可以做跨进程的通讯工作了。
由于时间限制,今天先写到这里,明天再补充