Service是android中在后台运行,不提供用户界面的一个组件。
Service可以有2种形式:启动的(Started)Service和绑定的(Bound)Service。
启动的Service是由一个组件(比如Activity)调用startService创建的,在后台独立行的组件(即使启动它的组件被销毁)。它并不返回运行结果。
绑定的Service可以在运行期间和进程内的其他组件(仅限于Activity,Content Provider, Service)进行交互,绑定的Service相当于一个服务器,调用它的组件相当于客户端,在运行期间客户端可以向Service发送请求,绑定,获取结果,还可以实现进程间通信(IPC)
一.启动的(Started)Service
1.创建和管理Service
创建一个Servcie:
1)创建一个类继承Service
public class MyService extends Service{
@Override
public void onCreate() {
Log.v("test","onCreate");
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.v("test","onStartCommand");
return START_NOT_STICKY;
}
@Override
public void onDestroy() {
Log.v("test","onDestroy");
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
}
2)在manifest文件中声明Servcie:
<manifest ... >
...
<application ... >
<service android:name="com.example.test.workspace1.app.MyService" />
...
</application>
</manifest>
启动Service:
在Activity或者其他组件中,可以通过Intent启动指定的Service
Intent intent = new Intent(this, MyService.class);
startService(intent);
停止Servcie:
可以在Activity或者其他组件中调用 stopService(Intent)或者在onStartCommand中调用 stopSelf()
2.生命周期和回调方法
在调用startService()方法后,如果service没有创建,则执行onCreate方法,之后执行onStartCommand方法。否则直接执行onStartCommand方法。当调用stopService或者stopSelf后,调用onDestory回调,然后销毁Servcie。
3.返回值
onStartCommand方法返回一个int值,这个返回值告诉系统应该怎么处理被系统关闭的Service,返回值可以是以下3个:
START_NOT_STICKY:当系统在onStartCommand返回后关闭Service后,不重新创建Service。
START_STICKY:当系统在onStartCommand返回后关闭Service,重新创建Service并且调用onStartCommand,但不重新传递上一个intent而是用null代替,除非用pendingIntent启动Service。
START_REDELIVER_INTENT:当系统在onStartCommand返回后关闭Service,重新创建Service并且调用onStartCommand,重新传递最新的ntent,pendingIntent按照顺序传递。这个返回值适用于后台操作需要恢复上一次的进度的情况。
4.使用IntentService
Service是运行在主线程中的,如果Servcie中有阻塞的操作,超过10秒的话会造成ANR。为避免这种情况发生,可以在Service中启用新的线程。或者继承IntentService类。
IntentService完成的工作:
1.创建一个单独的线程来执行 onStartCommand中的任务。
2.创建一个工作队列,每次将一个intent 传到onHandleIntent的实现中
3.提供一个 onStartCommand的默认实现,将intent送往工作队列,并由onHandleIntent处理
4.当所有任务完成后,自己调用 stopSelf
参照IntentService的源码:
public abstract class IntentService extends Service {
private volatile Looper mServiceLooper;
private volatile ServiceHandler mServiceHandler;
private String mName;
private boolean mRedelivery;
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
onHandleIntent((Intent)msg.obj);
stopSelf(msg.arg1);
}
}
public IntentService(String name) {
super();
mName = name;
}
public void setIntentRedelivery(boolean enabled) {
mRedelivery = enabled;
}
@Override
public void onCreate() {
super.onCreate();
HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
thread.start();
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}
@Override
public void onStart(Intent intent, int startId) {
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent;
mServiceHandler.sendMessage(msg);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
onStart(intent, startId);
return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
}
@Override
public void onDestroy() {
mServiceLooper.quit();
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
protected abstract void onHandleIntent(Intent intent);
在onCreate的时候创建了子线程,并用它的Looper对象创建一个handler用来接收任务请求,在onStartCommand中调用onStart发出handler请求Message中封装了请求的intent。在ServiceHandler这个内部类的Handler中的handleMessage里,调用onHandleIntent做具体的耗时操作,任务结束后,调用stopSelf结束Service。
使用IntentService要简单的多,实现自己的IntentService只需要2步:
1.重写构造方法。
2.实现onHandleIntent方法,耗时的操作写在onHandleIntent中。
public class HelloIntentService extends IntentService {
public HelloIntentService() {
super("HelloIntentService");
}
@Override
protected void onHandleIntent(Intent intent) {
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
二.绑定的(Bound)Service
当实现一个可供绑定的Service时,需要在Service中提供Ibinder接口。有三种方式可以提供Ibinder接口,分别是继承Binder类,使用Messenger,使用AIDL。
(一).继承Binder类。
如果需要绑定的Service对应用是私有的,并且不存在跨进程的通信情况,那么应该使用这种方式。
实现方式:
1.在Service类中,创建继承Binder的类,这个类包含返回当前Service实例的方法,或者返回其他组件可以调用的公共方法。
2.在 onBind()回调中返回Binder类的实例。
3.在绑定Service的组件中,实例化ServiceConnection,并且在ServiceConnection的onServiceConnected回调中获得Binder的实例,用它调用Service中的公共方法。
例子:
Service:
public class MyService extends Service{
private final IBinder mBinder = new LocalBinder();
private final Random mGenerator = new Random();
public class LocalBinder extends Binder {
MyService getService() {
return MyService.this;
}
}
//onBind方法返回Binder的实现类
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
//供其他组件调用的公共方法
public int getRandomNumber() {
return mGenerator.nextInt(100);
}
@Override
public void onCreate() {
Log.v("test","onCreate");
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.v("test","onStartCommand");
return START_NOT_STICKY;
}
@Override
public void onDestroy() {
Log.v("test","onDestroy");
}
}
LocalBinder 类是Binder的实现类,里面提供了getService方法返回这个Service的实例,绑定此Service的组件可以在ServiceConnection的onServiceConnected中,通过这个方法获取Service的实例,以调用其他公共方法。
Activity:
public class MainActivity extends ActionBarActivity {
private Button showNumber;
private MyService mService;
boolean mBound = false; //是否已经绑定了Service
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
showNumber = (Button) findViewById(R.id.showNumber);
showNumber.setOnClickListener(btnListener);
}
@Override
protected void onStart() {
super.onStart();
//绑定Service
Intent intent = new Intent(this, MyService.class);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
}
@Override
protected void onStop() {
super.onStop();
if (mBound) {
unbindService(mConnection);
mBound = false;
}
}
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
MyService.LocalBinder localBinder = (MyService.LocalBinder)iBinder;
mService = localBinder.getService();
mBound = true;
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
mBound = false;
}
};
private View.OnClickListener btnListener = new View.OnClickListener() {
@Override
public void onClick(View view) {
if (mBound) {
int num = mService.getRandomNumber();
Toast.makeText(MainActivity.this, "number: " + num, Toast.LENGTH_SHORT).show();
}
}
};
}
布局xml:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:paddingBottom="@dimen/activity_vertical_margin"
tools:context="com.example.test.workspace1.app.MainActivity">
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true">
<Button
android:id="@+id/showNumber"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="显示随机数"
android:layout_centerInParent="true"
/>
</RelativeLayout>
</RelativeLayout>
这个Activity在onStart的时候绑定了Service,在绑定期间,通过Service的实例,不断调用其getRandomNumber方法以获得不同的随机数。
(二)使用Messenger
如果Service需要和其他进程交互(IPC),可以使用Messenger为Service提供接口。
使用Messenger的概要:
1.在Service内部实现Handler,接受客户端请求,这个Handler作为实例化Messenger的构造方法的参数
2.在Service的onBind()回调中通过创建的Messenger对象返回IBinder对象的实例。
3.客户端用Ibinder实例作为参数实例化 Messenger,Messenger用来向Service发送消息,Service在Handler内部的 handleMessage方法中处理请求。
例子:
应用A的Service:
public class MessengerService extends Service{
//记录所有绑定的客户端数量
private ArrayList<Messenger> mClients = new ArrayList<Messenger>();
private int mValue = 0;
private static final int MSG_REGISTER_CLIENT = 1;
private static final int MSG_UNREGISTER_CLIENT = 2;
private static final int MSG_SET_VALUE = 3;
//这个handler接受客户端的请求
class IncomingHandler extends Handler {
//处理客户端的数据
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_REGISTER_CLIENT:
mClients.add(msg.replyTo);
break;
case MSG_UNREGISTER_CLIENT:
mClients.remove(msg.replyTo);
break;
case MSG_SET_VALUE:
mValue = msg.arg1;
for (int i = mClients.size()-1; i >= 0; i--) {
//向客户端发送客户端传来的最新数据
try {
mClients.get(i).send(Message.obtain(null, MSG_SET_VALUE, mValue, 0));
} catch (RemoteException e) {
mClients.remove(i);
e.printStackTrace();
}
}
break;
default:
super.handleMessage(msg);
}
}
}
//IncomingHandler作为Messenger的构造方法参数
final Messenger mMessenger = new Messenger(new IncomingHandler());
//onBind方法中通过创建的Messenger对象返回IBinder对象的实例
@Override
public IBinder onBind(Intent intent) {
Log.v("test","onBind");
return mMessenger.getBinder();
}
@Override
public void onCreate() {
Log.v("test","onCreate");
}
@Override
public void onDestroy() {
Log.v("test","onDestroy");
}
}
在这个Service内部实现了IncomingHandler,接受客户端请求,这个Handler作为实例化Messenger(mMessenger)的构造方法的参数。在handler中,当收到MSG_SET_VALUE的消息后,将这个值发送给所有绑定它的客户端。
应用A的Manifest文件:
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name=".MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name=".MessengerService" >
<intent-filter>
<action android:name="com.test.MessengerService" />
</intent-filter>
</service>
</application>
应用B的Activity:
public class MainActivity extends ActionBarActivity {
private Messenger mService = null;
private boolean mBound = false;
private TextView mCallbackText;
private static final int MSG_REGISTER_CLIENT = 1;
private static final int MSG_UNREGISTER_CLIENT = 2;
private static final int MSG_SET_VALUE = 3;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button bindBtn = (Button) findViewById(R.id.bind);
bindBtn.setOnClickListener(mBindListener);
Button unbindBtn = (Button) findViewById(R.id.unbind);
unbindBtn.setOnClickListener(mUnbindListener);
mCallbackText = (TextView)findViewById(R.id.text);
}
private View.OnClickListener mBindListener = new View.OnClickListener() {
public void onClick(View v) {
doBindService();
}
};
private View.OnClickListener mUnbindListener = new View.OnClickListener() {
public void onClick(View v) {
doUnbindService();
}
};
private void doBindService() {
Intent intent = new Intent("com.test.MessengerService");
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
mBound = true;
mCallbackText.setText("绑定.");
}
private void doUnbindService() {
if (mBound) {
if (mService != null) {
try {
//向Service发送解除绑定的消息
Message msg = Message.obtain(null, MSG_UNREGISTER_CLIENT);
msg.replyTo = mMessenger;
mService.send(msg);
} catch (RemoteException e) {
e.printStackTrace();
}
}
unbindService(mConnection);
mBound = false;
mCallbackText.setText("解除绑定.");
// msg = Message.obtain(null, MSG_SET_VALUE, this.hashCode(), 0);
// mService.send(msg);
}
}
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
mService = new Messenger(iBinder);
Toast.makeText(MainActivity.this, "与Service建立连接", Toast.LENGTH_SHORT).show();
try {
Message msg = Message.obtain(null, MSG_REGISTER_CLIENT);
msg.replyTo = mMessenger;
mService.send(msg);
//向Service发送一串字符
msg = Message.obtain(null, MSG_SET_VALUE, this.hashCode(), 0);
mService.send(msg);
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
mService = null;
Toast.makeText(MainActivity.this, "与Service断开连接", Toast.LENGTH_SHORT).show();
}
};
class IncomingHandler extends Handler {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_SET_VALUE:
mCallbackText.setText("service传递的数字: " + msg.arg1);
break;
default:
super.handleMessage(msg);
}
}
}
//与Service中初始化的方法一样
final Messenger mMessenger = new Messenger(new IncomingHandler());
}
MainActivity在绑定Service后,在onServiceConnected回调中通过new Messenger(iBinder);得到Service的Messenger对象,通过这个Messenger对象发送消息,Service的handler可以接收到请求并处理,同时在MainActivity中有个全局变量mMessenger,它初始化的方法和Service中是一样的。在onServiceConnected中将它赋值给Message对象的replyTo属性,通过Service的Messenger对象发送给Service的handler,这样Service中可以通过Activity发送过去的Messenger对象,向Activity发送请求,由Activity中的handler处理。
以上的Service和Activity在2个不同的APP中,它们完成的交互是:Activity将一段hashCode发送给绑定的Service,Service记录所有绑定自己的客户端,并且一旦收到最新的hashCode,就将他们发送给所有绑定的客户端,所有绑定的客户端中的Activity收到返回的hashCode后显示在TextView上。这样就通过Messenger对象,完成了2个不同进程收发消息的交互。
运行效果:
相比Messenger,AIDL适用于让多个APP同时访问你的Service进行通信的情况,一般的应用用不到AIDL,下篇单独写。
绑定Service的生命周期:
当Service在客户端调用bindService时是不会回调onStartCommand方法的,而是调用onBind,调用unbindService后,onUnbind方法回调,接下来是onDestroy。
当一个Service绑定了多个客户端时,只有所有的客户端调用unbindService后,Service才会销毁。
Service有2个回调方法 onRebind和 onUnbind,当onUnbind返回true时,客户端调用bindService时,Service会执行onRebind方法而不是onBind。