Android中的Service是用于后台服务的,当应用程序被挂到后台的时候,为了保证应用的某些组件仍然可以工作而引入了Service这个概念,那么这里面要强调的是Service不是独立的进程,也不是独立的线程,它是依赖于应用程序的主线程的,也就是说,在更多时候不建议在Service中编写耗时的逻辑和操作,否则会引起ANR。
那么我们当我们编写的耗时逻辑,不得不被service来管理的时候,就需要引入IntentService,IntentService是继承Service的,那么它包含了Service的全部特性,当然也包含service的生命周期,那么与service不同的是,IntentService在执行onCreate操作的时候,内部开了一个线程,去你执行你的耗时操作。
IntentService是通过Handler looper message的方式实现了一个多线程的操作,同时耗时操作也可以被这个线程管理和执行,同时不会产生ANR的情况。
-------------------------------------------------------------
Service 是长期运行在后台的应用程序组件。
Service 不是一个单独的进程,它和应用程序在同一个进程中,Service 也不是一个线程,它和线程没有任何关系,所以它不能直接处理耗时操作。如果直接把耗时操作放在 Service 的 onStartCommand() 中,很容易引起 ANR .如果有耗时操作就必须开启一个单独的线程来处理。
IntentService 是继承于 Service 并处理异步请求的一个类,在 IntentService 内有一个工作线程来处理耗时操作,启动 IntentService 的方式和启动传统 Service 一样,同时,当任务执行完后,IntentService 会自动停止,而不需要我们去手动控制。另外,可以启动 IntentService 多次,而每一个耗时操作会以工作队列的方式在IntentService 的 onHandleIntent 回调方法中执行,并且,每次只会执行一个工作线程,执行完第一个再执行第二个,以此类推。
而且,所有请求都在一个单线程中,不会阻塞应用程序的主线程(UI Thread),同一时间只处理一个请求。 那么,用 IntentService 有什么好处呢?首先,我们省去了在 Service 中手动开线程的麻烦,第二,当操作完成时,我们不用手动停止 Service。
service:
public class MyService2 extends Service {
private static final String TAG = "MyService2";
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
super.onCreate();
LogUtil.e(TAG, "onCreate");
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
LogUtil.e(TAG, "onStartCommand");
//因为service在主线程中 所以操作耗时操作必须创建子线程
new Thread(new Runnable() {
@Override
public void run() {
LogUtil.e(TAG, "onStartCommand");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
LogUtil.e(TAG, "睡眠结束");
}
});
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
super.onDestroy();
LogUtil.e(TAG, "onDestroy");
}
}
如果在onStartCommand中不开启线程直接支持耗时操作,因为时间短出现了:Skipped 60 frames! The application may be doing too much work on its main thread.
intentService:
public class MyIntentService2 extends IntentService {
private static final String TAG = "MyIntentService2";
public MyIntentService2() {
super("MyIntentService2"); //调用父类的有参构造函数
}
@Override
protected void onHandleIntent(@Nullable Intent intent) {
// 经测试,IntentService里面是可以进行耗时的操作的
//IntentService使用队列的方式将请求的Intent加入队列,然后开启一个worker thread(线程)来处理队列中的Intent
//对于异步的startService请求,IntentService会处理完成一个之后再处理第二个
LogUtil.e(TAG, "onStart");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
LogUtil.e(TAG, "睡眠结束");
}
@Override
public void onDestroy() {
super.onDestroy();
LogUtil.e(TAG, "onDestroy");
}
}
servicedemoActivity
@OnClick({R.id.button, R.id.button2, R.id.button3, R.id.button4})
public void onViewClicked(View view) {
switch (view.getId()) {
case R.id.button:
//如果不开线程 会造成线程阻塞ANR
startService(new Intent(this, MyService2.class));
break;
case R.id.button2:
stopService(new Intent(this, MyService2.class));
break;
case R.id.button3:
//连续两次启动IntentService,会发现应用程序不会阻塞,
//而且最重要的是第二次的请求会再第一个请求结束之后运行
// (这个证实了IntentService采用单独的线程每次只从队列中拿出一个请求进行处理)
startService(new Intent(this, MyIntentService2.class));
startService(new Intent(this, MyIntentService2.class));
break;
case R.id.button4:
//不用关闭
break;
}
}
打印结果:
因为是startService启动的服务,只要android系统不关闭和主动调用stopService方法,service会一直运行在后台。
如果希望启动服务的Activity关闭的时候service也跟着一起关闭,这就需要将service和Activity进行绑定。bindService
05-28 14:54:01.105 8224-8224/com.sdhmw.com.mystudy E/MyService2: onCreate
05-28 14:54:01.105 8224-8224/com.sdhmw.com.mystudy E/MyService2: onStartCommand
05-28 14:56:52.015 8224-8224/com.sdhmw.com.mystudy D/ViewRootImpl: ViewPostImeInputStage processPointer 0
05-28 14:56:52.095 8224-8224/com.sdhmw.com.mystudy D/ViewRootImpl: ViewPostImeInputStage processPointer 1
05-28 14:56:52.095 8224-8224/com.sdhmw.com.mystudy E/MyService2: onDestroy
05-28 14:57:22.205 8224-16273/com.sdhmw.com.mystudy E/MyIntentService2: onStart
05-28 14:57:23.205 8224-16273/com.sdhmw.com.mystudy E/MyIntentService2: 睡眠结束
05-28 14:57:23.205 8224-16273/com.sdhmw.com.mystudy E/MyIntentService2: onStart
05-28 14:57:24.205 8224-16273/com.sdhmw.com.mystudy E/MyIntentService2: 睡眠结束
05-28 14:57:24.205 8224-8224/com.sdhmw.com.mystudy E/MyIntentService2: onDestroy
连续两次启动IntentService,会发现应用程序不会阻塞, 而且最重要的是第二次的请求会再第一个请求结束之后运行 (这个证实了IntentService采用单独的线程每次只从队列中拿出一个请求进行处理)
IntentService不需要主动方法去关闭,自动关闭。
bindService 返回键Activity关闭的时候自动关闭:
05-28 15:21:26.295 7203-7203/com.sdhmw.com.mystudy E/MyService2: onCreate
05-28 15:21:26.295 7203-7203/com.sdhmw.com.mystudy E/MyService2: BinderStart
05-28 15:21:26.295 7203-7203/com.sdhmw.com.mystudy E/ServiceDemoActivity: onServiceConnected name:ComponentInfo{com.sdhmw.com.mystudy/com.sdhmw.com.mystudy.MyService2}
05-28 15:21:26.295 7203-7203/com.sdhmw.com.mystudy E/ServiceDemoActivity: onServiceConnected service:com.sdhmw.com.mystudy.MyService2$MyBinder@b888e6a
05-28 15:21:32.105 7203-7203/com.sdhmw.com.mystudy D/ViewRootImpl: ViewPostImeInputStage processKey 0
05-28 15:21:32.185 7203-7203/com.sdhmw.com.mystudy D/ViewRootImpl: ViewPostImeInputStage processKey 1
05-28 15:21:32.625 7203-7203/com.sdhmw.com.mystudy D/ViewRootImpl: #3 mView = null
05-28 15:21:32.635 7203-7203/com.sdhmw.com.mystudy E/MyService2: onDestroy
service里面的onstart()方法和onStartCommand()方法的区别
参考:https://blog.csdn.net/kuangren_01/article/details/9427839