什么是Service
Service是运行于Android后台的程序操作,无用户交互界面。
创建一个服务,只需要继承android.app.Service类即可。而其中必须实现的方法只有一个
@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
}
若不实现该方法,将会抛出异常。该方法将返回一个IBinder对象。IBinder是一个Interface,因此,我们需要在Service中定义一个Binder类(该类实现了IBinder接口),并在onBinder中返回。而绑定Service的Activity可通过强行转换,获取自定义的Binder类。
当然,如果不想Service被绑定,可以不定义,返回null即可。
注:作为Android的四大组件,Service也需要在Manifest中进行声明。如果使用Android Studio的创建向导,声明将被自动添加。
<application
android:allowBackup="true"
android:label="@string/app_name"
android:supportsRtl="true">
<service
android:name=".myService"
android:enabled="true"
android:exported="true"></service>
</application>
注:enabled表示是否启用这个Service,exported表示该服务能否被其他程序访问。
Service中常用的监听方法
(1)public void onCreate()
Service是一个单例。当Service第一次被创建时,该方法被调用。
(2)public int onStartCommand(Intent intent, int flags, int startId)
当Service被启动时,该方法被调用。每个Service都可以被启动多次,因此,该方法可以被调用多次。
(3)public void onDestroy()
当Service被销毁时,该方法被调用。
(4)public IBinder onBind(Intent intent)
当Service被绑定时,该方法被调用。
(5)public boolean onUnbind(Intent intent)
当Service被解绑时,该方法被调用。
如何触发Service
(1)Start/Stop方式
启动Service
intent=new Intent(this, myService.class);
startService(intent);
若此时Service未创建,则将依次触发
myService
onCreate
onStartCommand
否则,仅触发
onStartCommand
停止服务
intent=new Intent(this, myService.class);
stopService(intent);
停止服务将会触发
onDestroy
onDestroy跟onCreate一样,仅被触发一次。
(2)Bind/Unbind方式
若Service提供多种服务,比如func1,func2,我们该如何调用呢?
此时startService/stopService方式便不能满足要求了。因此,我们通过绑定的方式,获取服务代理,该代理即为Binder。
(a)在自定义的Binder类当中实现func1,func2。
public class myBinder extends Binder {
private final String TAG=getClass().getName();
public void fun1(){
Log.i(TAG, "fun1: ");
}
public void fun2(){
Log.i(TAG, "fun2: ");
}
}
(b)当Activity绑定Service时,将自定义的Binder实例提通过onBind接口供给Activity。
public class myService extends Service {
private final String TAG=getClass().getName();
private myBinder m_Binder;
public myService() {
Log.i(TAG, "myService: Thread id = "+Thread.currentThread().getId());
m_Binder=new CalculateBinder();
}
@Override
public void onDestroy() {
m_Binder=null;
super.onDestroy();
}
@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
return m_Binder;
}
}
(c)ServiceConnection接口
绑定Service是异步操作,因此,需要回掉方法来通知Activity,是否已经与Service建立连接。
ServiceConnection m_servic eConnection=new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
m_Binder=(CalculateBinder) iBinder;
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
m_Binder=null;
}
};
若连接建立成功,onServiceConnected方法将会被触发,iBinder即为onBind方法返回的Service代理。
这里需要对onServiceDisconnected进行特殊说明。onServiceDisconnected方法仅在Service异常丢失(并非onDestroy)时触发。系统资源不足时,会对资源进行回收,而Service的优先级别并不高,因此可能触发Service的丢失情况。
(d)绑定Service
intent=new Intent(this, myService.class);
bindService(intent,m_serviceConnection, Context.BIND_AUTO_CREATE);
bindService将触发以下Service生命周期监听方法
onCreate
onBind
(e)解绑Service
unbindService(m_serviceConnection);
若在bindService前,Service未被启动,或未被多个Activity绑定,则unbindService将触发以下Service生命周期监听方法
onUnbind
onDestroy
若bindService前,Service已被启动,或被多个Activity绑定,则unbindService将仅触发onUnbind方法。
需要注意的是,即使startService()仅被调用了一次,stopService()也可被多次调用。但对于bindService和unbindService就不同了。bindService可被多次调用。unbindService仅能被调用一次。若多次调用,将引发异常。
java.lang.IllegalArgumentException: Service not registered: com.breakloop.servicedemo.MainActivity$1@2ebc9d4
Service的问题
问题来了~
(1)Service能否关闭自己?
当然可以!在需要的位置,调用stopSelf()即可。
(2)Service是否在主线程中?
主线程!可以在Activity和Service中分别打印当前线程ID,会发现两者相同。
Thread.currentThread().getId();
IntentService
由Activity来停止Service的运行,并不可取。因为当前Activity并不知道,Service是否还被其他调用者使用。同时,由于处于主线程,如果Service来处理耗时任务,则会造成ANR(Application No Response)。为了解决这两个问题,Android提供了IntentService。
(当然,也在Service中使用线程和连接计数器来规避这两个问题。)
IntentService使用非常方便。当任务完成后,会自动停止,且任务在子线程中执行。因此,跟AsynTask类似。
创建一个自定义的IntentService,仅需要继承android.app.IntentService,并实现抽象方法protected void onHandleIntent(Intent intent),该方法将在线程中完成所有任务。类似于AsynTask的doBackground。
public class myIntentService extends IntentService {
private final String TAG=getClass().getName();
public myIntentService() {
super("myIntentService");
}
@Override
protected void onHandleIntent(Intent intent) {
//TODO
Log.i(TAG, "onHandleIntent");
}
@Override
public void onCreate() {
Log.i(TAG, "onCreate");
super.onCreate();
}
@Override
public void onDestroy() {
Log.i(TAG, "onDestroy");
super.onDestroy();
}
}
IntentService需要使用startService类启动。
intent=new Intent(this,myIntentService.class);
startService(intent);
而启动后,将依次触发IntentService的以下生命周期监听方法。
onCreate
onHandleIntent
onDestroy
以上,都是在同一进程中的service访问方法。
当然,Service也可以跨进程访问,通常使用AIDL的方式。将在单独的篇幅中进行介绍。