进程通信(二、AIDL)
大家好,我是你们的技术草帽,如果有不懂的我们可以一起探讨。先吹一波!
这里是通信第二篇AIDL,这个AIDL一开始用起来可能会有一些麻烦,可之后你会爱上他的!我看到大部分的文章都是只有一个app在本地调用,这样其实没什么,因为本地调用和在两个app之间调用,是差不多的,可有些时候正是这一丝丝的差别,在你刚开始的时候也会抓瞎。所以今天咱们就拿两个app来说事,当然我也会把本地调用作出讲解
现在我们开始
图1是通过 AIDL调用图2中的科目
现在我们来一起看代码
public class Book implements Parcelable {
public int bookId;
public String bookName;
public Book() {
}
public Book(int bookId, String bookName) {
this.bookId = bookId;
this.bookName = bookName;
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel out, int i) {
out.writeInt(bookId);
out.writeString(bookName);
}
public static final Parcelable.Creator<Book> CREATOR = new Creator<Book>() {
@Override
public Book createFromParcel(Parcel in) {
return new Book(in);
}
@Override
public Book[] newArray(int i) {
return new Book[i];
}
};
private Book(Parcel in) {
bookId = in.readInt();
bookName = in.readString();
}
}
这是咱们的第一步 建类 。这里有个小知识点 ,在代码中可以看到我实现的Parcelable,你们可以去自行查找它和Serializable 的区别。
那么现在是第二步写AIDL接口,这步很简单,咱们就建一个AIDL文件,里面就一句代码
parcelable Book;
这里要注意的是文件所在包名必须是和咱们第一步建的类在相同包名下。最简单的就是把类所在包复制一下放在main文件夹下,然后把文件改成AIDL文件就好,里面内容改成上面那一句代码的样子。
第三步是在AIDL文件所在包下再建一个AIDL文件用来对咱们所建的AIDL类文件进行一个反射操作。里面代码也很简单
interface IManager {
List<Book> getBookList();
void addBook(in Book book);
}
当然这里的操作可以是任意操作 。
第四步就是make,对,你没看错,就需要make一下
前期的准备工作都已经完成了
第五步终于到了我们的调用,那调用大家要想一下,怎么调用?AIDL文件是需要AIDL文件来操作,那建的java类是不是也不用一个文件来进行操作,那还要满足客户端能够调用的,大家能够想到什么?当然是service;
service代码
public class ManagerService extends Service {
private CopyOnWriteArrayList<Book> bookList = new CopyOnWriteArrayList<>();
private Binder mBinder = new IManager.Stub(){
@Override
public List<Book> getBookList() throws RemoteException {
return bookList;
}
@Override
public void addBook(Book book) throws RemoteException {
bookList.add(book);
}
};
@Override
public void onCreate() {
super.onCreate();
bookList.add(new Book(1, "语文"));
bookList.add(new Book(2, "数学"));
bookList.add(new Book(4, "英语"));
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
}
第六步客户端调用,首先是内部调用:
public class ManagerActivity extends AppCompatActivity {
TextView tx1;
TextView tx2;
TextView tx3;
private ServiceConnection serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
IManager manager = IManager.Stub.asInterface(iBinder);
try {
List<Book> bookList = manager.getBookList();
Log.i(Config.LOG_TAG, bookList.toString());
manager.addBook(new Book(3, "化学"));
bookList = manager.getBookList();
Log.e(Config.LOG_TAG, ""+bookList.get(0).bookName);
Log.e(Config.LOG_TAG, ""+bookList.size());
tx1.setText(bookList.get(0).bookName);
tx2.setText(bookList.get(1).bookName);
tx3.setText(bookList.get(2).bookName);
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.aty_manager);
tx1 = findViewById(R.id.tx1);
tx2 = findViewById(R.id.tx2);
tx3 = findViewById(R.id.tx3);
Intent intent = new Intent(this, ManagerService.class);
bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);
}
@Override
protected void onDestroy() {
unbindService(serviceConnection);
super.onDestroy();
}
}
<service
android:name=".service.ManagerService"
android:process=":remote"
>
</service>
在清单文件里配置一下
这里要说一下 在进行bindService的时候要用显式调用,5.0以后都要用显式调用,隐式调用和显式调用的区别自行get。
接下来就是异地调用
public class AIDLActivity extends AppCompatActivity {
private IManager iManager;
private TextView mTv_result;
private EditText mEditText;
private boolean isConnSuccess;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_aidl);
mEditText = (EditText) findViewById(R.id.editText);
mTv_result = (TextView) findViewById(R.id.tv_result);
// 连接绑定远程服务
Intent intent = new Intent();
intent.setComponent(new ComponentName("lemon.pear.ipctest", "lemon.pear.ipctest.service.ManagerService"));
// intent.setAction("lemon.pear.ipctest.service");
// intent.setPackage("lemon.pear.ipctest");
// intent.setPackage("lemon.pear.ipctest.service");
isConnSuccess = bindService(intent, serviceConnection, BIND_AUTO_CREATE);
// isConnSuccess = bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);
}
public void search(View view){
if(isConnSuccess){
// 连接成功
int id = Integer.valueOf(mEditText.getText().toString());
try {
List<Book> bookList = iManager.getBookList();
String name = bookList.get(id).bookName;
mTv_result.setText(name);
}catch (RemoteException ex) {
ex.printStackTrace();
}
}else{
System.out.println("连接失败!");
}
}
private ServiceConnection serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
iManager = IManager.Stub.asInterface(iBinder);
try {
List<Book> bookList = iManager.getBookList();
Log.e("..", bookList.toString());
LogUtil.e("iManager"+iManager.getBookList().size());
bookList = iManager.getBookList();
Log.e("..", ""+bookList.size());
} catch (Exception e) {
e.printStackTrace();
LogUtil.e("Exception"+e);
}
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
}
};
public static void startAction(Activity activity) {
Intent intent = new Intent(activity, AIDLActivity.class);
activity.startActivity(intent);
activity.overridePendingTransition(R.anim.fade_in,
R.anim.fade_out);
}
@Override
protected void onDestroy() {
super.onDestroy();
unbindService(serviceConnection);
}
}
在bindService时要指定service所在app包名,app包名,app包名,然后指定service的具体路径
intent.setComponent(new ComponentName("lemon.pear.ipctest", "lemon.pear.ipctest.service.ManagerService"));
到这里就结束了,大家有不明白的可以发我邮箱[email protected]