脑子里记了太多,最近感觉不太够用了,还是决定来CSDN给存起来,方便自己以后翻阅也便利别人,一点知识总结,如有错误各位过客可在评论区指出。
Service内容基本会在这章总结到,总结顺序如下:
* 按启动方式分类:通过Context.startService()或Context.bindService启动(顺带讲到Service与Thread区别)
* 按寄存方式分类:本地服务,远程服务(讲到使用AIDL进行进程间通信)
* 按运行方式分类:前台服务,后台服务
4.IntentService使用和源码分析
什么是Service,相信大家应该不会陌生了,Service是Android四大组件之一,是一个可以在后台长时间运行操作而没有用户界面的应用组件,服务可由其他应用组件启动(如Activity),服务可以处理网络事务、播放音乐,执行文件 I/O 或与内容提供程序交互,而所有这一切均可在后台进行,即使我们的APP已经退出桌面了。Service没有界面与用户交互,但是也可以为Service添加界面,后面娓娓道来。
Service知识总结(相关代码请移步https://github.com/Mangosir/ServiceReview/tree/master)
onCreate:当用Context.startService,Context.bindService启动服务时,会回调onCreate,在整个生命周期中,只会回调一次。也是生命周期方法中第一个被回调的,系统将调用次方法来执行一次性设置程序
onStartCommand:用Context.startService启动Service会回调这个方法,每次启动都会回调,Context.bindService启动Service不会回调这个方法。
onBind:Context.bindService启动Service回调这个方法,启动者可通过该方法返回对象来对Service对象进行操控。
onReBind:当使用startService启动Service,又调用bindService启动Service,且 onUnbind 返回值为 true 时,下次再次调用 Context.bindService 将触发方法。
onUnBind:用 Context.unbindService 触发此方法,默认返回 false, 当返回值 true 后,再次调用 Context.bindService 时将触发 onRebind 方法。
onDestory:1.以Context.startService启动service,调用Context.stopService停止服务回调此方法;2.以Context.bindService启动service,以Context.unbindService停止服务回调此方法;3.先以Context.startService 启动服务,再用Context.bindService绑定服务,结束时必须先调用Context.unbindService解绑再使用Context.stopService停止service才会回调此方法,否则会报错。这里做一些资源释放操作
(onStart方法已经过时,这里就不再赘述)
第一类:通过Context.startService()启动,调用Context.stopService()停止服务。
第二类:通过Context.bindService启动service,以Context.unbindService停止服务。
第一类:
新建一个ServiceDemo类继承Service类,如下
public class ServiceDemo extends Service{
private String TAG = "ServiceDemo";
@Nullable
@Override
public IBinder onBind(Intent intent) {
Log.e(TAG,"onBind");
return null;
}
@Override
public void onCreate() {
super.onCreate();
Log.e(TAG,"onCreate ");
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.e(TAG,"onStartCommand");
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
super.onDestroy();
Log.e(TAG,"onDestroy");
}
}
然后在MainActivity的布局中添加两个按钮,一个启动服务,一个停止服务
然后在监听方法中启动服务:
public class MainActivity extends AppCompatActivity {
private String TAG = "MainActivity";
@Bind(R.id.start)TextView start;
@Bind(R.id.stop)TextView stop;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.bind(this);
}
@OnClick(R.id.start)
public void start() {
Intent intent = new Intent(this, ServiceDemo.class);
startService(intent);
}
@OnClick(R.id.stop)
public void stop() {
Intent intent = new Intent(this, ServiceDemo.class);
stopService(intent);
}
@Override
protected void onDestroy() {
super.onDestroy();
ButterKnife.unbind(this);
}
}
Intent intent = new Intent(this, ServiceDemo.class);
startService(intent);
这里用到了ButterKnife注解框架,这里先不做过多解释,以后再出一篇使用详述。
这里可以看到当点击按钮启动Service时,log日子打印结果是
11-06 11:03:58.192 6941-6941 E/ServiceDemo: onCreate
11-06 11:03:58.192 6941-6941 E/ServiceDemo: onStartCommand
当多次点击启动按钮,日志打印结果是
11-06 11:03:58.192 6941-6941 E/ServiceDemo: onCreate
11-06 11:03:58.192 6941-6941 E/ServiceDemo: onStartCommand
11-06 11:05:20.231 6941-6941 E/ServiceDemo: onStartCommand
11-06 11:05:20.690 6941-6941 E/ServiceDemo: onStartCommand
11-06 11:05:20.958 6941-6941 E/ServiceDemo: onStartCommand
11-06 11:05:21.262 6941-6941 E/ServiceDemo: onStartCommand
11-06 11:05:21.529 6941-6941 E/ServiceDemo: onStartCommand
启动总结:
从这可以看出,一个Service是可以多次启动的,但是onCreate只会回调一次,而onStartCommand是启动一次就回调一次。所以如果你的Service有多次启动的可能性的话,有一些初始化的操作就放在onCreate里,避免无故开辟内存。但是onStartCommand方法却可以回调多次,我们先看onStartCommand这个方法是有返回值的并且是我们开发者可以控制返回什么值。我们知道当系统内存是有限的,当系统内存资源不足,Service是会被销毁的,如果你在Service里做了什么重要事情,那被销毁显然是你不愿意看到的,所以要有一种方法让系统帮我们重启该服务,那要不要重启就由这个返回值决定了,看下方:
如果把返回值设置成START_STICKY和START_REDELIVER_INTENT,这样就可以处于不死状态了(这样做其实是不好的)还有一种情况是用户主动在设置界面把你的Service给杀死,但是这会回调onDestroy,你可以在这里发送广播重新启动。
onStartCommand()第二个输入参数flags正是代表此次onStartCommand()方法的启动方式,正常启动时,flags默认为0,被kill后重新启动,参数分为以下两种:
好,我们继续往下说,当我们点击按钮停止服务时
Intent intent = new Intent(this, ServiceDemo.class);
stopService(intent);
此时log打印为
11-06 11:20:48.120 6941-6941 E/ServiceDemo: onDestroy
也就是回调了onDestroy,在这里做一些释放内存的事情。
注意了,服务可以多次启动,但是停止只能停一次,还有服务必须在AndroidManifest.xml里注册:
如果以这种方式启动服务,服务就会在后台无限期运行,即使启动的Activity被销毁了,也不会对Service有任何影响;除非手动调用stopService,服务才会停止
总结使用步骤:
第二类:
新建ServiceDemo2类继承Service类
public class ServiceDemo2 extends Service{
private String TAG = "ServiceDemo";
private MyBind myBind;
@Override
public void onCreate() {
super.onCreate();
Log.e(TAG,"onCreate");
myBind = new MyBind();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.e(TAG,"onStartCommand");
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
super.onDestroy();
Log.e(TAG,"onDestroy");
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
Log.e(TAG,"onBind");
return myBind;
}
@Override
public void onRebind(Intent intent) {
super.onRebind(intent);
Log.e(TAG,"onRebind");
}
@Override
public boolean onUnbind(Intent intent) {
Log.e(TAG,"onUnbind");
return super.onUnbind(intent);
}
public class MyBind extends Binder {
public void beginDown() {
Log.e(TAG,"begin");
down();
}
}
private void down() {
Log.e(TAG,"down");
}
}
然后在布局里加两个按钮一个绑定服务,一个解绑服务,然后在MainActivity里进行操作
public class MainActivity extends AppCompatActivity {
private String TAG = "MainActivity";
@Bind(R.id.bind)TextView bind;
@Bind(R.id.unBind)TextView unBind;
private ServiceDemo2.MyBind myBind;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.bind(this);
// thread id = " + Thread.currentThread().getId() + ",thread name = " + Thread.currentThread().getName()
Log.e(TAG,"onCreate");
}
@OnClick(R.id.bind)
public void bind() {
bind.setText("绑定成功");
unBind.setText("解绑服务");
Intent intent = new Intent(this, ServiceDemo2.class);
bindService(intent,connection,BIND_AUTO_CREATE);
}
@OnClick(R.id.unBind)
public void unBind() {
bind.setText("绑定服务");
unBind.setText("解绑成功");
unbindService(connection);
}
private ServiceConnection connection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
myBind = (ServiceDemo2.MyBind) service;
//这里就可以调用Service类的方法了
myBind.beginDown();
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
@Override
protected void onDestroy() {
super.onDestroy();
ButterKnife.unbind(this);
}
}
看启动方式:
Intent intent = new Intent(this, ServiceDemo2.class);
bindService(intent,connection,BIND_AUTO_CREATE);
我们先介绍下这三个参数:
就这样Service就运行起来了,
看下log日志:
11-06 14:24:55.982 7123-7123 E/ServiceDemo: onCreate
11-06 14:24:55.985 7123-7123 E/ServiceDemo: onBind
11-06 14:24:55.987 7123-7123 E/MainActivity: onServiceConnected
11-06 14:24:55.987 7123-7123 E/ServiceDemo: begin
11-06 14:24:55.987 7123-7123 E/ServiceDemo: down
也就是服务一绑定,会执行onCreate,再回调onBind,最后会走到ServiceConnection类的onServiceConnected中。
再调用解绑服务:
11-06 14:37:55.575 14517-14517 E/ServiceDemo: onUnbind
11-06 14:37:55.576 14517-14517 E/ServiceDemo: onDestroy
总结使用步骤:
注意:
1.本地服务 (Local Service): 寄存于当前的进程当中,当前进程结束后 Service 也会随之结束;因为处于同一个进程当中,所以Service 可以随时与 Activity 等多个部件进行通信,不需要IPC和AIDL;Service服务不会自动启动线程,如果没有人工调用多线程方式进行启动,Service将寄存于主线程当中。
2.远程服务 (Remote Service ): 独立寄存于另一进程中, 服务常驻后台,通过 AIDL (Android Interface Definition Language)接口定义语言,实现Android设备上的两个进程间通信(IPC)。
本地服务:
我们先打开MainActivity,在onCreate里打一个显示当前线程的log,
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.bind(this);
Log.e(TAG,"onCreate thread id = " + Thread.currentThread().getId() + ",thread name = " + Thread.currentThread().getName() );
}
再看日志,表明当前Activity运行在主线程
11-06 15:31:22.269 32438-32438 E/MainActivity: onCreate thread id = 1,thread name = main
再启动Service,在onCreate里加个log
@Override
public void onCreate() {
super.onCreate();
Log.e(TAG,"onCreate thread id = " + Thread.currentThread().getId() + ",thread name = " + Thread.currentThread().getName());
}
再在MainActivity里启动服务(用bindService是一样的)
Intent intent = new Intent(this, ServiceDemo2.class);
startService(intent);
看日志
11-06 15:31:23.645 32438-32438 E/ServiceDemo2: onCreate thread id = 1,thread name = main
11-06 15:31:23.647 32438-32438 E/ServiceDemo2: onStartCommand
这就可以看出来Service与Activity运行在同一个main线程,这就是本地服务了。
远程服务:
讲远程服务的时候先讲一下Service在Androidmanifest里的android:process配置属性,这个是表示这个Service是否在另一个进程中运行,不设置默认为本地服务,设置为:remote就为远程服务。那如何将远程服务用起来呢,请看下方:
由于远程服务涉及到AIDL进程间通信,以及两个进程间简单数据和复杂类型数据传递,篇幅较大,就不在这叙述了,请看博主另一篇文章http://blog.csdn.net/qq_30993595/article/details/78481716
前台Service和后台Service(普通)最大的区别就在于:
来看看前台Service什么样,新建一个类ServiceDemo3继承Service:
public class ServiceDemo3 extends Service{
private String TAG = "ServiceDemo3";
@Nullable
@Override
public IBinder onBind(Intent intent) {
Log.e(TAG,"onBind");
return null;
}
@Override
public void onCreate() {
super.onCreate();
Log.e(TAG,"onCreate ");
//添加下列代码将后台Service变成前台Service
//构建点击通知栏后打开MainActivity的Intent对象
// 在API11之后构建Notification的方式
Intent nfIntent = new Intent(this, MainActivity.class);
PendingIntent pendingIntent = getActivity(this,0,nfIntent,0);
Notification.Builder builder = new Notification.Builder(getApplicationContext()); //获取一个Notification构造器
builder .setContentIntent(pendingIntent) // 设置PendingIntent
.setLargeIcon(BitmapFactory.decodeResource(this.getResources(), R.mipmap.ic_launcher)) // 设置下拉列表中的图标(大图标)
.setContentTitle("前台服务") // 设置下拉列表里的标题
.setSmallIcon(R.mipmap.ic_launcher) // 设置状态栏内的小图标
.setContentText("显示的内容") // 设置上下文内容
.setWhen(System.currentTimeMillis()); // 设置该通知发生的时间
Notification notification = builder.build(); // 获取构建好的Notification
notification.defaults = Notification.DEFAULT_SOUND; //设置为默认的声音
// 参数一:唯一的通知标识;参数二:通知消息。
startForeground(110, notification);// 让Service变成前台Service,并在系统的状态栏显示出来
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.e(TAG,"onStartCommand");
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
// 停止前台服务--参数:表示是否移除之前的通知
stopForeground(true);
super.onDestroy();
Log.e(TAG,"onDestroy");
}
}
在onCreate方法中构建一个通知Notification,这样在MainActivity里就可以启动服务了
Intent intent = new Intent(this, ServiceDemo3.class);
startService(intent);
这样就是一个前台服务了,当然这个显示通知这个代码你可以放在你自己具体的逻辑里。
后台服务就不多叙述了,把通知这段代码去掉再启动这个服务就是一个后台服务了。
IntentService是Service的一个子类,它可以自己处理异步请求,在它内部有一个工作线程来处理耗时请求,可以启动IntentService多次,每个耗时操作会以队列的方式在onHandlerIntent方法中回调处理,每次只会执行一个工作线程,全部处理完,IntentService会自动结束,不需要开发者去结束。
先来个IntentService的简单使用,然后再分析源码:
先新建一个类ServiceDemo4
public class ServiceDemo4 extends IntentService{
private String TAG = "ServiceDemo4";
public ServiceDemo4() {
//调用父类的构造函数 构造函数参数=工作线程的名字
super("ServiceDemo4");
Log.e(TAG,"ServiceDemo4");
}
@Override
public void onCreate() {
super.onCreate();
Log.e(TAG,"onCreate");
}
@Override
public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
Log.e(TAG,"onStartCommand");
return super.onStartCommand(intent, flags, startId);
}
@Override
protected void onHandleIntent(@Nullable Intent intent) {
Log.e(TAG,"onHandleIntent intent = " + intent.getStringExtra("params") + " thread id = " + Thread.currentThread().getId() + ",name = "+Thread.currentThread().getName());
}
@Override
public void onDestroy() {
super.onDestroy();
Log.e(TAG,"onDestroy");
}
}
在配置文件里注册服务
在MainActivity里启动服务
@OnClick(R.id.start)
public void start() {
Intent intent = new Intent(this, ServiceDemo4.class);
intent.putExtra("params","thread");
startService(intent);
}
我们先来看下日志:
11-07 11:17:12.657 18996-18996 E/MainActivity2: onCreate thread id = 1,name = main
11-07 11:17:35.215 18996-18996 E/ServiceDemo4: ServiceDemo4
11-07 11:17:35.217 18996-18996 E/ServiceDemo4: onCreate
11-07 11:17:35.217 18996-18996 E/ServiceDemo4: onStartCommand
11-07 11:17:35.218 18996-19347 E/ServiceDemo4: onHandleIntent intent = thread thread id = 613,name = IntentService[ServiceDemo4]
11-07 11:17:35.222 18996-18996 E/ServiceDemo4: onDestroy
当我再次点击启动任务按钮,日志如下:
11-07 11:21:50.631 18996-18996 E/ServiceDemo4: ServiceDemo4
11-07 11:21:50.632 18996-18996 E/ServiceDemo4: onCreate
11-07 11:21:50.633 18996-18996 E/ServiceDemo4: onStartCommand
11-07 11:21:50.633 18996-21742 E/ServiceDemo4: onHandleIntent intent = thread thread id = 614,name = IntentService[ServiceDemo4]
11-07 11:21:50.634 18996-18996 E/ServiceDemo4: onDestroy
可以得出
再来写个模拟耗时操作例子,第一次startService,IntentService还在onHandleIntent异步处理请求,没处理完再次startService,再次发一个耗时请求过去:
public class ServiceDemo4 extends IntentService{
private String TAG = "ServiceDemo4";
private LocalBroadcastManager mBroadcastManager;
private boolean isRunning = true;
private boolean isRunning_again = true;
private int progress = 0;
private int progress_again = 0;
public ServiceDemo4() {
//调用父类的构造函数 构造函数参数=工作线程的名字
super("ServiceDemo4");
Log.e(TAG,"ServiceDemo4");
}
@Override
public void onCreate() {
super.onCreate();
Log.e(TAG,"onCreate");
//切记不要在构造方法里实例化这个本地广播,因为获取不到context作为参数
mBroadcastManager = LocalBroadcastManager.getInstance(this);
}
@Override
public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
Log.e(TAG,"onStartCommand");
return super.onStartCommand(intent, flags, startId);
}
@Override
protected void onHandleIntent(@Nullable Intent intent) {
Log.e(TAG,"onHandleIntent intent = " + intent.getStringExtra("params") + " thread id = " + Thread.currentThread().getId() + ",name = "+Thread.currentThread().getName());
String parma = intent.getStringExtra("params");
if (!TextUtils.isEmpty(parma)) {
switch (parma) {
case "thread" :
//当请求为 thread 类型时,模拟下载进度回调,每隔2s加1,然后通过本地广播发出去;
isRunning = true;
while (isRunning) {
progress++;
if (progress>=5) {
isRunning = false;
}
sendThreadStatus(ACTION_THREAD,progress);
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
break;
case "thread_again" :
//当请求为 thread_again 类型时,模拟下载进度回调,每隔2s加1,然后通过本地广播发出去;
isRunning_again = true;
while (isRunning_again) {
progress_again++;
if (progress_again>=5) {
isRunning_again = false;
}
sendThreadStatus(ACTION_THREAD_AGAIN,progress_again);
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
break;
}
}
}
// 发送线程结果
private void sendThreadStatus(String action, int progress) {
Log.e(TAG,"action="+action+",progress="+progress);
Intent intent = new Intent(action);
intent.putExtra("progress", progress);
mBroadcastManager.sendBroadcast(intent);
}
@Override
public void onDestroy() {
super.onDestroy();
Log.e(TAG,"onDestroy");
}
}
这里是在onHandleIntent里模拟耗时请求,获得结果后通过本地广播发出去,然后在MainActivity接受广播进行更新UI
public class MainActivity2 extends AppCompatActivity {
private static String TAG = "MainActivity2";
public final static String ACTION_THREAD = "com.mango.thread";
public final static String ACTION_THREAD_AGAIN = "com.mango.thread_again";
@Bind(R.id.msg)TextView msg;
@Bind(R.id.msg_again)TextView msg_again;
private LocalBroadcastManager mBroadcastManager;
private MyBoradCast myBoradCast;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
ButterKnife.bind(this);
Log.e(TAG,"onCreate thread id = " + Thread.currentThread().getId()+ ",name = "+Thread.currentThread().getName());
mBroadcastManager = LocalBroadcastManager.getInstance(this);
myBoradCast = new MyBoradCast();
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(ACTION_THREAD);
intentFilter.addAction(ACTION_THREAD_AGAIN);
mBroadcastManager.registerReceiver(myBoradCast,intentFilter);
}
@OnClick(R.id.start)
public void start() {
Intent intent = new Intent(this, ServiceDemo4.class);
intent.putExtra("params","thread");
startService(intent);
}
@OnClick(R.id.start_again)
public void startAgain() {
Intent intent = new Intent(this, ServiceDemo4.class);
intent.putExtra("params","thread_again");
startService(intent);
}
@OnClick(R.id.stop)
public void stop() {
Intent intent = new Intent(this, ServiceDemo4.class);
stopService(intent);
}
@Override
protected void onDestroy() {
super.onDestroy();
ButterKnife.unbind(this);
mBroadcastManager.unregisterReceiver(myBoradCast);
}
public class MyBoradCast extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action != null) {
switch (action) {
case ACTION_THREAD :
int progress = intent.getIntExtra("progress",0);
msg.setText("ACTION_THREAD 当前进度 = "+progress);
break;
case ACTION_THREAD_AGAIN :
int progress_again = intent.getIntExtra("progress",0);
msg_again.setText("ACTION_THREAD_AGAIN 当前进度 = "+progress_again);
break;
}
}
}
}
}
这里先在onCreate里实例化广播MyBoradcast,然后通过本地广播注册(广播这个组件在Service讲完后再写一遍文章具体分析),然后在第一个按钮里启动服务,记得传一个params参数,看日志:
11-07 15:31:29.488 13558-13558 E/MainActivity2: onCreate thread id = 1,name = main
11-07 15:31:31.861 13558-13558 E/ServiceDemo4: ServiceDemo4
11-07 15:31:31.863 13558-13558 E/ServiceDemo4: onCreate
11-07 15:31:31.863 13558-13558 E/ServiceDemo4: onStartCommand
11-07 15:31:31.864 13558-13703 E/ServiceDemo4: onHandleIntent intent = thread thread id = 868,name = IntentService[ServiceDemo4]
11-07 15:31:31.865 13558-13703 E/ServiceDemo4: action=com.mango.thread,progress=1
11-07 15:31:33.867 13558-13703 E/ServiceDemo4: action=com.mango.thread,progress=2
当耗时操作计数到2时,再点击第二个按钮再次启动服务,看日志:
11-07 15:31:34.638 13558-13558 E/ServiceDemo4: onStartCommand
11-07 15:31:35.869 13558-13703 E/ServiceDemo4: action=com.mango.thread,progress=3
11-07 15:31:37.870 13558-13703 E/ServiceDemo4: action=com.mango.thread,progress=4
这里只回调了onStartCommad方法,并没有进入onHandleIntent方法,继续看日志:
11-07 15:31:39.872 13558-13703 E/ServiceDemo4: action=com.mango.thread,progress=5
11-07 15:31:41.873 13558-13703 E/ServiceDemo4: onHandleIntent intent = thread_again thread id = 868,name = IntentService[ServiceDemo4]
11-07 15:31:41.874 13558-13703 E/ServiceDemo4: action=com.mango.thread_again,progress=1
11-07 15:31:43.874 13558-13703 E/ServiceDemo4: action=com.mango.thread_again,progress=2
11-07 15:31:45.875 13558-13703 E/ServiceDemo4: action=com.mango.thread_again,progress=3
这里可以看到第一个请求计数到5结束后,就回调了onHandleIntent方法处理第二个请求,此时点击停止按钮停止服务,看日志:
11-07 15:31:46.696 13558-13558 E/ServiceDemo4: onDestroy
11-07 15:31:47.876 13558-13703 E/ServiceDemo4: action=com.mango.thread_again,progress=4
11-07 15:31:49.877 13558-13703 E/ServiceDemo4: action=com.mango.thread_again,progress=5
虽然服务停止了,但是服务里开启的子线程并没有结束,依然在计数,依然在发广播。
IntentService使用步骤:
总结:
Service有的特性IntentService都有,但是有一些自身具有的属性,它在内部封装了一个消息队列和HnadlerThread。我们进到IntentService的源码中
public abstract class IntentService extends Service {
private volatile Looper mServiceLooper;//这是一个消息队列,存放着发过来的请求Intent
private volatile ServiceHandler mServiceHandler;//就是自定义一个Handler,用来从消息队
列取消息和放消息到消息队列中
private String mName;//工作线程名字
private boolean mRedelivery;//是否重启服务的标志,默认flase
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
//从onCreate里可以知道ServiceHandler的创建是依附于HandlerThread线程的,也就是在线程里创建一个Handler
//所以在这里处理请求是在HandlerThread进行,不会阻塞主线程
//每处理一个请求就调用一次stopSelf(msg.arg1),这个参数是onStartCommand方法第三个参数,并不是真的销毁自己,会判断
//如果mServiceLooper的队列里还有消息,就不会销毁自己
@Override
public void handleMessage(Message msg) {
onHandleIntent((Intent)msg.obj);
stopSelf(msg.arg1);
}
}
/**
*创建一个IntentService。 由你的子类的构造函数调用。
* 参数name是工作线程名字
*/
public IntentService(String name) {
super();
mName = name;
}
/**
*
* 设置true,如果onStartCommand在返回之前IntentService被系统销毁了,系统会重启该服务
* 如果有多个Intent已经被发送,则只有最近的一个保证被重新递交。
* 设置flase 如果onStartCommand在返回之前IntentService被系统销毁了,系统不会重启该服务
*/
public void setIntentRedelivery(boolean enabled) {
mRedelivery = enabled;
}
@Override
public void onCreate() {
super.onCreate();
//构建一个线程,HandlerThread是继承自Thread
HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
thread.start();
//将HandlerThread的消息队列拿出来,传给ServiceHandler
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}
/**
*可以看到每startService一次,就会调用一次onStartCommand,在onStartCommand会调用onStart,
* 在onStart里将发过来的请求Intent放到Message里,
* 这个startId是叠加的,表示请求顺序
*/
@Override
public void onStart(@Nullable Intent intent, int startId) {
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent;
mServiceHandler.sendMessage(msg);
}
/**
* 建议不用重写这个方法,没有用,因为有onHandleIntent方法被回调
*/
@Override
public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
onStart(intent, startId);
return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
}
//只要调用stopService后,后续请求就不会得到执行,因为消息队列清空了mServiceLooper.quit()
@Override
public void onDestroy() {
mServiceLooper.quit();
}
/**
* 除非您为您的服务提供绑定,否则不需要实现此方法,因为默认实现返回null。
* 所以建议用startService启动服务,不用bindService启动服务。
*/
@Override
@Nullable
public IBinder onBind(Intent intent) {
return null;
}
/**
* 这是一个抽象方法,在工作线程去处理请求,不会阻塞主线程,一次只处理一个请求,如果一个请求耗时较长,会将接下来的请求处理往后延,
* 所有请求结束后,IntentService会自动销毁,开发者不要调用stopSelf
*/
@WorkerThread
protected abstract void onHandleIntent(@Nullable Intent intent);
}
整体流程来说就是:
Service与IntentService