最近在学习IPC进程间通信,在此记录下AIDL的使用,并附上一个Demo:服务端每隔一分钟添加一本书籍,客户端通过进程间通信,获取当前服务端的书籍列表,并且服务端对外开放添加、删除等操作。
终于明白鸿洋所说的App效果图尽力的意思了!Android屏幕截图方法可参考:http://www.jianshu.com/p/9a1825e679b7
服务端:
1、新建一个AIDLServer工程,创建一个Parcelable接口类Book
package com.aa.aidlserver;
import android.os.Parcel;
import android.os.Parcelable;
public class Book implements Parcelable {
public String name;
public String describe;
public Book(String name, String describe) {
this.name = name;
this.describe = describe;
}
protected Book(Parcel in) {
name = in.readString();
describe = in.readString();
}
//反序列化
public static final Creator<Book> CREATOR = new Creator<Book>() {
@Override
public Book createFromParcel(Parcel in) {
return new Book(in);
}
@Override
public Book[] newArray(int size) {
return new Book[size];
}
};
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel parcel, int i) {
//序列化
parcel.writeString(name);
parcel.writeString(describe);
}
}
2、创建两个aidl文件:Book.aidl和IBookManager.aidl
// Book.aidl
package com.aa.aidlserver;
parcelable Book;
// IBookManager.aidl
package com.aa.aidlserver;
import com.aa.aidlserver.Book;
interface IBookManager {
//获取书本列表
List<Book> getBookList();
//添加书本
void addBook(in Book book);
//删除书本
void deleteBook(in Book book);
}
注意:
- 其中Book.aidl用来声明Book实现了Parcelable接口
- 因为在IBookManager中使用了Book参数,所以无论Book.java是否在同一个包名下,都必须进行一次import
3、创建自定义Service,创建一个IBookManager.Stub对象,即一个Binder对象,重写onBind方法返回这个对象。然后在AndroidManifest中声明此Service,并加入action
package com.aa.aidlserver;
import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
import android.support.annotation.Nullable;
import android.util.Log;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
public class AIDLService extends Service {
/**
* 书本列表
*/
private CopyOnWriteArrayList<Book> mBookList = new CopyOnWriteArrayList<>();
private Binder mBinder = new IBookManager.Stub() {
@Override
public List<Book> getBookList() throws RemoteException {
return mBookList;
}
@Override
public void addBook(Book book) throws RemoteException {
mBookList.add(book);
}
@Override
public void deleteBook(Book book) throws RemoteException {
mBookList.remove(0);
}
};
@Nullable
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if(mBookList.size() == 0) {
mBookList.add(new Book("他们最幸福", "一个屌丝写的书"));
mBookList.add(new Book("晓松奇谈", "矮大紧写的书"));
} else {
addBook();
}
return super.onStartCommand(intent, flags, startId);
}
/**
* 通过定时任务来添加书本信息
*/
private void addBook() {
Log.e("TAG", "Adding...");
int len = mBookList.size() + 1;
String name = "图书" + len;
String describe = "这是第" + len + "本书";
Book book = new Book(name, describe);
mBookList.add(book);
}
}
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.aa.aidlserver">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<service
android:name=".AIDLService"
android:process=":remote">
<intent-filter>
<action android:name="com.aa.aidlserver.AIDLService"/>
</intent-filter>
</service>
</application>
</manifest>
4、在MainActivity中使用AlarmManager每隔一分钟创建(打开)Service
package com.aa.aidlserver;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initAlarmManager();
}
/**
* 初始化定时任务
*/
private void initAlarmManager() {
Intent intent = new Intent();
// 设置Intent的Action 属性
intent.setAction("com.aa.aidlserver.AIDLService");
// Android 5.0以上需要设置包名
intent.setPackage("com.aa.aidlserver");
//创建一个PendingIntent对象,包含了startService操作
PendingIntent pi = PendingIntent.getService(this, 0,intent, PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager am = (AlarmManager) getSystemService(ALARM_SERVICE);
long intervalMillis = 60 * 1000;
//创建一个系统级定时器,即使熄屏状态也会每隔一分钟启动一次Service添加书本(注:部分定制系统定时器不准)
am.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), intervalMillis, pi);
}
}
5、在app的build.gradle文件的android节点中添加以下代码,可解决找不到Book类的问题
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']
}
}
至此服务端就开发完毕了,相比之下,客户端的就简单一些。
客户端:
1、新建一个AIDLClient工程,将AIDLServer工程的app\src\main\aidl目录拷贝到AIDLClient工程的app\src\main目录下,不需任何修改(注意这里的包名、文件都与AIDLServer是一致的)
2、服务端每隔一分钟会添加一本书,所以在客户端MainActivity中获取当前服务端书本列表并显示,也可进行添加、删除等操作
package com.aa.aidlclient;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ListView;
import android.widget.Toast;
import com.aa.aidlserver.Book;
import com.aa.aidlserver.IBookManager;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private ListView mListView;
private ArrayAdapter<String> mAdapter;
private List<String> mBooks = new ArrayList<>();
private Button btnLoadmore, btnAdd, btnDetele;
private IBookManager mIBookManager;
private ServiceConnection mServiceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
//Service已连接
mIBookManager = IBookManager.Stub.asInterface(iBinder);
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
//Service已断开
mIBookManager = null;
}
};
private void toast(String msg) {
Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();
Log.e("AA", "收到Log:" + msg);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mListView = (ListView) findViewById(R.id.lv_main);
btnLoadmore = (Button) findViewById(R.id.btn_main_loadmore);
btnLoadmore.setOnClickListener(this);
btnAdd = (Button) findViewById(R.id.btn_main_add);
btnAdd.setOnClickListener(this);
btnDetele = (Button) findViewById(R.id.btn_main_delete);
btnDetele.setOnClickListener(this);
bindAIDLService();
}
@Override
protected void onDestroy() {
unbindAIDLService();
super.onDestroy();
}
/**
* 绑定AIDL服务
*/
private void bindAIDLService() {
Intent intent = new Intent("com.aa.aidlserver.AIDLService");
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
// Android 5.0以上需要设置包名
intent.setPackage("com.aa.aidlserver");
bindService(intent, mServiceConnection, BIND_AUTO_CREATE);
}
/**
* 解绑AIDL服务
*/
private void unbindAIDLService() {
if(mIBookManager != null) {
unbindService(mServiceConnection);
}
}
@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.btn_main_loadmore:
//加载更多
try {
List<Book> books = mIBookManager.getBookList();
if(books != null && books.size() > 0) {
if(mBooks.size() > 0) {
mBooks.clear();
}
//解析数据
for(Book book : books) {
mBooks.add("Name:" + book.name + " --- Describe:" + book.describe);
}
//填充数据
mAdapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, android.R.id.text1, mBooks);
mListView.setAdapter(mAdapter);
}
} catch (RemoteException e) {
e.printStackTrace();
}
break;
case R.id.btn_main_add:
//新增图书
int len = mBooks.size() + 1;
String name = "图书" + len;
String describe = "这是第" + len + "本书";
Book book = new Book(name, describe);
try {
mIBookManager.addBook(book);
mBooks.add("Name:" + book.name + " --- Describe:" + book.describe);
mAdapter.notifyDataSetChanged();
} catch (RemoteException e) {
e.printStackTrace();
}
break;
case R.id.btn_main_delete:
//删除图书
if(mBooks.size() > 0) {
try {
Book book1 = mIBookManager.getBookList().get(0);
mIBookManager.deleteBook(book1);
mBooks.remove(0);
mAdapter.notifyDataSetChanged();
} catch (RemoteException e) {
e.printStackTrace();
}
} else {
toast("已经没有书可以删除了");
}
break;
}
}
}
3、客户端也需要在app的build.gradle文件的android节点中添加以下代码,解决找不到Book类的问题
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']
}
}
其实,AIDL说简单也不简单,难也并不难,还是需要根据实际需求来做的。