概述

大家知道,普通Service服务是运行在UI线程上的,这就意味着如果我们需要通过Service执行一些耗时的操作,我们必须要通过创建一个工作线程来完成,否则应用可能会出现ANR异常。

IntentService就是为了解决这个问题而出现的。IntentService是Service的一个子类,该类的作用就是可以让服务在工作线程中执行任务,而不需要自行创建工作线程。

IntentService的主要作用(优点):
1. 在IntentService中会默认创建工作线程用于执行传递的Intent,这样在执行耗时操作时不需要手动去创建线程了
2. 在IntentService中创建工作队列,用于将 Intent 逐一传递给 onHandleIntent() 实现,这样就永远不必担心多线程问题。
3. 在处理完所有启动请求后停止服务,因此您永远不必调用 stopSelf()。
4. IntentService的onBind方法默认返回null

IntentService源码分析

在IntentService中,主要使用到了HandlerThread。HandlerThread是Thread的一个子类,在该类中可以使用Handler。其实HandlerThread的实现原理非常简单,就是在run方法中通过Looper.prepare()来创建消息队列,然后通过Looper.loop()方法开启消息循环,整个实现流程如同ActivityThread.main()方法中MainLooper的初始化过程。

具体关于HandlerThread的介绍,请看 Android HandlerThread源码分析

IntentServcie源码分析

public abstract class IntentService extends Service {    /**     * 1、在IntentServcie被首次创建时,会执行onCreate方法     */    @Override    public void onCreate() {        super.onCreate();        // 1、创建一个HandlerThread,用于接收消息        HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");        thread.start();        // 2、获取上面HandlerThread的实例的looper        mServiceLooper = thread.getLooper();        // 3、通过HandlerThread的looper,创建一个handler对象mServiceHandler,这样通过mServiceHandler发送的对象都会在HandlerThread中被处理        mServiceHandler = new ServiceHandler(mServiceLooper);    }    /**     * 2、每次启动IntentServcie, onStartCommand方法会被调用,该方法内部主要调用onStart方法     */    @Override    public int onStartCommand(Intent intent, int flags, int startId) {        onStart(intent, startId);        return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;    }    /**     * 3、在onStrat方法中主要是通过mServiceHandler发送了一条消息。     * 

* 在mServiceHandler发送的消息中,intent对象会作为发送消息的参数(这里的intent和通过startServcie方法传递的intent是同一个对象) *

* 同时,消息中会被携带一个startId的参数,该参数主要用于判断服务是否结束 */ @Override public void onStart(Intent intent, int startId) { Message msg = mServiceHandler.obtainMessage(); msg.arg1 = startId; msg.obj = intent; mServiceHandler.sendMessage(msg); } /** * 4、ServiceHandler,该handler对象是通过HandlerThread的looper创建的,所以通过ServiceHandler * 发送的消息都会被发送到HandlerThread中执行,由于HandlerThread是一个Thread类,这样就实现了在IntentService * 无需创建一个Thread来执行后台耗时任务。 *

* 同时,由于ServiceHandler内部的消息队列是通过looper维护的,这样就保证了消息队列是顺序执行的,所以IntentService也是 * 顺序执行任务的。 */ private final class ServiceHandler extends Handler { public ServiceHandler(Looper looper) { super(looper); } @Override public void handleMessage(Message msg) { /* * 1、抽象方法,需要在子类中实现具体后台任务的实现 */ onHandleIntent((Intent) msg.obj); /* * 2、在任务执行完成,自动停止服务。 * * msg.arg1 就是在startId,这是为每一消息生成的唯一标识。每通过IntentService处理一个请求时, * 都会有一个消息被放入到消息队列中,只有当最后一个消息执行完成即msg.arg1等于最后一个放入到消息队列的startId, * 服务才会被停止,否者IntentService不会被停止 * * 这样做的好处就是:保证消息队列中的所有消息都被处理,服务才会被停止。 * */ stopSelf(msg.arg1); } } /** * 5、抽象方法,该方法需要在IntentService的子类中实现,也是IntentService中唯一一个需要实现的方法 * * @param intent */ protected abstract void onHandleIntent(Intent intent); @Override public void onDestroy() { // 退出消息队列循环 mServiceLooper.quit(); } @Override @Nullable public IBinder onBind(Intent intent) { // 默认返回null return null; }}

IntentService的简单使用

这里通过IntentService模拟一个简单的下载任务。

public class IntentServcieActivity extends AppCompatActivity {    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_intent_servcie);        Button button = findViewById(R.id.btn);        button.setOnClickListener(new View.OnClickListener() {            private int urlid;            @Override            public void onClick(View v) {                Intent intent = new Intent(IntentServcieActivity.this, DownloadService.class);                intent.putExtra(DownloadService.DOWN_URL, "url" + ++urlid);                startService(intent);            }        });    }}/** * 通过IntentService完成下载任务 */public class DownloadService extends IntentService {    public static final String DOWN_URL = "down_url";    public DownloadService() {        super("DownloadService");    }    @Override    protected void onHandleIntent(Intent intent) {        String url = intent.getStringExtra(DOWN_URL);        downlaod(url);    }    /**     * 模拟下载任务     */    private void downlaod(String url) {        Log.e("zhangke", "url = " + url + "  正在下载中...");        SystemClock.sleep(3000);        Log.e("zhangke", "url = " + url + "  下载完成");    }}

更多相关文章

  1. Android线程学习 一
  2. Adapter 要从源头开始适配
  3. Android读写XML(中)
  4. Android(安卓)CountDownTimer 倒计时器的简单使用
  5. Android获取其他包的Context实例,然后调用它的方法
  6. Android(安卓)中 View 炸裂特效的实现分析 《IT蓝豹》
  7. android DDMS 调试初级及小技巧
  8. Android中如何给app widget添加复杂view
  9. Android(安卓)camera2使用

随机推荐

  1. android重要包的描述
  2. android动态创建控件
  3. Android近期任务列表 Recent Applicatoin
  4. Android屏幕适配攻略
  5. Android(安卓)-- Looper.prepare()和Loop
  6. Android项目--团购类客户端
  7. 生命週期
  8. 【安卓学习笔记】Android(安卓)Studio第9
  9. Andriod自动化测试原理基础
  10. Linux 使用 Nexus3.x 为 Android(安卓)搭