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的布局中添加两个按钮,一个启动服务,一个停止服务
-
<LinearLayout
-
xmlns:android=
"http://schemas.android.com/apk/res/android"
-
android:layout_width=
"match_parent"
-
android:layout_height=
"match_parent"
-
android:orientation=
"vertical"
-
android:gravity=
"center">
-
-
<TextView
-
android:id=
"@+id/start"
-
android:layout_width=
"100dp"
-
android:layout_height=
"50dp"
-
android:gravity=
"center"
-
android:background=
"@color/colorAccent"
-
android:text=
"启动服务"/>
-
-
<TextView
-
android:id=
"@+id/stop"
-
android:layout_marginTop=
"20dp"
-
android:layout_width=
"100dp"
-
android:layout_height=
"50dp"
-
android:gravity=
"center"
-
android:background=
"@color/colorAccent"
-
android:text=
"停止服务"/>
-
-
LinearLayout>
然后在监听方法中启动服务:
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里注册:
<service android:name="com.mangoer.servicereview.Service.ServiceDemo">service>
如果以这种方式启动服务,服务就会在后台无限期运行,即使启动的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"); } }
在配置文件里注册服务
<service android:name=".Service.ServiceDemo4">service>
在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