最近感觉自己越来越菜,感觉自己什么都懂一点点,什么也不会。于是决定静下心来学习学习。所以,从看开发艺术说起。今天重新看了看第二章,感觉有了不一样的收获。那么今天就来记录下。
Messenger,信使。
AIDL(Android Interface definition language),android接口定义语言。实现跨进程通讯的一种方式。
使用Messenger
我们来看个例子:
服务端Service,并将这个service开启到另一个进程
public class MessengerService extends Service {
public static final String TAG = "MessengerService";
public static class MessengerHandler extends Handler{
@Override
public void handleMessage(Message msg) {
switch (msg.what){
case 0: //来自客户端的消息
Log.e(TAG,"receive msg from Client"+msg.getData().getString("msg"));
Messenger client = msg.replyTo;
Message replyMessage = Message.obtain(null,1);
Bundle data = new Bundle();
data.putString("reply","hello ,i can shoudao you message");
replyMessage.setData(data);
try {
client.send(replyMessage);
} catch (RemoteException e) {
e.printStackTrace();
}
break;
}
}
}
private final Messenger mMessenger = new Messenger(new MessengerHandler());
@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
Log.e("tag","bind success");
return mMessenger.getBinder();
}
@Override
public void onCreate() {
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return super.onStartCommand(intent, flags, startId);
}
}
客户端Activity
public class MessengerActivity extends AppCompatActivity {
private static final String TAG = "MessengerActivity";
private Messenger mService;
private ServiceConnection conn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.e("tag","can ");
mService = new Messenger(service);
Message msg = Message.obtain(null,0);
Bundle data = new Bundle();
data.putString("msg","hello,this is client");
msg.setData(data);
msg.replyTo = mGetReplyMessenger;
try {
mService.send(msg);
} catch (RemoteException e) {
Log.e("tag","send msg errormessage:-->"+e.getMessage());
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
private Messenger mGetReplyMessenger = new Messenger(new MessengerHandler());
private static class MessengerHandler extends Handler{
@Override
public void handleMessage(Message msg) {
Log.e("tag","recive msg from service:"+msg.getData().getString("reply"));
}
}
private Button button;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_messenger);
button = (Button) findViewById(R.id.bind);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(MessengerActivity.this,MessengerService.class);
bindService(intent,conn, Context.BIND_AUTO_CREATE);
}
});
}
@Override
protected void onDestroy() {
unbindService(conn);
super.onDestroy();
}
}
如果还有不懂的,请看张鸿洋 或者看书。
使用AIDL
那么,接下来我就按照书上的内容来做一个demo。
首先将Book序列化
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 flags) {
out.writeInt(bookId);
out.writeString(bookName);
}
public static final Parcelable.Creator<Book> CREATOR = new ClassLoaderCreator<Book>() {
@Override
public Book createFromParcel(Parcel source, ClassLoader loader) {
return new Book(source);
}
@Override
public Book createFromParcel(Parcel in) {
return new Book(in);
}
@Override
public Book[] newArray(int size) {
return new Book[size];
}
};
private Book(Parcel in){
bookId = in.readInt();
bookName = in.readString();
}
@Override
public String toString() {
return String.format("[bookId:%s, bookName:%s]",bookId,bookName);
}
}
接着,创建IBookManager.aidl和Book.aidl,注意Book.aidl创建的时候创建个文件,起名交Book.aidl,若直接在as下创建AIDL文件,会提示以存在。
Book.aidl
package com.gl.android_yishu;
parcelabl
IBookManager.aidl,注意,要将除了一些基础类型以外的其他类型用import导进来
package com.gl.android_yishu;
// Declare any non-default types here with import statements
import com.gl.android_yishu.Book;
import com.gl.android_yishu.IOnNewBookArrivedListener;
interface IBookManager {
/** * 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);
List<Book> getBookList();
void addBook(in Book book);
void registerListener(IOnNewBookArrivedListener listener);
void unregisterListener(IOnNewBookArrivedListener listener);
}
IOnNewBookArrivedListener.aidl (监听器)
package com.gl.android_yishu;
// Declare any non-default types here with import statements
import com.gl.android_yishu.Book;
interface IOnNewBookArrivedListener {
void onNewBookArrived(in Book book);
}
将这个aidl文件创建好之后,rebuild,就会在build/source/aidl/debug 下面生成对应的java文件。我在这里不管文件的内容。(我会在后面学习Binder的时候记录)。
接下来看看service的写法。
public class BookManagerService extends Service {
private CopyOnWriteArrayList<Book> mBookList = new CopyOnWriteArrayList<Book>();
private RemoteCallbackList<IOnNewBookArrivedListener> mListener = new
RemoteCallbackList<IOnNewBookArrivedListener>();
private AtomicBoolean mIsServiceDestoryed = new AtomicBoolean(false);
private Binder mBinder = new IBookManager.Stub(){
@Override
public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {
}
@Override
public List<Book> getBookList() throws RemoteException {
return mBookList;
}
@Override
public void addBook(Book book) throws RemoteException {
mBookList.add(book);
}
@Override
public void registerListener(IOnNewBookArrivedListener listener) throws RemoteException {
mListener.register(listener);
}
@Override
public void unregisterListener(IOnNewBookArrivedListener listener) throws RemoteException {
mListener.unregister(listener);
}
};
@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
int check = checkCallingOrSelfPermission("com.gl.android_yishu.permission.ACCESS");
if (check == PackageManager.PERMISSION_DENIED){
Log.e("tag","权限认证失败");
}else{
Log.e("tag","onbind---->");
return mBinder;
}
return null;
}
@Override
public void onCreate() {
super.onCreate();
mBookList.add(new Book(0, "Android"));
mBookList.add(new Book(1,"IOS"));
new Thread(new ServiceWorker()).start();
}
private void onNewBookArrived(Book book) throws RemoteException {
mBookList.add(book);
int N = mListener.beginBroadcast();
Log.e("tag","onNewBookArrived , notify listeners" +N);
for (int i = 0; i < N; i++) {
IOnNewBookArrivedListener listener = mListener.getBroadcastItem(i);
listener.onNewBookArrived(book);
}
mListener.finishBroadcast();
}
private class ServiceWorker implements Runnable {
@Override
public void run() {
while (!mIsServiceDestoryed.get()){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
int bookId = mBookList.size()+1;
Book newBook = new Book(bookId,"new Book#"+bookId);
try {
onNewBookArrived(newBook);
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
}
}
代码不多,也不复杂。
int N = mListener.beginBroadcast();
Log.e("tag","onNewBookArrived , notify listeners" +N);
for (int i = 0; i < N; i++) { IOnNewBookArrivedListener listener = mListener.getBroadcastItem(i); listener.onNewBookArrived(book); }
mListener.finishBroadcast();
以begin开头,以finish结束。
我们来看下客户端的代码
public class MainActivity extends AppCompatActivity {
private Button messenger,aidl;
private Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
switch (msg.what){
case 1:
Log.e("tag","receive new book" + msg.obj);
break;
default:
break;
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
}
private ServiceConnection conn;
{
conn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
IBookManager bookManager = IBookManager.Stub.asInterface(service);
try {
service.linkToDeath(new IBinder.DeathRecipient() {
@Override
public void binderDied() {
bind();
}
},0);
} catch (RemoteException e) {
e.printStackTrace();
}
try {
List<Book> list = bookManager.getBookList();
Log.e("tag", "query book list,list type :" + list.getClass().getCanonicalName());
Log.e("tag", "query book list :" + list.toString());
bookManager.registerListener(mListener);
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
// bind();
}
};
}
private void initView() {
messenger = (Button) findViewById(R.id.messenger);
messenger.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(MainActivity.this, MessengerActivity.class);
startActivity(intent);
}
});
aidl = (Button) findViewById(R.id.AIDL);
aidl.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
bind();
}
});
}
private void bind() {
Intent intent = new Intent(MainActivity.this,BookManagerService.class);
bindService(intent,conn,Context.BIND_AUTO_CREATE);
}
private IOnNewBookArrivedListener mListener = new IOnNewBookArrivedListener.Stub(){
@Override
public void onNewBookArrived(Book book) throws RemoteException {
handler.obtainMessage(1,book).sendToTarget();
}
};
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
@Override
protected void onDestroy() {
unbindService(conn);
super.onDestroy();
}
}
没什么特别的。不过,下面一点需要注意:
Binder是可能会意外死亡的。我们可以通过重连来解决。
1.
try {
service.linkToDeath(new IBinder.DeathRecipient() {
@Override
public void binderDied() {
bind();
}
},0);
} catch (RemoteException e) {
e.printStackTrace();
}
bind()函数自己看。
2.在onServiceDisconnected()方法中重连
这2中方法的区别,第一种在客户端的Binder线程池中被毁掉,也就是说我们不能直接访问UI线程,而第二种则是在UI线程中被回调。
还有一点需要注意:客户端调用远程服务的方法,被调用的方法运行在服务端的Binder线程池中 ,同时,客户端线程会被挂起,那么,我们就不能再这个时候进行耗时操作。客户端的onServiceconnected()和onServiceDisconnected()方法都运行在UI线程中,所以我们也不能用来惊醒耗时操作。另外,由于服务端方法运行在Binder线程池中,本身就是耗时的,所以尽量不要开线程去进行异步任务。
最后,还有一种Binder验证的方法,就是在onTranscat()方法中进行认证。关于AIDL和Messenger,就这么多了。