一、前言
上次我们从源码的角度分析了Service的两种状态下的工作过程,具体分析可查看Service的工作过程。在文章的最后引出了两个问题,其中一个是:
Activity和Service的交互,Service是本地的或者远程的,两者之间有什么区别?
为了分析上述两者的区别,我们新建了一个工程,增加了两个aidl文件,分别是Book.aidl、IBookManager.aidl。
Book.aidl:
// IBook.aidl
package com.hwldzh.myapplication.aidl;
// Declare any non-default types here with import statements
parcelable Book;
IBookManager.aidl:
// IBookManager.aidl
package com.hwldzh.myapplication.aidl;
import com.hwldzh.myapplication.aidl.Book;
// Declare any non-default types here with import statements
interface IBookManager {
List<Book> getBookList();
void addBookWithIn(in Book book);
}
并且增加了BookService.java和BookActivity.java。
BookService.java:
package com.hwldzh.myapplication.aidl;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
import android.support.annotation.Nullable;
import java.util.ArrayList;
import java.util.List;
/**
* Created by hwldzh on 2018/11/21
*/
public class BookService extends Service {
private List<Book> bookList = new ArrayList<>();
public BookService() {
Book bookAndroid = new Book("Android", 10);
bookList.add(bookAndroid);
}
IBookManager.Stub binder = new IBookManager.Stub() {
@Override
public List<Book> getBookList() throws RemoteException {
return bookList;
}
@Override
public void addBookWithIn(Book book) throws RemoteException {
}
};
@Nullable
@Override
public IBinder onBind(Intent intent) {
return binder;
}
}
BookActivity.java:
package com.hwldzh.myapplication.aidl;
import android.app.Activity;
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.annotation.Nullable;
import android.util.Log;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;
import com.mucfc.myapplication.R;
import java.util.List;
/**
* Created by hwldzh on 2018/11/21
*/
public class BookActivity extends Activity {
private IBookManager bookManager;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.book_layout);
Intent intent = new Intent(this, BookService.class);
bindService(intent, new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
bookManager = IBookManager.Stub.asInterface(service);
}
@Override
public void onServiceDisconnected(ComponentName name) {
bookManager = null;
}
}, BIND_AUTO_CREATE);
findViewById(R.id.add_book_in).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (bookManager != null) {
try {
Book book = new Book("JavaScript", 40);
bookManager.addBookWithIn(book);
Toast.makeText(BookActivity.this, "增加成功", Toast.LENGTH_SHORT).show();
Log.d("ABC", "book.Info=书名:" + book.getmBookName() + ", 价格:" + book.getmBookPrice());
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
});
findViewById(R.id.get_books).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (bookManager != null) {
List<Book> bookList = null;
try {
bookList = bookManager.getBookList();
} catch (RemoteException e) {
e.printStackTrace();
}
if (bookList != null) {
StringBuilder builder = new StringBuilder();
for (int i = 0; i < bookList.size(); i++) {
Book book = bookList.get(i);
builder.append("第" + (i + 1) + "本书,书名为:" + book.getmBookName() + ", 价格为:" + book.getmBookPrice() + "\n");
}
((TextView) findViewById(R.id.book_list)).setText(builder.toString());
}
}
}
});
}
}
二、本地Service
所谓本地Service,即Activity和Service处于同一个进程中。我们直接看Activity和Service绑定成功后,Service的onBind方法返回的IBinder对象:
bindService(intent, new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
bookManager = IBookManager.Stub.asInterface(service);
}
@Override
public void onServiceDisconnected(ComponentName name) {
bookManager = null;
}
}, BIND_AUTO_CREATE);
在ServiceConnection的onServiceConnected方法中,调用了IBookManager.Stub对象的asInterface方法。
IBookManager.Stub对象是什么???它就是上面的IBookManager.aidl经过build命令后生成的IBookManager的内部类,其中的asInterface方法如下:
public static com.mucfc.myapplication.aidl.IBookManager asInterface(android.os.IBinder obj) {
if ((obj==null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof com.mucfc.myapplication.aidl.IBookManager))) {
return ((com.mucfc.myapplication.aidl.IBookManager)iin);
}
return new com.mucfc.myapplication.aidl.IBookManager.Stub.Proxy(obj);
}
上面的代码中,调用了obj. queryLocalInterface方法,而obj就是Service传进来的IBinder对象。由于IBinder是一个接口,所以其中的queryLocalInterface方法由其实现类Binder来实现:
public @Nullable IInterface queryLocalInterface(@NonNull String descriptor) {
if (mDescriptor.equals(descriptor)) {
return mOwner;
}
return null;
}
上面代码传进来的参数DESCRIPTOR是IBookManager的一个静态不可变字符串,其内容为IBookManager类的包路径,保证了工程内的唯一性。
从BookService中可知,当Service为本地Service时,该Service的onBind方法返回的对象就是IBookManager.Stub对象,该对象的构造函数如下所示。
public Stub() {
this.attachInterface(this, DESCRIPTOR);
}
IBookManager.Stub对象调用了Binder类的attachInterface方法,并将自己和DESCRIPTOR字符串传递进去,如下所示。
public void attachInterface(@Nullable IInterface owner, @Nullable String descriptor) {
mOwner = owner;
mDescriptor = descriptor;
}
上面的代码逻辑将IBookManager的DESCRIPTOR字符串赋值给了mDescriptor对象,并将IBookManager.Stub对象赋值给mOwner对象。
这个时候,我们再回头看上面说到的queryLocalInterface方法,就知道了其返还的mOwer对象就是IBookManager.Stub对象,也就是在Service服务中创建的IBookManager.Stub对象。
这样,我们就能够在Activity中获取到Service创建的IBookManager.Stub对象,通过该对象就可以和Service进行交互。
三、远程Service
所谓远程Service,即该Service和Activity不在同一个进程中。这个时候Activity和Service的交互通信就是进程间的通信(IPC)。
Activity和Service绑定成功后,Service的onBind方法给我们返回了一个IBinder对象:
bindService(intent, new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
bookManager = IBookManager.Stub.asInterface(service);
}
@Override
public void onServiceDisconnected(ComponentName name) {
bookManager = null;
}
}, BIND_AUTO_CREATE);
在ServiceConnection的onServiceConnected方法中,调用了IBookManager.Stub对象的asInterface方法。这一步和上面本地Service的分析是一致的,其中IBookManager.Stub对象的asInterface方法如下:
public static com.mucfc.myapplication.aidl.IBookManager asInterface(android.os.IBinder obj) {
if ((obj==null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof com.mucfc.myapplication.aidl.IBookManager))) {
return ((com.mucfc.myapplication.aidl.IBookManager)iin);
}
return new com.mucfc.myapplication.aidl.IBookManager.Stub.Proxy(obj);
}
从本地Service的分析可得知,obj由于是一个远程进程传递过来的IBinder对象,所以其中的mDescriptor和本地的IBookManager的DESCRIPTOR是不相等的,即asInterface方法会走到最后一步,也就是new了一个IBookManager.Stub.Proxy对象,并将obj传递了过去,IBookManager.Stub.Proxy对象的构造函数如下:
private android.os.IBinder mRemote;
Proxy(android.os.IBinder remote)
{
mRemote = remote;
}
很简单的赋值操作,将传进来的IBinder对象进行了存储。
这样就完了吗???所谓的交互呢???
我们接着往下看,BookActivity中有一个获取书单的按钮,其逻辑为:
findViewById(R.id.get_books).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (bookManager != null) {
List<Book> bookList = null;
try {
bookList = bookManager.getBookList();
} catch (RemoteException e) {
e.printStackTrace();
}
if (bookList != null) {
StringBuilder builder = new StringBuilder();
for (int i = 0; i < bookList.size(); i++) {
Book book = bookList.get(i);
builder.append("第" + (i + 1) + "本书,书名为:" + book.getmBookName() + ", 价格为:" + book.getmBookPrice() + "\n");
}
((TextView) findViewById(R.id.book_list)).setText(builder.toString());
}
}
}
});
onClick方法中的bookManager对象是什么?就是上面分析的IBookManager.Stub.Proxy对象。好,它接着调用了getBookList方法,也就是IBookManager.Stub.Proxy对象的getBookList方法,如下所示。
@Override
public java.util.List<com.hwldzh.myapplication.aidl.Book> getBookList() throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
java.util.List<com.hwldzh.myapplication.aidl.Book> _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(Stub.TRANSACTION_getBookList, _data, _reply, 0);
_reply.readException();
_result = _reply.createTypedArrayList(com.hwldzh.myapplication.aidl.Book.CREATOR);
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
上面的代码中创建了两个Parcel对象,分别是_data、_reply,创建了一个List<com.hwldzh.myapplication.aidl.Book>对象——_result,然后调用了mRemote对象的transact方法,并将_data、_reply对象传递过去。上面分析到mRemote对象就是远程的IBinder对象,这里调用transact方法,会回调到远程IBinder对象的onTransact方法:
@Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException {
switch (code)
{
case INTERFACE_TRANSACTION:
{
reply.writeString(DESCRIPTOR);
return true;
}
case TRANSACTION_getBookList:
{
data.enforceInterface(DESCRIPTOR);
java.util.List<com.mucfc.myapplication.aidl.Book> _result = this.getBookList();
reply.writeNoException();
reply.writeTypedList(_result);
return true;
}
case TRANSACTION_addBookWithIn:
{
data.enforceInterface(DESCRIPTOR);
com.mucfc.myapplication.aidl.Book _arg0;
if ((0!=data.readInt())) {
_arg0 = com.mucfc.myapplication.aidl.Book.CREATOR.createFromParcel(data);
} else {
_arg0 = null;
}
this.addBookWithIn(_arg0);
reply.writeNoException();
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
而onTransact方法会根据不同方法的code值,将计算结果计算出来后,并回写到reply(Parcel类型)对象中。所以上面的getBookList方法通过远程Service返回的_reply参数就能获取到远程Service的BookList,从而实现了本地Activity和远程Service的交互。
上面我们只分析了Activity从远程Service获取数据的过程,而Activity传递数据给远程Service数据的过程是相类似的,所以就不再作分析。
网友评论