Service
Service 是长期运行在后台的应用程序组件。
Service 不是一个单独的进程,它和应用程序在同一个进程中,Service 也不是一个线程,它和线程没有任何关系,所以它不能直接处理耗时操作。如果直接把耗时操作放在 Service 的 onStartCommand() 中,很容易引起 ANR .如果有耗时操作就必须开启一个单独的线程来处理。
IntentService
IntentService 是继承于 Service 并处理异步请求的一个类,在 IntentService 内有一个工作线程来处理耗时操作,启动 IntentService 的方式和启动传统 Service 一样,同时,当任务执行完后,IntentService 会自动停止,而不需要我们去手动控制。另外,可以启动 IntentService 多次,而每一个耗时操作会以工作队列的方式在IntentService 的 onHandleIntent 回调方法中执行,并且,每次只会执行一个工作线程,执行完第一个再执行第二个,以此类推。
而且,所有请求都在一个单线程中,不会阻塞应用程序的主线程(UI Thread),同一时间只处理一个请求。 那么,用 IntentService 有什么好处呢?首先,我们省去了在 Service 中手动开线程的麻烦,第二,当操作完成时,我们不用手动停止 Service。
接下来让我们来看看如何使用,写一个Demo来模拟两个耗时操作。
比较Service 和 IntentService 处理耗时操作的结果
先分别在 Service 和 IntentService 里面处理耗时,看看是什么结果。首先创建一个 Service 服务,在其 onStartCommand() 中执行一个20s的耗时。
public class MyService extends Service { String TAG = "MyService";
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Logger.d(TAG, "-->开始睡眠");
try {
Thread.sleep(20000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Logger.d(TAG, "-->睡眠结束");
return super.onStartCommand(intent, flags, startId);
}
public static void startMyService(Context mContext) {
Intent intent = new Intent(mContext, MyService.class);
mContext.startService(intent);
}
}
结果发生ANR。
然后试试 IntentService
public class MyIntentService extends IntentService {
String TAG = "MyIntentService";
public MyIntentService() {
super("luwenje");
}
@Override
protected void onHandleIntent(Intent intent) {
Logger.d(TAG, "-->开始睡眠");
try {
Thread.sleep(20000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Logger.d(TAG, "-->睡眠结束");
}
public static void startMyIntentService(Context mContext){
Intent intent = new Intent(mContext,MyIntentService.class);
mContext.startService(intent);
}
}
IntentService 默认实现了 OnBind(),返回值为 null。
IntentService 必须实现 MyIntentService() 构造方法和 onHandleIntent(Intent intent)。
注意:
IntentService 的构造函数一定是参数为空的构造函数,然后再在其中调用 super(“name”) 这种形式的构造函数。
因为 Service 的实例化是系统来完成的,而且系统是用参数为空的构造函数来实例化Service的。
启动 IntentService,果然没有发生ANR。
为了看看 IntentService 异步处理的能力 我想不如这样来极端的启动它。
for (int i = 0; i < 20; i++) {
MyIntentService.startMyIntentService(this);
}
循环20次启动 IntentSerivce 然后我们来看看log信息。
结果是20组 有序的这样开始-结束 开始-结束,所以IntentService是等前面的请求结束之后再执行下一个。 这个证实了 IntentService 采用单独的线程每次只从队列中拿出一个请求进行处理
IntentService 的生命周期和执行过程
再来写个 demo 看看 IntentService 的生命周期和执行过程
public class MyIntentService2 extends IntentService {
String TAG = "MyIntentService2";
public MyIntentService2() {
super("luwenjie2");
}
@Override
public void onCreate() {
Logger.d(TAG,"onCreate");
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Logger.d(TAG,"onStartCommand");
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onStart(Intent intent, int startId) {
Logger.d(TAG,"onStart");
super.onStart(intent, startId);
}
@Override
public IBinder onBind(Intent intent) {
Logger.d(TAG,"onBind");
return super.onBind(intent);
}
@Override
public void setIntentRedelivery(boolean enabled) {
super.setIntentRedelivery(enabled);
Logger.d(TAG,"setIntentRedelivery");
}
@Override
protected void onHandleIntent(Intent intent) {
//Intent是从Activity发过来的,携带识别参数,根据参数不同执行不同的任务
String action = intent.getExtras().getString("param");
if (action.equals("oper1")) {
Logger.d("Operation1");
}else if (action.equals("oper2")) {
Logger.d("Operation2");
}
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
@Override
public void onDestroy() {
Logger.d(TAG,"onDestroy");
super.onDestroy();
}
}
我把生命周期方法全打印出来了,待会我们来看看它执行的过程是怎样的。接下来是 Activity,在 Activity 中创建2个带不同值的 Intent 来启动 IntentService:
//Operation 1
Intent startServiceIntent = new Intent(this,MyIntentService2.class);
Bundle bundle = new Bundle();
bundle.putString("param", "oper1");
startServiceIntent.putExtras(bundle);
startService(startServiceIntent);
//Operation 2
Intent startServiceIntent2 = new Intent(this,MyIntentService2.class);
Bundle bundle2 = new Bundle();
bundle2.putString("param", "oper2");
startServiceIntent2.putExtras(bundle2);
startService(startServiceIntent2);
日志打印的顺序是:
onCreate -> onStartCommand -> onStart -> onStartCommand -> onStart -> Operation1 -> Operation2 -> onDestroy
从结果可以看到,onCreate 方法只执行了一次,而 onStartCommand 和 onStart 方法执行了两次,开启了两个 Work Thread,这就证实了之前所说的,启动多次,但IntentService 的实例只有一个,这跟传统的 Service 是一样的。Operation1 也是先于 Operation2 打印,并且我让两个操作间停顿了2s,最后是 onDestroy 销毁了IntentService。
总结
这就是IntentService,一个方便我们处理业务流程的类,它是一个Service,但是比Service更智能。