美文网首页Android技术分享
异步消息处理机制

异步消息处理机制

作者: 瑟闻风倾 | 来源:发表于2019-11-07 17:02 被阅读0次

    说明:异步消息处理框架 HandlerAsyncTaskHandlerThreadIntentService 本质上都是对线程和线程池的封装。

    1. Handler

    1.1 what is Handle

    handler:handler是一个消息分发对象,进行发送和处理消息。handle通过发送和处理Message和Runnable对象来关联相对应线程的MessageQueue。让耗时操作放在子线程,更新UI放在主线程。

    1.2 handle机制原理

    handle机制原理.png
    四者关系.png

    1.3 handler异步消息处理的两种方式

    (1) 通过handler.post(runnable)的方式来进行消息传递

    • 创建Handler对象
    • 创建runnable对象并重写run()方法
    • 通过handler.post(runnable)方法将runnable对象通过post()方法传到handler中:主线程会在合适的时候执行runnable对象run方法中的代码从而更新UI

    (2) 通过handler.sendMessage(message)的方式来进行消息传递

    • 创建Handler对象并重写handleMessage()方法
    • 创建Message对象添加消息标识后通过handler.sendMessage(message)方法发送消息
    • 在handleMessage()方法中根据消息标识处理消息从而更新UI

    备注:post(runnable)只是对sendMessage(message)进行了封装,底层最终调用的还是sendMessage(message)。
    注意:UI线程(主线程)才能更新UI,所以创建Handler只能在主线程而不能在内部类,从而使Handler的HandlerhandleMessage(msg)方法执行在UI线程,这样才能保证UI线程是线程安全的。

    1.4 handler异步消息处理示例

    (1) 常见的子线程向主线程发送消息更新UI

    package comi.example.liy.mytestdemo;
    
    import android.os.Bundle;
    import android.os.Handler;
    import android.support.v7.app.AppCompatActivity;
    import android.widget.Toast;
    
    /**
     * Created by liy on 2019-11-06 15:36
     */
    public class HandlerWithRunnableActivity extends AppCompatActivity {
    
        private HandlerWithRunnableActivity activity;
    
        //(1)在成员变量中创建Handler对象:创建后Handler就会绑定到UI线程(主线程)
        private Handler myHandler = new Handler();
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            activity = this;
        }
    
        @Override
        protected void onResume() {
            super.onResume();
            new MyThread().start();
        }
    
        private class MyThread extends Thread{
            @Override
            public void run() {
                super.run();
                try{
                    System.out.println("开始耗时操作");
                    sleep(5000);
                    System.out.println("耗时操作完成");
                    //(2)创建runnable对象并重写run方法
                    Runnable runnable = new Runnable() {
                        @Override
                        public void run() {
                            /*Toast.makeText(HandlerWithMessageActivity.this,"更新UI",Toast.LENGTH_SHORT).show();*/
                            Toast.makeText(activity,"更新UI",Toast.LENGTH_SHORT).show();
                        }
                    };
                    myHandler.post(runnable);//(3)完成耗时操作后将runnable对象通过post方法传到handler中:主线程会在合适的时候执行runnable对象run方法中的代码从而更新UI
                }catch (Exception e){
                    e.printStackTrace();
                }
    
            }
        }
    }
    
    
    package comi.example.liy.mytestdemo;
    
    import android.os.Bundle;
    import android.os.Handler;
    import android.os.Message;
    import android.support.v7.app.AppCompatActivity;
    import android.widget.Toast;
    
    /**
     * Created by liy on 2019-11-06 15:35
     */
    public class HandlerWithMessageActivity extends AppCompatActivity {
    
        private static final int MESSAGE_TEST = 1;//消息标识
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
        }
    
        //(1)在成变量中创建Handler对象并重写handleMessage方法
        private Handler myHandler = new Handler(){
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                switch (msg.what){//(3)根据消息标识处理消息
                    case MESSAGE_TEST:
                        Toast.makeText(HandlerWithMessageActivity.this,"更新UI",Toast.LENGTH_SHORT).show();
                }
            }
        };
    
    
        @Override
        protected void onResume() {
            super.onResume();
            new MyThread().start();
        }
    
        private class MyThread extends Thread{
            @Override
            public void run() {
                super.run();
                try{
                    sleep(5000);
                }catch (Exception e){
                    e.printStackTrace();
                }
                //(2)创建Message对象添加消息标识后发送消息
                Message message = new Message();// Message messsag = myHandler.obtainMessage();
                message.what = MESSAGE_TEST;
                myHandler.sendMessage(message);
            }
        }
    
    }
    
    

    Bundle传参示例

    Message message = new Message();
    message.what = MESSAGE_TEST;
    Bundle bundle = new Bundle();
    bundle.putString("number",number);
    bundle.putString("name",name);
    message.setData(bundle);
    myHandler.sendMessage(message);
    

    (2) 不常见的的主线程向子线程发送消息
    拓展:我们平时开发时,经常是子线程向主线程发消息让主线程更新UI,但根据具体的项目需求也可能会要求主线程向子线程发消息。

    package comi.example.liy.mytestdemo;
    
    import android.os.Bundle;
    import android.os.Handler;
    import android.os.Looper;
    import android.os.Message;
    import android.support.v7.app.AppCompatActivity;
    import android.view.View;
    import android.widget.TextView;
    import android.widget.Toast;
    
    /**
     * Created by liy on 2019-11-07 14:40
     * 主线程向子线程发送消息
     */
    public class HandlerTestActivity extends AppCompatActivity {
    
        private Handler handler;
        private  HandlerTestActivity activity;
    
        private TextView textView;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            activity = this;
    
            textView = findViewById(R.id.text);
            textView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    handler.sendEmptyMessage(2);//主线程发送消息
                }
            });
    
        }
    
        @Override
        protected void onResume() {
            super.onResume();
            new MyThread().start();
        }
    
        //子线程接收消息
        private class MyThread extends Thread{
            @Override
            public void run() {
                super.run();
    
                //(1)子线程创建Looper对象开启消息循环(默认情况下Android中除主线程外新建的子线程都没有开启消息循环,主线程系统会自动为其创建Looper对象并开启消息循环)
                Looper.prepare();
                //(2)在子线程中创建Handler
                handler = new Handler(){
                    @Override
                    public void handleMessage(Message msg) {
                        super.handleMessage(msg);
                        System.out.println("threadName:" + Thread.currentThread().getName() + ",messageWhat:" + msg.what);
                        Toast.makeText(activity,"threadName:" + Thread.currentThread().getName() + ",messageWhat:" + msg.what,Toast.LENGTH_SHORT).show();
                    }
                };
    
                try{
                    sleep(3000);
                }catch (Exception e){
                    e.printStackTrace();
                }
                //(3)取出消息对象开始消息循环
                //注意:写在Looper.loop()之后的代码不会被执行,这个函数内部是一个死循环,当调用mHandler.getLooper().quit()后,loop才会中止,其后的代码才能得以运行。
                Looper.loop();//开始消息循环:Looper从消息队列取出消息并交给Handler处理
            }
        }
    
    }
    
    

    拓展开启子线程的三种方式

    1.5 handler引起的内存泄漏及解决方法

    (1) handler引起内存泄漏原因:非静态内部类持有外部类的匿名引用导致外部activity无法释放(java相关)。创建的Handler若不是静态内部类,则会隐秘地持有activity的引用,当activity被回收时,若handler内部仍在做耗时操作则handler没有被释放,所有handler所持有的activity的引用也不能被释放,导致activity无法被回收从而导致内存泄漏。
    (2) 解决方法:Android常见异常与性能优化

    • 静态内部类:Handler 改为静态内部类(static)
    • 弱引用:内部类Handler若调用了外部activity,可使用弱引用而不要直接使用activity
    • 资源回收:在activity的onDestory()生命周期函数中调用handler.removeCallbacks()方法

    2. AsyncTask框架

    2.1 what is AsyncTask

    AsyncTask:AsyncTask本质上是封装了线程池和Handler的异步框架,主要是来执行异步任务的(适用于耗时短的操作,耗时长的任务使用线程池比较好),由于内部集成了Handler,所以能够方便地在UI线程(主线程)和工作线程(子线程)灵活切换。

    • UI线程(主线程):主线程负责UI的绘制及相应用户的操作
    • 工作线程(子线程):子线程负责在后台做耗时操作,避免UI线程的ANR(Application Not Responding)问题

    2.2 AsyncTask内部原理

    内部原理:AsyncTask框架内部封装了线程池,通过Handler发送消息在UI线程和主线程中传递

    2.3 AsyncTask的使用方法(掌握3个参数和5个方法)

    3个参数和5个方法.png

    (1) AsyncTaskTestActivity.java

    package comi.example.liy.mytestdemo;
    
    import android.os.Bundle;
    import android.support.v7.app.AppCompatActivity;
    import android.view.View;
    import android.widget.Button;
    import android.widget.ProgressBar;
    import android.widget.TextView;
    
    /**
     * Created by liy on 2019-11-07 17:10
     */
    public class AsyncTaskTestActivity extends AppCompatActivity {
    
        private Button button;
        private ProgressBar progressBar;
        private TextView textView;
        
        private AsyncTaskUpdateInfo asyncTask;
    
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_asynctask);
    
            button = (Button)findViewById(R.id.button03);
            progressBar = (ProgressBar)findViewById(R.id.progressBar02);
            textView = (TextView)findViewById(R.id.textView01);
    
            button.setOnClickListener(new View.OnClickListener() {
    
                @Override
                public void onClick(View v) {
                    asyncTask = new AsyncTaskUpdateInfo(textView, progressBar);
                    asyncTask.execute(1000);
                }
            });
        }
    
        @Override
        protected void onDestroy() {
            super.onDestroy();
            asyncTask.onCancelled();//在activity的onDestroy()方法中取消asyncTask任务避免内存泄漏
        }
    }
    
    

    (2) AsyncTaskUpdateInfo .java

    package comi.example.liy.mytestdemo;
    
    import android.os.AsyncTask;
    import android.widget.ProgressBar;
    import android.widget.TextView;
    
    /**
     * Created by liy on 2019-11-07 13:13
     * AsyncTask是android提供的一个抽象类,需派生出子类来执行不同的异步任务
     * AsyncTask的三个参数(泛型)分别代表:耗时操作需传递的参数,进度条和返回结果
     * AsyncTask的五个方法:
     */
    public class AsyncTaskUpdateInfo extends AsyncTask<Integer,Integer,String> {
        private TextView textView;
        private ProgressBar progressBar;
    
        public AsyncTaskUpdateInfo(TextView textView, ProgressBar progressBar) {
            this.textView = textView;
            this.progressBar = progressBar;
        }
    
        //(1)耗时操作执行前的UI更新
        @Override
        protected void onPreExecute() {
            super.onPreExecute();
            textView.setText("开始执行异步线程");
        }
    
        //(2)在子线程中执行耗时操作
        @Override
        protected String doInBackground(Integer... params) {
            int i;
            for (i = 10;  i<=100 ; i+=10) {
                publishProgress(i);//publishProgress()执行完成后就会调用onProgressUpdate()来更新进度条
            }
            return i + params[0].intValue() + "";
        }
    
        //耗时操作时的UI实时更新
        @Override
        protected void onProgressUpdate(Integer... values) {
            super.onProgressUpdate(values);
            int value = values[0];
            progressBar.setProgress(value);
        }
    
        //(3)耗时操作完成后的UI更新
        @Override
        protected void onPostExecute(String s) {//doInBackground()执行完毕后会执行onPostExecute(),并把返回结果传递给onPostExecute()
            super.onPostExecute(s);
            textView.setText("异步操作执行结束:" + result);
        }
    
        @Override
        protected void onCancelled(String s) {
            super.onCancelled(s);
        }
    
        @Override
        protected void onCancelled() {
            super.onCancelled();
        }
    }
    

    (3) activity_asynctask.xml

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="vertical"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        >
        <TextView
            android:id="@+id/textView01"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            />
        <ProgressBar
            android:id="@+id/progressBar02"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            style="?android:attr/progressBarStyleHorizontal"
            />
        <Button
            android:id="@+id/button03"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:text="更新progressbar"
            />
    </LinearLayout>
    

    2.4 AsyncTask注意事项

    (1) 内存泄漏:AsyncTask引起的内存泄漏的原因和Handler一样。
    说明:解决handler引起的内存泄漏可在activity的onDestory()生命周期函数中调用handler.removeCallbacks()方法,而解决AsyncTask引起的内存泄漏调用asyncTask.onCancelled()方法即可。
    (2) 结果丢失:

    • 原因和现象描述:非静态内部类AsyncTask持有外部类activity的引用,当销毁activity时若AsyncTask还在执行耗时任务,则导致activity无法被回收。此时若重新打开activity则此时AsyncTask所持有的activity的引用并非是当前activity,导致结果丢失。
    • 解决:在activity的onDestory()生命周期函数中调用asyncTask.onCancelled()方法。

    (3) 并行 or 串行:AsyncTask虽然可以执行并行执行耗时操作,但是会导致线程池不稳定,AsyncTask仅适合执行耗时短的操作。

    3. HandlerThread框架

    3.1 HandlerThread介绍

    (1)产生背景:耗时任务需要通过创建子线程来执行,执行完毕会自动销毁子线程;但线程的创建和销毁很消耗系统资源,当第一个耗时任务执行完毕后又有耗时任务,那么就需要重新再创建一个子线程,如此循环地创建和销毁线程很浪费系统资源。

    为了解决这个问题,我们可以创建一个循环线程,在线程中创建Looper监听器来进行消息的轮询,即当有耗时任务投放到循环线程当中,线程就开始执行耗时任务,处理完成后循环线程处于阻塞等待状态,直到下一个耗时任务被投放在循环线程(通过阻塞等待来保证性能最优,避免频繁创建销毁线程消耗系统资源)。过程如下:

    package comi.example.liy.mytestdemo;
    
    import android.os.Bundle;
    import android.os.Handler;
    import android.os.Looper;
    import android.os.Message;
    import android.support.v7.app.AppCompatActivity;
    import android.widget.Toast;
    
    /**
     * Created by liy on 2019-11-07 14:40
     * 创建一个循环线程,在线程中创建Looper监听器来进行消息的轮询:HanderThread的原理
     */
    public class HandlerTestActivity extends AppCompatActivity {
    
        private Handler handler1;
        private  HandlerTestActivity activity;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            activity = this;
        }
    
        @Override
        protected void onResume() {
            super.onResume();
            new MyThread().start();
        }
    
        //在子线程中调用Looper.prepare()为线程开启消息循环:默认情况下Android中除主线程外新建的子线程都没有开启消息循环,主线程系统会自动为其创建Looper对象并开启消息循环
        private class MyThread extends Thread{
            @Override
            public void run() {
                super.run();
    
                //(1)创建Looper对象
                Looper.prepare();
                handler1 = new Handler(){
                    @Override
                    public void handleMessage(Message msg) {
                        super.handleMessage(msg);
                        System.out.println("threadName:" + Thread.currentThread().getName() + ",messageWhat:" + msg.what);
                        Toast.makeText(activity,"threadName:" + Thread.currentThread().getName() + ",messageWhat:" + msg.what,Toast.LENGTH_SHORT).show();
                    }
                };
    
                try{
                    sleep(3000);
                }catch (Exception e){
                    e.printStackTrace();
                }
    
                handler1.sendEmptyMessage(2);
                //注意:写在Looper.loop()之后的代码不会被执行,这个函数内部是一个死循环,当调用mHandler.getLooper().quit()后,loop才会中止,其后的代码才能得以运行。
                Looper.loop();//(2)开始消息循环:Looper从消息队列取出消息并交给Handler处理
            }
        }
    
    }
    
    

    然而以上操作可以用已经封装好的HandlerThread类来帮我们完成。

    (2) what is HandlerThread:HandlerThread本质上是一个内部建立了looper的特殊线程(继承Thread),可以进行looper循环,在HandlerThread内部创建Handler对象来处理消息。通过获取HandlerThread的looper对象传递消息给Handler,可以在handleMessage()方法中执行异步任务。

    • 优点:不会阻塞UI线程,使主界面更流畅(HandlerThread将loop转到子线程中处理,拥有自己的消息队列,不会干扰或阻塞UI线程)
    • 缺点:不能同时进行多任务的处理,需等待处理。(与线程池并发不同,HandlerThread背后只有一个线程,在线程内部,任务是串行处理)

    3.2 HandlerThread源码解析(内部机制)

    /*
     * Copyright (C) 2006 The Android Open Source Project
     *
     * Licensed under the Apache License, Version 2.0 (the "License");
     * you may not use this file except in compliance with the License.
     * You may obtain a copy of the License at
     *
     *      http://www.apache.org/licenses/LICENSE-2.0
     *
     * Unless required by applicable law or agreed to in writing, software
     * distributed under the License is distributed on an "AS IS" BASIS,
     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     * See the License for the specific language governing permissions and
     * limitations under the License.
     */
    
    package android.os;
    
    /**
     * Handy class for starting a new thread that has a looper. The looper can then be 
     * used to create handler classes. Note that start() must still be called.
     */
    public class HandlerThread extends Thread {
        int mPriority;
        int mTid = -1;
        Looper mLooper;
    
        public HandlerThread(String name) {
            super(name);
            mPriority = Process.THREAD_PRIORITY_DEFAULT;
        }
        
        /**
         * Constructs a HandlerThread.
         * @param name
         * @param priority The priority to run the thread at. The value supplied must be from 
         * {@link android.os.Process} and not from java.lang.Thread.
         */
        public HandlerThread(String name, int priority) {
            super(name);
            mPriority = priority;
        }
        
        /**
         * Call back method that can be explicitly overridden if needed to execute some
         * setup before Looper loops.
         */
        protected void onLooperPrepared() {
        }
    
        @Override
        public void run() {
            mTid = Process.myTid();
            Looper.prepare();
            synchronized (this) {
                mLooper = Looper.myLooper();
                notifyAll();
            }
            Process.setThreadPriority(mPriority);
            onLooperPrepared();
            Looper.loop();
            mTid = -1;
        }
        
        /**
         * This method returns the Looper associated with this thread. If this thread not been started
         * or for any reason is isAlive() returns false, this method will return null. If this thread 
         * has been started, this method will block until the looper has been initialized.  
         * @return The looper.
         */
        public Looper getLooper() {
            if (!isAlive()) {
                return null;
            }
            
            // If the thread has been started, wait until the looper has been created.
            synchronized (this) {
                while (isAlive() && mLooper == null) {
                    try {
                        wait();
                    } catch (InterruptedException e) {
                    }
                }
            }
            return mLooper;
        }
    
        /**
         * Quits the handler thread's looper.
         * <p>
         * Causes the handler thread's looper to terminate without processing any
         * more messages in the message queue.
         * </p><p>
         * Any attempt to post messages to the queue after the looper is asked to quit will fail.
         * For example, the {@link Handler#sendMessage(Message)} method will return false.
         * </p><p class="note">
         * Using this method may be unsafe because some messages may not be delivered
         * before the looper terminates.  Consider using {@link #quitSafely} instead to ensure
         * that all pending work is completed in an orderly manner.
         * </p>
         *
         * @return True if the looper looper has been asked to quit or false if the
         * thread had not yet started running.
         *
         * @see #quitSafely
         */
        public boolean quit() {
            Looper looper = getLooper();
            if (looper != null) {
                looper.quit();
                return true;
            }
            return false;
        }
    
        /**
         * Quits the handler thread's looper safely.
         * <p>
         * Causes the handler thread's looper to terminate as soon as all remaining messages
         * in the message queue that are already due to be delivered have been handled.
         * Pending delayed messages with due times in the future will not be delivered.
         * </p><p>
         * Any attempt to post messages to the queue after the looper is asked to quit will fail.
         * For example, the {@link Handler#sendMessage(Message)} method will return false.
         * </p><p>
         * If the thread has not been started or has finished (that is if
         * {@link #getLooper} returns null), then false is returned.
         * Otherwise the looper is asked to quit and true is returned.
         * </p>
         *
         * @return True if the looper looper has been asked to quit or false if the
         * thread had not yet started running.
         */
        public boolean quitSafely() {
            Looper looper = getLooper();
            if (looper != null) {
                looper.quitSafely();
                return true;
            }
            return false;
        }
    
        /**
         * Returns the identifier of this thread. See Process.myTid().
         */
        public int getThreadId() {
            return mTid;
        }
    }
    
    

    3.3 HandlerThread使用

    (1) HandlerThreadTestActivity .java

    package comi.example.liy.mytestdemo;
    
    import android.os.Bundle;
    import android.os.Handler;
    import android.os.HandlerThread;
    import android.os.Message;
    import android.support.annotation.Nullable;
    import android.support.v7.app.AppCompatActivity;
    import android.util.Log;
    
    /**
     * Created by liy on 2019-11-08 9:15
     */
    public class HandlerThreadTestActivity extends AppCompatActivity {
        private HandlerThread handlerThread;
        private Handler handler;
    
        @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            handlerThread = new HandlerThread("handler-thread");//创建一个线程(HandlerThread是一个具有Looper对象的特殊线程),名字是handler-thread
            handlerThread.start();//开启线程
    
            handler = new Handler(handlerThread.getLooper()){//在handler-thread线程中创建Handler对象
                @Override
                public void handleMessage(Message msg) {//该方法运行在handler-thread线程,可进行耗时操作
                    super.handleMessage(msg);
                    Log.v( "HandlerThread: " , "线程名:" + Thread.currentThread().getName() + ",消息标识:" + msg.what) ;
                }
            };
    
            handler.sendEmptyMessage(1);//在主线程给Handler发消息
    
            new Thread(new Runnable() {
                @Override
                public void run() {
                    handler.sendEmptyMessage(2);//在子线程给Handler发消息
                }
            }).start();
    
        }
    
        @Override
        protected void onDestroy() {
            super.onDestroy();
            handlerThread.quit();//释放资源
        }
    }
    
    

    运行效果:

    mytestdemo V/HandlerThread:线程名:handler-thread,消息标识:1
    mytestdemo V/HandlerThread:线程名:handler-thread,消息标识:2
    

    4. IntentService

    4.1 what is IntentService

    IntentService:IntentService本质上是一个内部封装了Handler和HandlerThread的特殊服务(继承Service),在 IntentService 内有一个工作线程来处理耗时操作。

    4.2 IntentService源码解析(内部机制)

    说明:IntentService本质上是一个封装了HandlerThread和Handler的异步框架,HandlerThread可以在线程中开启循环,利用Handler来发送消息。

    /*
     * Copyright (C) 2008 The Android Open Source Project
     *
     * Licensed under the Apache License, Version 2.0 (the "License");
     * you may not use this file except in compliance with the License.
     * You may obtain a copy of the License at
     *
     *      http://www.apache.org/licenses/LICENSE-2.0
     *
     * Unless required by applicable law or agreed to in writing, software
     * distributed under the License is distributed on an "AS IS" BASIS,
     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     * See the License for the specific language governing permissions and
     * limitations under the License.
     */
    
    package android.app;
    
    import android.annotation.WorkerThread;
    import android.annotation.Nullable;
    import android.content.Intent;
    import android.os.Handler;
    import android.os.HandlerThread;
    import android.os.IBinder;
    import android.os.Looper;
    import android.os.Message;
    
    /**
     * IntentService is a base class for {@link Service}s that handle asynchronous
     * requests (expressed as {@link Intent}s) on demand.  Clients send requests
     * through {@link android.content.Context#startService(Intent)} calls; the
     * service is started as needed, handles each Intent in turn using a worker
     * thread, and stops itself when it runs out of work.
     *
     * <p>This "work queue processor" pattern is commonly used to offload tasks
     * from an application's main thread.  The IntentService class exists to
     * simplify this pattern and take care of the mechanics.  To use it, extend
     * IntentService and implement {@link #onHandleIntent(Intent)}.  IntentService
     * will receive the Intents, launch a worker thread, and stop the service as
     * appropriate.
     *
     * <p>All requests are handled on a single worker thread -- they may take as
     * long as necessary (and will not block the application's main loop), but
     * only one request will be processed at a time.
     *
     * <div class="special reference">
     * <h3>Developer Guides</h3>
     * <p>For a detailed discussion about how to create services, read the
     * <a href="{@docRoot}guide/topics/fundamentals/services.html">Services</a> developer guide.</p>
     * </div>
     *
     * @see android.os.AsyncTask
     */
    public abstract class IntentService extends Service {
        private volatile Looper mServiceLooper;
        private volatile ServiceHandler mServiceHandler;
        private String mName;
        private boolean mRedelivery;
    
        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);
            }
        }
    
        /**
         * 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;
        }
    
        /**
         * Sets intent redelivery preferences.  Usually called from the constructor
         * with your preferred semantics.
         *
         * <p>If enabled is true,
         * {@link #onStartCommand(Intent, int, int)} will return
         * {@link Service#START_REDELIVER_INTENT}, so if this process dies before
         * {@link #onHandleIntent(Intent)} returns, the process will be restarted
         * and the intent redelivered.  If multiple Intents have been sent, only
         * the most recent one is guaranteed to be redelivered.
         *
         * <p>If enabled is false (the default),
         * {@link #onStartCommand(Intent, int, int)} will return
         * {@link Service#START_NOT_STICKY}, and if the process dies, the Intent
         * dies along with it.
         */
        public void setIntentRedelivery(boolean enabled) {
            mRedelivery = enabled;
        }
    
        @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);
        }
    
        @Override
        public void onStart(@Nullable Intent intent, int startId) {
            Message msg = mServiceHandler.obtainMessage();
            msg.arg1 = startId;
            msg.obj = intent;
            mServiceHandler.sendMessage(msg);
        }
    
        /**
         * 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(@Nullable Intent intent, int flags, int startId) {
            onStart(intent, startId);
            return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
        }
    
        @Override
        public void onDestroy() {
            mServiceLooper.quit();
        }
    
        /**
         * Unless you provide binding for your service, you don't need to implement this
         * method, because the default implementation returns null.
         * @see android.app.Service#onBind
         */
        @Override
        @Nullable
        public IBinder onBind(Intent intent) {
            return null;
        }
    
        /**
         * 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)}.
         *               This may be null if the service is being restarted after
         *               its process has gone away; see
         *               {@link android.app.Service#onStartCommand}
         *               for details.
         */
        @WorkerThread
        protected abstract void onHandleIntent(@Nullable Intent intent);
    }
    
    

    4.3 IntentService使用方法

    • 自定义类MyIntentService继承自IntentService
    • 实现构造方法和onHandlerIntent()方法:onHandlerIntent()为异步方法,可执行耗时操作

    (1) IntentServiceTestActivity .java

    package comi.example.liy.mytestdemo;
    
    import android.content.BroadcastReceiver;
    import android.content.Context;
    import android.content.Intent;
    import android.content.IntentFilter;
    import android.os.Bundle;
    import android.support.annotation.Nullable;
    import android.support.v4.content.LocalBroadcastManager;
    import android.support.v7.app.AppCompatActivity;
    import android.util.Log;
    import android.view.View;
    import android.widget.Button;
    import android.widget.ProgressBar;
    import android.widget.TextView;
    
    /**
     * Created by liy on 2019-11-08 9:59
     */
    public class IntentServiceTestActivity extends AppCompatActivity {
    
        private Button button;
        private ProgressBar progressBar;
        private TextView textView;
    
        private Intent intent;
        public final static String ACTION_TYPE_THREAD = "action.type.thread";
    
        private LocalBroadcastManager localBroadcastManager;
        private MyBroadcastReceiver myBroadcastReceiver;
    
        class MyBroadcastReceiver extends BroadcastReceiver{
            @Override
            public void onReceive(Context context, Intent intent) {
                if(intent.getAction()==ACTION_TYPE_THREAD){
                    String status = intent.getStringExtra("status");
                    int progress = intent.getIntExtra("progress",0);
                    Log.v("IntentServiceUpdateInfo","status:" + status + ",progress:" + progress + "%");
                    textView.setText("status:" + status + ",progress:" + progress + "%");
                    progressBar.setProgress(progress);
                }
            }
        }
    
        @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_asynctask);
            button = (Button)findViewById(R.id.button03);
            progressBar = (ProgressBar)findViewById(R.id.progressBar02);
            textView = (TextView)findViewById(R.id.textView01);
    
            button.setOnClickListener(new View.OnClickListener() {
    
                @Override
                public void onClick(View v) {
                    intent = new Intent(IntentServiceTestActivity.this,IntentServiceUpdateInfo.class);
                    startService(intent);
                }
            });
    
            localBroadcastManager = LocalBroadcastManager.getInstance(this);
            myBroadcastReceiver = new MyBroadcastReceiver();
            IntentFilter intentFilter = new IntentFilter();
            intentFilter.addAction(ACTION_TYPE_THREAD);
            localBroadcastManager.registerReceiver(myBroadcastReceiver,intentFilter);
        }
    
        @Override
        protected void onDestroy() {
            super.onDestroy();
            stopService(intent);
            localBroadcastManager.unregisterReceiver(myBroadcastReceiver);
        }
    
    }
    
    

    (2) HandlerThreadTestActivity .java

    package comi.example.liy.mytestdemo;
    
    import android.app.IntentService;
    import android.content.Intent;
    import android.support.v4.content.LocalBroadcastManager;
    import android.util.Log;
    
    /**
     * Created by liy on 2019-11-08 10:10
     */
    public class IntentServiceUpdateInfo extends IntentService {
    
        private boolean isRunning;
        private int count;
    
        private LocalBroadcastManager localBroadcastManager;
    
        public IntentServiceUpdateInfo(){
            super("IntentServiceUpdateInfo");
            Log.v("IntentServiceUpdateInfo","构造方法");
        }
    
        @Override
        public void onCreate() {
            super.onCreate();
            localBroadcastManager = LocalBroadcastManager.getInstance(this);
            Log.v("IntentServiceUpdateInfo","服务启动");
        }
    
        @Override
        protected void onHandleIntent(Intent intent) {
            Log.v("IntentServiceUpdateInfo","重写onHandleIntent()方法处理耗时任务");
            try{
                Thread.sleep(1000);
                isRunning = true;
                count = 0;
                while (isRunning){
                    count++;
                    if (count>=100){
                        isRunning = false;
                        sendThreadStatus("线程结束",count);
                        return;
                    }
                    Thread.sleep(50);
                    sendThreadStatus("线程运行中",count);
                }
            }catch (Exception e){
                e.printStackTrace();
            }
    
        }
    
        //发送进度消息:service通过broadcast向activity传递消息
        private void sendThreadStatus(String status, int progress){
            Intent intent = new Intent(IntentServiceTestActivity.ACTION_TYPE_THREAD);
            intent.putExtra("status",status);
            intent.putExtra("progress",progress);
            localBroadcastManager.sendBroadcast(intent);
        }
    
        @Override
        public void onDestroy() {
            super.onDestroy();
            Log.v("IntentServiceUpdateInfo","服务结束" +count);
        }
        
    }
    
    

    (3) activity_asynctask.xml

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="vertical"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        >
        <TextView
            android:id="@+id/textView01"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            />
        <ProgressBar
            android:id="@+id/progressBar02"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            style="?android:attr/progressBarStyleHorizontal"
            />
        <Button
            android:id="@+id/button03"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:text="更新progressbar"
            />
    </LinearLayout>
    

    5. 拓展

    (1) 更新UI可通过handler,也可以在runOnUiThread这个方法中。

    //更新UI可以在runOnUiThread这个方法或通过handler
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            Bitmap bitmap = BitmapFactory.decodeByteArray(data,0,data.length);
                            imageView.setImageBitmap(bitmap);
                        }
                    });
    

    相关文章

      网友评论

        本文标题:异步消息处理机制

        本文链接:https://www.haomeiwen.com/subject/cmmubctx.html