Service是Android四大组件之一,与Activity的职责相反,Service一般在后台处理一些耗时任务,或者一直执行某个任务。
Service使用
新建一个计时Service。
public class TimerService extends Service {
private static String TAG = TimerService.class.getName();
private static final long LOOP_TIME = 1; //循环时间
private static ScheduledExecutorService mExecutorService;
@Override
public void onCreate() {
super.onCreate();
Log.d(TAG, "onCreate");
mExecutorService = Executors.newScheduledThreadPool(2);
mExecutorService.scheduleAtFixedRate(mRunnable, LOOP_TIME, LOOP_TIME, TimeUnit.SECONDS);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(TAG, "onStartCommand");
return super.onStartCommand(intent, flags, startId);
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
Log.d(TAG, "onBind");
return null;
}
@Override
public void onDestroy() {
Log.d(TAG, "onDestroy");
super.onDestroy();
mExecutorService.shutdown();
mExecutorService = null;
mRunnable = null;
}
private int count = 0;
private Runnable mRunnable = new Runnable() {
@Override
public void run() {
count++;
Log.d(TAG, "=== count:" + count);
}
};
}
四大组件都需要在manifest中注册
<service android:name=".service.TimerService"/>
声明Service的时候还有一些属性可以一起配置。需要的话
<service android:name=".service.TimerService"
android:enabled="true"
android:exported="true"
android:icon="@mipmap/ic_launcher"
android:label="string"
android:process="string"
android:permission="string"
>
<!--设置service优先级,最大1000-->
<intent-filter android:priority="100"/>
</service>
- 1
-
android:enabled 是否允许除了当前程序之外的其他程序访问这个服务
-
android:exported 是否启用这个服务
-
android:process 是否需要在单独的进程中运行,当设置为android:process=”:remote”时,代表Service在单独的进程中运行。注意“:”很重要,它的意思是指要在当前进程名称前面附加上当前的包名,所以“remote”和”:remote”不是同一个意思,前者的进程名称为:remote,而后者的进程名称为:App-packageName:remote。
-
android:permission 权限声明
我们知道Service的使用方式有两种,我们分别使用不同的方式进行使用。
1、使用startService()方法启动服务
Intent intent = new Intent(ServiceActivity.this, TimerService.class);
//使用Intent传值
intent.putExtra("key","value");
startService(intent);
启动任务,查看控制台我们输出的Log
TimerService: onCreate
TimerService: onStartCommand
TimerService: === count:1
TimerService: === count:2
......
可以看见,Service被创建,并且计时任务在后台执行。
如果我们不小心多点了次启动按钮,会发生什么事呢?会有两个计时任务一起执行么?我们将APP卸载重新运行可以试着多点几次启动,查看控制台输出日志:
TimerService: onCreate
TimerService: onStartCommand
TimerService: === count:1
TimerService: onStartCommand
TimerService: onStartCommand
TimerService: onStartCommand
TimerService: === count:2
......
从日志上可以看见,我们连续点击启动按钮启动服务,服务并不会重新创建 ,而是执行onStartCommand
方法,因为我们计时任务的初始化和启动都是放在onCreate
方法中的,所以不会启动多个计时任务。
停止服务
服务一旦启动,除非我们手动关闭服务,否则服务会一直在后台运行,直到系统资源不足的时候,系统主动杀死服务。
使用stopService
停止服务。
stopService(new Intent(ServiceActivity.this, TimerService.class));
控制台输出如下:
TimerService: onDestroy
所以使用startService
方式启动服务的service生命周期为:
oncreate --> onStartCommand --> onDestroy
- onCreate:服务创建的时候调用一次,如果已经创建了,则不会再调用。
- onStartCommand : 当通过startService() 启动服务时,系统将调用此方法。一旦执行此方法,服务即会启动并可在后台无限期运行。
- onDestroy:当服务不再使用且将被销毁时,系统将调用此方法。
多次启动服务会重复执行onStartCommand 方法。
2、使用bindService 绑定服务
bindService和startService的最大区别是,客户和服务绑定在一起了,客户可以通过binder获得Service实例,从而达到交互的目的。
bindService()方法有三个参数。Intent,ServiceConnection,flags
。
创建Intent和ServiceConnection
private ServiceConnection mServiceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder iBinder) {
Log.d("tag", "onServiceConnected");
}
@Override
public void onServiceDisconnected(ComponentName name) {
Log.d("tag", "onServiceDisconnected");
}
};
通过绑定服务启动服务和unbindService解绑服务
Intent intent = new Intent(ServiceActivity.this, TimerService.class);
//BIND_AUTO_CREATE 自动创建Service。
bindService(intent, mServiceConnection, BIND_AUTO_CREATE);
运行结果如下:
TimerService: onCreate
TimerService: onBind
//解除绑定
unbindService(mServiceConnection);
运行结果如下:
TimerService: onCreate
TimerService: onBind
TimerService: onUnbind
TimerService: onDestroy
可以看出通过bindService方式启动服务,完整生命周期方法为:
onCreate() --> onBind() --> onUnbind -->onDestroy()
此时我们的onBind方法返回的还是一个空的IBinder。
@Nullable
@Override
public IBinder onBind(Intent intent) {
Log.d(TAG, "onBind");
return null;
}
创建一个IBinder实例,返回此TimerService。
public class MyBinder extends Binder{
TimerService getService(){
return TimerService.this;
}
}
修改onBind返回值。在 onServiceConnected(ComponentName name, IBinder iBinder)
方法中通过IBinder 获得
private MyBinder mMyBinder = new MyBinder();
@Nullable
@Override
public IBinder onBind(Intent intent) {
Log.d(TAG, "onBind");
return mMyBinder;
}
修改mServiceConnection
,onServiceConnected方法中的IBinder对象就是上面onBinder()方法中返回的对象
private TimerService timerService;
private ServiceConnection mServiceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder iBinder) {
TimerService.MyBinder myBinder = (TimerService.MyBinder) iBinder;
timerService = myBinder.getService();
mCounterTv.setText(timerService.getCount() + "");
Log.d("tag", "onServiceConnected");
}
@Override
public void onServiceDisconnected(ComponentName name) {
Log.d("tag", "onServiceDisconnected");
}
};
再次执行bindService();运行结果如下
TimerService: onCreate
TimerService: onBind
D/tag: onServiceConnected
可以看出当service中的onBind()方法返回一个不为空的IBinder对象时,onServiceConnected
方法被执行,表示activity和service已经成功连接。我们也已经通过IBinder 成功获得TimerService对象实例,从而对service进行操作。
当我们通过两种方式启动同一个service,此时service的生命周期如何?
TimerService: onCreate
TimerService: onStartCommand
TimerService: onBind
D/ServiceActivity: onServiceConnected
TimerService: === count:1
D/ServiceActivity: 调用了stopService()
TimerService: === count:2
TimerService: === count:3
D/ServiceActivity: 调用了unbindService()
TimerService: onUnbind
TimerService: onDestroy
可以看到,当使用两种方式启动同一个服务时,只用一种方式是取消不了服务的,要同时调用stop和unbind方法才行