• Android IntentService的使用和源代码分析


    引言

    Service服务是Android四大组件之中的一个,在Android中有着举足重轻的作用。Service服务是工作的UI线程中,当你的应用须要下载一个文件或者播放音乐等长期处于后台工作而有没有UI界面的时候,你肯定要用到Service+Thread来实现。

    因此你须要自己在Service服务里面实现一个Thread工作线程来下载文件或者播放音乐。然而你每次都须要自己去写一个Service+Thread来处理长期处于后台而没有UI界面的任务。这样显得非常麻烦,不是必需每次都去构建一个Service+Thread框架处理长期处于后台的任务。Googleproject师给我们构建了一个方便开发人员使用的这么一个框架—IntentService。

    IntentService简单介绍

    IntentService是一个基础类,用于处理Intent类型的异步任务请求。当client调用android.content.Context#startService(Intent)发送请求时,Service服务被启动,且在其内部构建一个工作线程来处理Intent请求。当工作线程运行结束,Service服务会自己主动停止。IntentService是一个抽象类,用户必须实现一个子类去继承它,且必须实现IntentService里面的抽象方法onHandleIntent来处理异步任务请求。

    IntentServic演示样例

    Client代码

    public class ClientActivity extends AppCompatActivity {
    
        @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
        }
    
        //client同一时候发送两个任务到IntentService服务端运行
        public void send(View view) {
            Intent intent = new Intent(this, DownLoadService.class);
            intent.putExtra("key", 1);
            intent.putExtra("value", "the first task1");
            startService(intent);
    
            Intent intent1 = new Intent(this, DownLoadService.class);
            intent1.putExtra("key", 2);
            intent1.putExtra("value", "the second task2");
            startService(intent1);
        }
    }

    模拟两个异步任务同一时候请求,通过Intent实例携带数据启动Service服务。

    Serviceclient

    public class DownLoadService extends IntentService {
    
        public static final String TAG = "DownLoadService";
        //重写默认的构造方法
        public DownLoadService() {
            super("DownLoadService");
        }
    
        //在后台线程运行
        @Override
        protected void onHandleIntent(Intent intent) {
            int key = intent.getIntExtra("key", 0);
            String value = intent.getStringExtra("value");
            switch (key) {
                case 1:
                    //模拟耗时任务1
                    try {
                        Thread.sleep(3 * 1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    break;
                case 2:
                    //模拟耗时任务1
                    try {
                        Thread.sleep(3 * 1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    break;
                default:
                    break;
            }
    
            Log.e(TAG, "
    the current time is: " + System.currentTimeMillis()/1000
                    + "
    the Thread id is " + Thread.currentThread().getId()
                    + "
    the current task is " + value);
        }
    }

    DownLoadService子类继承IntentService类,然后实现onHandleIntent抽象方法进行处理Intent请求的异步任务。在服务端DownLoadService类中。我们并没有创建Thread线程去运行异步耗时任务请求。

    全部的异步耗时任务都是在onHandleIntent抽象方法中实现了。言外之意是IntentService类内部已经帮开发人员搭建好了一个异步任务处理器,用户仅仅需实现当中的onHandleIntent抽象方法去处理异步任务就可以。从而让开发人员更加简单方便的使用IntentService处理后台异步任务请求。那么IntentService内部是怎么搭建异步任务处理器的呢?我们最好还是查看源代码来窥探个到底。

    IntentService源代码分析

    IntentService构造方法

     /**
         * Creates an IntentService.  Invoked by your subclass's constructor.
         *
         * @param name Used to name the worker thread, important only for debugging.
         */
        public IntentService(String name) {
            super();
            mName = name;
        }

    分析:该构造方法需在子类中调用。用于创建一个IntentService对象。參数name用于定义工作线程的名称,仅仅用于调式作用。我们知道Service服务的生命周期是从onCreate方法開始的。那么就来看看IntentService#onCreate方法吧。

    IntentService#onCreate方法

     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);
        }

    分析:该方法首先利用HandlerThread类创建了一个循环的工作线程thread,然后将工作线程中的Looper对象作为參数来创建ServiceHandler消息运行者。由还有一篇博客 Android HandlerThread 源代码分析 可知。HandlerThread+Handler构建成了一个带有消息循环机制的异步任务处理机制。

    因此开发人员就能够将异步任务封装成消息的形式发送到工作线程中去运行了。

    Service服务生命周期第二步运行IntentService#onStartCommand方法。

    IntentService#onStartCommand方法

        /**
         * You should not override this method for your IntentService. Instead,
         * override {@link #onHandleIntent}, which the system calls when the IntentService
         * receives a start request.
         * @see android.app.Service#onStartCommand
         */
        @Override
        public int onStartCommand(Intent intent, int flags, int startId) {
            onStart(intent, startId);
            return mRedelivery ?

    START_REDELIVER_INTENT : START_NOT_STICKY; }

    分析:在IntentService子类中你无需重写该方法。

    然后你须要重写onHandlerIntent方法。系统会在IntentService接受一个请求開始调用该方法。我们看到在该方法中仅仅是调用了onStart方法而已。跟踪代码:

     @Override
        public void onStart(Intent intent, int startId) {
            Message msg = mServiceHandler.obtainMessage();
            msg.arg1 = startId;
            msg.obj = intent;
            mServiceHandler.sendMessage(msg);
        }
    

    分析:该方法中通过mServiceHandler获得一个消息对象msg。然后将startId作为该消息的消息码,将异步任务请求intent作为消息内容封装成一个消息msg发送到mServiceHandler消息运行者中去处理,那么我们来看看mServiceHandler的实现吧!

    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);
            }
        }

    分析:实现也比較简单。ServiceHandler是IntentService的内部类,在重写消息处理方法handlerMessage里面调用了onHandlerIntent抽象方法去处理异步任务intent的请求,当异步任务请求结束之后。调用stopSelf方法自己主动结束IntentService服务。看过博客 Android HandlerThread 源代码分析 的人都应该知道,此处handleMessage方法是在工作线程中调用的,因此我们子类重写的onHandlerIntent也是在工作线程中实现的。我们来看看onHandlerIntent方法:

    /**
         * This method is invoked on the worker thread with a request to process.
         * Only one Intent is processed at a time, but the processing happens on a
         * worker thread that runs independently from other application logic.
         * So, if this code takes a long time, it will hold up other requests to
         * the same IntentService, but it will not hold up anything else.
         * When all requests have been handled, the IntentService stops itself,
         * so you should not call {@link #stopSelf}.
         *
         * @param intent The value passed to {@link
         *               android.content.Context#startService(Intent)}.
         */
        protected abstract void onHandleIntent(Intent intent);

    分析:该方法用于处理intent异步任务请求,在工作线程中调用该方法。每个时刻仅仅能处理一个intent请求,当同一时候又多个intent请求时。也就是client同一时候多次调用Content#startService方法启动同一个服务时。其它的intent请求会临时被挂起。直到前面的intent异步任务请求处理完毕才会处理下一个intent请求。

    直到全部的intent请求结束之后,IntentService服务会调用stopSelf停止当前服务。

    也就是当intent异步任务处理结束之后。相应的IntentService服务会自己主动销毁。进而调用IntentService#onDestroy方法:

    @Override
        public void onDestroy() {
            mServiceLooper.quit();
        }

    该方法中调用HandlerThread工作线程中Looper对象的quit方法让当前工作线程HandlerThread退出当前Looper循环。进而结束线程。

    进而结束当前IntentService服务。到此,整个IntentService服务结束。如今能够用一张流程图来描写叙述整个步骤例如以下:

    这里写图片描写叙述

    IntentService总结

    1. 子类需继承IntentService而且实现里面的onHandlerIntent抽象方法来处理intent类型的任务请求。

    2. 子类须要重写默认的构造方法,且在构造方法中调用父类带參数的构造方法。

    3. IntentService类内部利用HandlerThread+Handler构建了一个带有消息循环处理机制的后台工作线程。client仅仅需调用Content#startService(Intent)将Intent任务请求放入后台工作队列中,且client无需关注服务是否结束,非常适合一次性的后台任务。比方浏览器下载文件,退出当前浏览器之后,下载任务依旧存在后台。直到下载文件结束,服务自己主动销毁。
    4. 仅仅要当前IntentService服务没有被销毁,client就能够同一时候投放多个Intent异步任务请求,IntentService服务端这边是顺序运行当前后台工作队列中的Intent请求的。也就是每一时刻仅仅能运行一个Intent请求。直到该Intent处理结束才处理下一个Intent。由于IntentService类内部利用HandlerThread+Handler构建的是一个单线程来处理异步任务。

    【转载请注明出处:http://blog.csdn.net/feiduclear_up CSDN 废墟的树】

  • 相关阅读:
    把文本数据转化为json
    componentsSeparatedByString 的注意事项
    内存管理
    审核问题2.3.1
    H5缩放效果的问题和缓存问题
    iOS库
    DDOS 攻击防范
    连接数过多的问题
    nginx 长连接keeplive
    javascript 判断身份证的正确性
  • 原文地址:https://www.cnblogs.com/jzssuanfa/p/7237498.html
Copyright © 2020-2023  润新知