而对于intentService,自己会自动new一条线程,所以我们一旦使用intentService,就可以不用自己new线程了。关于intentService与Service如和选择,官方的api是说多任务就选择Service。
Service的重难点还是在bindService绑定服务上。
下面重点分析bindService.
1.bindService基础
2.使用Messenger的IPC
3.使用AIDL的IPC
4.使用Transact的IPC
笔记
-
OK,学习Android从官方demo开始,一切皆在demo中
-
-
/************************************************************************************************************************************/
-
对binderService的理解
-
-
下面是Service的demo
-
-
public class LocalService extends Service {
-
/**
-
* Binder given to clients
-
* LocalBinder也就是Binder对象上转型为IBinder接口
-
*/
-
private final IBinder mBinder = new LocalBinder();
-
-
/**
-
* Random number generator
-
* 这个就不解释了
-
*/
-
private final Random mGenerator = new Random();
-
-
/**
-
* Class used for the client Binder. Because we know this service always
-
* runs in the same process as its clients, we don't need to deal with IPC.
-
* 重要的是这是一个内部类,显然,内部类可以访问外围类的成员与方法。
-
* 而Binder是实现了IBinder接口的一个类。
-
* IBinder又是onBind方法返回给Service的一个接口。其它组件如Activity与Service就是通过IBinder接口进行通信的。
-
* 所以通过onBind方法返回一个IBinder给Service,通过LocalBinder对象的getService()方法将IBinder返回给Activity
-
* 这样就形成这样的通信方式:Service-IBinder-Activity
-
*/
-
public class LocalBinder extends Binder {
-
LocalService getService() {
-
// Return this instance of LocalService so clients can call public methods
-
return LocalService.this;
-
}
-
}
-
-
/**
-
* 将Service与Activity通信的接口返回给Service
-
* @param intent
-
* @return
-
*/
-
@Override
-
public IBinder onBind(Intent intent) {
-
return mBinder;
-
}
-
-
/**
-
* 一个自定义的Service的方法,供内部类LocalBinder对象调用
-
* method for clients
-
* @return
-
*/
-
public int getRandomNumber() {
-
return mGenerator.nextInt(100);
-
}
-
}
-
-
-
下面是Activity的demo
-
-
public class BindingActivity extends Activity {
-
/**
-
* Service中一个内部类的对象,通过此对此对象课返回与Service通信的IBinder
-
*/
-
LocalService mService;
-
-
/**
-
* 标记是否绑定Service
-
*/
-
boolean mBound = false;
-
-
@Override
-
protected void onCreate(Bundle savedInstanceState) {
-
super.onCreate(savedInstanceState);
-
setContentView(R.layout.main);
-
}
-
-
@Override
-
protected void onStart() {
-
super.onStart();
-
/**
-
* Bind to LocalService
-
*/
-
Intent intent = new Intent(this, LocalService.class);
-
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
-
}
-
-
@Override
-
protected void onStop() {
-
super.onStop();
-
/**
-
* Unbind from the service
-
* 必须记得解绑
-
*/
-
if (mBound) {
-
unbindService(mConnection);
-
mBound = false;
-
}
-
}
-
-
/** Called when a button is clicked (the button in the layout file attaches to
-
* this method with the android:onClick attribute)
-
* 通过Service的内部类LocalBinder对象调用Service的方法,“简称通信”,哈哈!
-
*/
-
public void onButtonClick(View v) {
-
if (mBound) {
-
// Call a method from the LocalService.
-
// However, if this call were something that might hang, then this request should
-
// occur in a separate thread to avoid slowing down the activity performance.
-
int num = mService.getRandomNumber();
-
Toast.makeText(this, "number: " + num, Toast.LENGTH_SHORT).show();
-
}
-
}
-
-
/**
-
* Defines callbacks for service binding, passed to bindService()
-
* ServiceConnection对象mConnection是binderService的第二个参数
-
*/
-
private ServiceConnection mConnection = new ServiceConnection() {
-
-
/**
-
* 绑定service时回调
-
* @param className
-
* @param service
-
*/
-
@Override
-
public void onServiceConnected(ComponentName className,
-
IBinder service) {
-
/**
-
* We've bound to LocalService, cast the IBinder and get LocalService instance
-
* 获取IBinder建立与service的通信,这里说的IBinder不要误解,getService返回LocalBinder对象
-
* 而LocalBinder继承Binder
-
* 而Binder实现IBinder接口
-
*/
-
LocalBinder binder = (LocalBinder) service;
-
mService = binder.getService();
-
mBound = true;
-
}
-
-
/**
-
* 解绑service时回调
-
* @param arg0
-
*/
-
@Override
-
public void onServiceDisconnected(ComponentName arg0) {
-
mBound = false;
-
}
-
};
-
}
-
-
-
/************************************************************************************************************************************/
-
-
对Messenger(信使)的理解
-
-
正如上面对bindService的理解中,客户端是通过调用service的方法的方式进行通行的,而对于使用Messenger后,就不用回调method了。
-
实现进程集间的通信,可以用Messenger和AIDL,如果使用上面的对bindService的理解的demo似乎只是通过调用service的方法是实现单向的通行
-
如果我们的业务背景是,在同一个App中,实现进程间的通信,我们使用Messenger。如果在不同的App间的service进程间通信,我们使用AIDL
-
-
下面是使用Messenger的service Demo
-
-
public class MessengerService extends Service {
-
/** Command to the service to display a message */
-
static final int MSG_SAY_HELLO = 1;
-
-
/**
-
* Handler of incoming messages from clients.
-
*/
-
class IncomingHandler extends Handler {
-
@Override
-
public void handleMessage(Message msg) {
-
switch (msg.what) {
-
case MSG_SAY_HELLO:
-
Toast.makeText(getApplicationContext(), "hello!", Toast.LENGTH_SHORT).show();
-
break;
-
default:
-
super.handleMessage(msg);
-
}
-
}
-
}
-
-
/**
-
* Target we publish for clients to send messages to IncomingHandler.
-
*/
-
final Messenger mMessenger = new Messenger(new IncomingHandler());
-
-
/**
-
* When binding to the service, we return an interface to our messenger
-
* for sending messages to the service.
-
* 这段代码难以理解的是mMessenger.getBinder();
-
* 我们看看源码,Messenger类的代码很少,但是封装死了,不能深入看看
-
* public IBinder getBinder() {
-
* return mTarget.asBinder();
-
* }
-
* 而mTarget又是private final IMessenger mTarget;我们无法看到IMessenger源码
-
*
-
*/
-
@Override
-
public IBinder onBind(Intent intent) {
-
Toast.makeText(getApplicationContext(), "binding", Toast.LENGTH_SHORT).show();
-
return mMessenger.getBinder();
-
}
-
}
-
-
-
下面是service的Demo
-
-
public class ActivityMessenger extends Activity {
-
/** Messenger for communicating with the service. */
-
Messenger mService = null;
-
-
/** Flag indicating whether we have called bind on the service. */
-
boolean mBound;
-
-
/**
-
* Class for interacting with the main interface of the service.
-
*/
-
private ServiceConnection mConnection = new ServiceConnection() {
-
public void onServiceConnected(ComponentName className, IBinder service) {
-
// This is called when the connection with the service has been
-
// established, giving us the object we can use to
-
// interact with the service. We are communicating with the
-
// service using a Messenger, so here we get a client-side
-
// representation of that from the raw IBinder object.
-
mService = new Messenger(service);
-
mBound = true;
-
}
-
-
public void onServiceDisconnected(ComponentName className) {
-
// This is called when the connection with the service has been
-
// unexpectedly disconnected -- that is, its process crashed.
-
mService = null;
-
mBound = false;
-
}
-
};
-
-
public void sayHello(View v) {
-
if (!mBound) return;
-
// Create and send a message to the service, using a supported 'what' value
-
Message msg = Message.obtain(null, MessengerService.MSG_SAY_HELLO, 0, 0);
-
try {
-
mService.send(msg);
-
} catch (RemoteException e) {
-
e.printStackTrace();
-
}
-
}
-
-
@Override
-
protected void onCreate(Bundle savedInstanceState) {
-
super.onCreate(savedInstanceState);
-
setContentView(R.layout.main);
-
}
-
-
@Override
-
protected void onStart() {
-
super.onStart();
-
// Bind to the service
-
bindService(new Intent(this, MessengerService.class), mConnection,
-
Context.BIND_AUTO_CREATE);
-
}
-
-
@Override
-
protected void onStop() {
-
super.onStop();
-
// Unbind from the service
-
if (mBound) {
-
unbindService(mConnection);
-
mBound = false;
-
}
-
}
-
}
-
-
由于官方的demo只是把Activity的消息发送到service,并每有说明如何从service发送到Activity。下面把demo修改下为一个小的app demo便于理解
-
布局文件就不给出了
-
/**
-
* MainActivity.java
-
*/
-
package com.vibexie.servicemessenger;
-
-
import android.content.ComponentName;
-
import android.content.Context;
-
import android.content.Intent;
-
import android.content.ServiceConnection;
-
import android.os.Handler;
-
import android.os.IBinder;
-
import android.os.Message;
-
import android.os.Messenger;
-
import android.os.RemoteException;
-
import android.support.v7.app.ActionBarActivity;
-
import android.os.Bundle;
-
import android.view.Menu;
-
import android.view.MenuItem;
-
import android.view.View;
-
import android.widget.Button;
-
import android.widget.EditText;
-
-
-
public class MainActivity extends ActionBarActivity {
-
private Button button;
-
private EditText editText;
-
-
/**
-
* Messenger for communicating with the service.
-
* 负责向service发送Message
-
*/
-
Messenger mService = null;
-
-
/** Flag indicating whether we have called bind on the service. */
-
boolean mBound;
-
-
/**
-
* 理解为客户端的Messenger,负责接收Service返回的Message
-
*/
-
private Messenger clientMessenger=new Messenger(new Handler(){
-
@Override
-
public void handleMessage(Message msg) {
-
super.handleMessage(msg);
-
editText.setText(msg.obj.toString());
-
}
-
});
-
-
/**
-
* Class for interacting with the main interface of the service.
-
* 理解了bindService,这里就好理解了,不赘述
-
*/
-
private ServiceConnection mConnection = new ServiceConnection() {
-
public void onServiceConnected(ComponentName className, IBinder service) {
-
/**
-
* This is called when the connection with the service has been
-
*established, giving us the object we can use to
-
*interact with the service. We are communicating with the
-
*service using a Messenger, so here we get a client-side
-
*representation of that from the raw IBinder object.
-
*绑定Service接收消息的Messenger,以向service发送Message
-
*/
-
mService = new Messenger(service);
-
mBound = true;
-
}
-
-
public void onServiceDisconnected(ComponentName className) {
-
/**
-
*This is called when the connection with the service has been
-
*unexpectedly disconnected -- that is, its process crashed.
-
* 解绑时回调
-
*/
-
mService = null;
-
mBound = false;
-
}
-
};
-
-
@Override
-
protected void onCreate(Bundle savedInstanceState) {
-
super.onCreate(savedInstanceState);
-
setContentView(R.layout.activity_main);
-
-
button=(Button)this.findViewById(R.id.button);
-
editText=(EditText)this.findViewById(R.id.editText);
-
-
button.setOnClickListener(new View.OnClickListener() {
-
@Override
-
public void onClick(View v) {
-
if (!mBound) return;
-
/**
-
* Create and send a message to the service, using a supported 'what' value
-
* 一看到Message就要联系到Handler,我们写Messsge完全可以不按这样的方式写
-
* 这里的obtain为public static Message obtain(Handler h, int what, int arg1, int arg2);很好理解吧
-
*/
-
Message msg = Message.obtain(null, MessengerService.MSG_SAY_HELLO, 0, 0);
-
-
/**
-
* 设定msg消息将要返回到我们定义的客户端clientMessenger,这里将clientMessenger携带发送给service
-
*/
-
msg.replyTo=clientMessenger;
-
-
try {
-
/**
-
* 将Message发送给Service
-
*/
-
mService.send(msg);
-
} catch (RemoteException e) {
-
e.printStackTrace();
-
}
-
}
-
});
-
}
-
-
@Override
-
protected void onStart() {
-
super.onStart();
-
// Bind to the service
-
bindService(new Intent(this, MessengerService.class), mConnection,
-
Context.BIND_AUTO_CREATE);
-
}
-
-
@Override
-
protected void onStop() {
-
super.onStop();
-
// Unbind from the service
-
if (mBound) {
-
unbindService(mConnection);
-
mBound = false;
-
}
-
}
-
}
-
-
/**
-
* MessengerService.java
-
*/
-
package com.vibexie.servicemessenger;
-
-
import android.app.Service;
-
import android.content.Intent;
-
import android.os.Handler;
-
import android.os.IBinder;
-
import android.os.Message;
-
import android.os.Messenger;
-
import android.os.RemoteException;
-
import android.widget.Toast;
-
-
public class MessengerService extends Service {
-
/** Command to the service to display a message */
-
static final int MSG_SAY_HELLO = 11;
-
-
/**
-
* 对应Activity的clientMessenger
-
*/
-
private Messenger replyMessenger=null;
-
-
/**
-
* Handler of incoming messages from clients.
-
*/
-
class IncomingHandler extends Handler {
-
@Override
-
public void handleMessage(Message msg) {
-
switch (msg.what) {
-
case MSG_SAY_HELLO:
-
Toast.makeText(getApplicationContext(), "Service接收到11", Toast.LENGTH_SHORT).show();
-
-
/**
-
* 这里是回传Message给Activity的关键
-
* 首先从消息池中obtain,再包装消息发送个Activity
-
*/
-
Message replyMessage=Message.obtain();
-
replyMessage.obj="我接收到你的消息!";
-
/**
-
* 注意是msg调用replyTo方法,将replyMessager对应到客户端的clientMessenger
-
*/
-
replyMessenger=msg.replyTo;
-
try {
-
replyMessenger.send(replyMessage);
-
} catch (RemoteException e) {
-
e.printStackTrace();
-
}
-
-
break;
-
default:
-
super.handleMessage(msg);
-
}
-
}
-
}
-
-
/**
-
* Target we publish for clients to send messages to IncomingHandler.
-
*/
-
final Messenger mMessenger = new Messenger(new IncomingHandler());
-
-
/**
-
* When binding to the service, we return an interface to our messenger
-
* for sending messages to the service.
-
*/
-
@Override
-
public IBinder onBind(Intent intent) {
-
Toast.makeText(getApplicationContext(), "binding", Toast.LENGTH_SHORT).show();
-
return mMessenger.getBinder();
-
}
-
}
-
-
总结一下:
-
客户端和Service之间进行Message的交互大概是这样的模型
-
客户端 Service
-
clientMessenger* * mMessenger
-
* *
-
*
-
* *
-
mService* *replyMessenger
-
-
/************************************************************************************************************************************/
-
-
对AIDL的理解
- 在不同App间访问service即不同App进程间通信,我们就使用AIDL。这个相对用的少,因为很少需要与其它App进行交互
- 对AIDl的理解因为需要在一个demo中认识,所以笔记在下一篇