IntentService继承了Service并且是一个抽象类,需要创建它的子类才能使用IntentService。它相对Service来说,是一个特殊的Service,它的内部使用HandleThread
来执行服务,任务执行完,IntentService会自动退出。相对于Thread来说,它是一个服务,它的优先级高于线程,不容易被系统回收。
一个面试问题:我要用服务下载apk,是用IntentService,还是Service好?为什么?
IntentService与Service都可以执行下载apk的任务。具体的下载代码可以观看我的文章:IntentService、Service下载的apk。在回答这可问题之前我们要再次回顾一下Service的概念。Service是一种计算型组件,用于在后台执行一系列计算任务。Service不是一个线程,尽管它是执行后台计算的,它是运行在主线程中,耗时的后台操作仍然需要在单独的子线程中去执行,所以不要在Service的onStart方法中执行耗时操作,不然会出现Application Not Responding!的异常。而IntentService采用队列的方式将请求的Intent加入队列,然后开启一个线程来处理队列中的Intent,对于异步的startService请求。IntentService处理完一个后再处理第二个,都是在子线程中,不会阻塞主线程。所以有耗时操作与其在Service里开启子线程不如在IntentService中处理耗时操作。
回到主题,继续分析IntentService。
在IntentService的onCreate()方法中,可以看到它实现了HandleThread 和Handle。
private volatile Looper mServiceLooper;
private volatile ServiceHandler mServiceHandler;
@Override
public void onCreate() {
// TODO: It would be nice to have an option to hold a partial wakelock
// during processing, and to have a static startService(Context, Intent)
// method that would launch the service & hand off a wakelock.
super.onCreate();
HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
thread.start();
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}
IntentService第一次启动时,onCreate()方法调用,创建一个HandlerThread,获取到mServiceLooper,mServiceHandler。通过mServiceHandler发送信息会在HandlerThread中执行。每次启动IntentService,会调用onStartCommand()。IntentService在onStartCommand()方法中处理后台的Intent。在源码中onStartCommand调用了onStart():
@Override
public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
onStart(intent, startId);
return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
}
@Override
public void onStart(@Nullable Intent intent, int startId) {
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent;
mServiceHandler.sendMessage(msg);
}
IntentService通过mServiceHandler发送了一条信息,消息会在HandleThread方法中处理。同时将Intent对象给 ServiceHandler的onHandleIntent方法处理。onHandleIntent是运行在子线程中,可以做耗时操作。另外这里的Intent对象和外界startService(intent)保持一致,通过它可以获得外界启动IntentService传递的参数,可以区分具体的后台任务,对不同的后台采取不同的处理方式(可以咱参照文章后边的样例)。onHandleIntent方法执行完之后,会调用stopSelf(int startId)停止服务。stopSelf()会立即停止服务,stopSelf(int startId)会等待所有信息都处理完后才关闭服务,它在服务关闭前会判断最近启动的次数是否与startId相等,相等立即停止服务,不相等不停止服务。
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
onHandleIntent((Intent)msg.obj);
stopSelf(msg.arg1);
}
}
//This method is invoked on the worker thread with a request to process.
@WorkerThread
protected abstract void onHandleIntent(@Nullable Intent intent);
onHandleIntent是一个抽象方法,需要在子类中实现,它的作用就是区分Intent中的参数来区分任务并执行。在执行完onHandleIntent方法后,如果目前只有一个后台任务会立刻调用stopSelf(int startId)停止服务。如果有多个,会在onHandleIntent执行完最后一个任务后调用停止服务。每执行一个后台任务都会启动一次IntentService,而IntentService内部的信息是通过HandleThread来执行,Handle中的Looper顺序处理信息,所以IntentService是顺序执行后台任务的。多后台任务会按照外界发起的顺序排队执行。
public class DemoIntentService extends IntentService {
static final String Tag = "DemoIntentService";
public DemoIntentService() {
super("demo-intentService");
}
@Override
protected void onHandleIntent(Intent intent) {
String action = intent.getStringExtra("test_action");
Log.e(Tag, "receive action=====" + action);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
@Override
public void onDestroy() {
Log.e(Tag, "onDestroy=====");
super.onDestroy();
}
}
public class TestActivity extends Activity {
BroadcastReceiver receiver;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Intent mIntent = new Intent(this, DemoIntentService.class);
mIntent.putExtra("test_action","action1");
startService(mIntent);
mIntent.putExtra("test_action","action2");
startService(mIntent);
mIntent.putExtra("test_action","action3");
startService(mIntent);
}
}
注册列表
<service android:name=“.downloadApk.DemoIntentService"/>
打印结果:
05-16 23:53:12.219 18007-18292/? E/DemoIntentService: receive action=====action1
05-16 23:53:13.219 18007-18292/? E/DemoIntentService: receive action=====action2
05-16 23:53:14.219 18007-18292/? E/DemoIntentService: receive action=====action3
05-16 23:53:15.219 18007-18007/? E/DemoIntentService: onDestroy=====
日志显示三个后台任务顺序执行,在action3后,执行stopSelf(int startId)。
=====================================>
这是一篇对书笔记,文章内容大多数来自于androdi开发艺术探索,很不错的一本书。