201709013工作日记--Android消息机制HandlerThread
1.首先来看一个常规的handler用法:
在主线程中建立一个handler:
private Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what) {
                case 0:
                    mTestTV.setText("This is handleMessage");//更新UI
                    break;
            }
        }
    };
在子线程中进行耗时操作,结束后发送消息,主线程收到消息后进行更新UI操作。
new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(1000);//在子线程有一段耗时操作,比如请求网络
                    mHandler.sendEmptyMessage(0);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
2.现在来看看handler.post()的版本:
private Handler mHandler;//全局变量
@Override
protected void onCreate(Bundle savedInstanceState) {
mHandler = new Handler();
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(1000);//在子线程有一段耗时操作,比如请求网络
mHandler.post(new Runnable() {
@Override
public void run() {
mTestTV.setText("This is post");//更新UI
}
});
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
耗时操作完成之后,直接在handler开启的子线程中进行了更新UI的操作。post和sendMessage原理都是封装成Message,并且最终都调用了enqueueMessage()一个无限循环将消息加入到消息队列中(链表的形式)。翻看MessageQueue的方法,我们找到了next(),代码太长,不赘述,我们知道它是用来把消息取出来的就行了。不过这个方法是在什么地方调用的呢,不是在Handler中,我们找到了Looper这个关键人物,我叫他环形使者,专门负责从消息队列中拿消息。参考博客:http://blog.csdn.net/ly502541243/article/details/52062179/
3.HandlerThread用法
(1)创建HandlerThread并启动
mThread = new HandlerThread("handler_thread");
mThread.start();
(2)创建处理任务的handler和在主线程中更新UI的handler
一句话来总结就是:通过handler与HandlerThread进行绑定相当于开启了一个子线程,在这个子线程中处理任务,处理后的任务形成消息或者其他数据形式。再通过主线程的handler.sendMessage(子线程结果),发送给主线程的handler,进行UI操作。
其中处理任务的mWorkHandler与handlerThread关联起来,那么这个Handler对象就是与HandlerThread这个线程绑定了(这时就不再是与UI线程绑定了,这样它处理耗时操作将不会阻塞UI),它将在handleMessage(Message msg)中处理耗时任务,之后在mUIHandler对UI进行刷新,如果在handleMessage()执行完成后,如果想要更新UI,可以用UI线程的Handler发消息给UI线程来更新。
mWorkHandler = new Handler(mThread.getLooper());
mUIHandler = new Handler();
(3)在合适的时机退出HandlerThread,比如activity中的onDestroy(),方法有quit()和quitSafely()
下面我们看一个比较典型的handlerThread的使用过程:参考http://blog.csdn.net/javazejian/article/details/52426353
public class HandlerThreadActivity extends Activity {
    /**
     * 图片地址集合
     */
    private String url[]={
            "http://img.blog.csdn.net/20160903083245762",
            "http://img.blog.csdn.net/20160903083252184",
            "http://img.blog.csdn.net/20160903083257871",
            "http://img.blog.csdn.net/20160903083257871",
            "http://img.blog.csdn.net/20160903083311972",
            "http://img.blog.csdn.net/20160903083319668",
            "http://img.blog.csdn.net/20160903083326871"
    };
    private ImageView imageView;
    private Handler mUIHandler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            LogUtils.e("次数:"+msg.what);
            ImageModel model = (ImageModel) msg.obj;
            imageView.setImageBitmap(model.bitmap);
        }
    };
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_handler_thread);
        imageView= (ImageView) findViewById(R.id.image);
        //创建异步HandlerThread
        HandlerThread handlerThread = new HandlerThread("downloadImage");
        //必须先开启线程
        handlerThread.start();
        //子线程Handler
        Handler childHandler = new Handler(handlerThread.getLooper(),new ChildCallback());
        for(int i=0;i<7;i++){
            //每个1秒去更新图片
            childHandler.sendEmptyMessageDelayed(i,1000*i);
        }
    }
    /**
     * 该callback运行于子线程
     */
    class ChildCallback implements Handler.Callback {
        @Override
        public boolean handleMessage(Message msg) {
            //在子线程中进行网络请求
            Bitmap bitmap=downloadUrlBitmap(url[msg.what]);
            ImageModel imageModel=new ImageModel();
            imageModel.bitmap=bitmap;
            imageModel.url=url[msg.what];
            Message msg1 = new Message();
            msg1.what = msg.what;
            msg1.obj =imageModel;
            //通知主线程去更新UI
            mUIHandler.sendMessage(msg1);
            return false;
        }
    }
    private Bitmap downloadUrlBitmap(String urlString) {
        HttpURLConnection urlConnection = null;
        BufferedInputStream in = null;
        Bitmap bitmap=null;
        try {
            final URL url = new URL(urlString);
            urlConnection = (HttpURLConnection) url.openConnection();
            in = new BufferedInputStream(urlConnection.getInputStream(), 8 * 1024);
            bitmap=BitmapFactory.decodeStream(in);
        } catch (final IOException e) {
            e.printStackTrace();
        } finally {
            if (urlConnection != null) {
                urlConnection.disconnect();
            }
            try {
                if (in != null) {
                    in.close();
                }
            } catch (final IOException e) {
                e.printStackTrace();
            }
        }
        return bitmap;
    }
}
在这个案例中,我们创建了两个Handler,一个用于更新UI线程的mUIHandler和一个用于异步下载图片的childHandler。最终的结果是childHandler会每个隔1秒钟通过sendEmptyMessageDelayed方法去通知ChildCallback的回调函数handleMessage方法去下载图片并告诉mUIHandler去更新UI界面,以上便是HandlerThread常规使用。
下面来看另外一个例子,使用post方式通信:
public class MainActivity extends AppCompatActivity {
    private TextView mTvServiceInfo;
    private HandlerThread mCheckMsgThread;
    private Handler mCheckMsgHandler;
    private boolean isUpdateInfo;
    private static final int MSG_UPDATE_INFO = 0x110;
    //与UI线程管理的handler
    private Handler mHandler = new Handler();
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.i("~~~~~~~~~~~~~~~now is ",Thread.currentThread().getName());
        setContentView(R.layout.activity_main);
        //创建后台线程
        mCheckMsgThread = new HandlerThread("check-message-coming");
        mCheckMsgThread.start();
        mCheckMsgHandler = new Handler(mCheckMsgThread.getLooper()){
            @Override
            public void handleMessage(Message msg) {
                try
                {
                    //模拟耗时,处理任务(模拟实时获取大盘数据),处理完成之后,通知mHandler完成界面更新
                    Thread.sleep(1000);
                    mHandler.post(new Runnable()
                    {
                        @Override
                        public void run()
                        {
                            String result = "实时更新中,当前大盘指数:<font color='red'>%d</font>";
                            result = String.format(result, (int) (Math.random() * 3000 + 1000));
                            mTvServiceInfo.setText(Html.fromHtml(result));
                        }
                    });
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                if (isUpdateInfo)
                {
                    mCheckMsgHandler.sendEmptyMessageDelayed(MSG_UPDATE_INFO, 1000);
                }
            }
        };
    }
}
4.handlerThread的一些细节补充学习:
HandlerThread本质上是一个线程类,继承自Thread类,但是HandlerThread有自己的Looper对象,可以进行looper循环,不断从MessageQueue中取消息。
HandlerThread的特点
- HandlerThread将loop转到子线程中处理,说白了就是将分担MainLooper的工作量,降低了主线程的压力,使主界面更流畅。
 - 开启一个线程起到多个线程的作用。处理任务是串行执行,按消息发送顺序进行处理。
相比多次使用new Thread(){…}.start()这样的方式节省系统资源。
但是由于每一个任务都将以队列的方式逐个被执行到,一旦队列中有某个任务执行时间过长,那么就会导致后续的任务都会被延迟处理。 - HandlerThread拥有自己的消息队列,它不会干扰或阻塞UI线程。
 - 通过设置优先级就可以同步工作顺序的执行,而又不影响UI的初始化;
 - HandlerThread本质上就是一个普通Thread,只不过内部建立了Looper
 
总结
HandlerThread比较适用于单线程+异步队列的场景,比如IO读写操作,耗时不多而且也不会产生较大的阻塞。对于网络IO操作,HandlerThread并不适合,因为它只有一个线程,还得排队一个一个等着
201709013工作日记--Android消息机制HandlerThread的更多相关文章
- 201709012工作日记--Android消息机制
		
1. android的消息机制——Handler机制 参考:http://www.jianshu.com/p/9e4d1fab0f36. Android异步消息处理机制完全解析,带你从源码的角度理解: ...
 - 201709013工作日记--Android异步通信AsyncTask
		
参考相关博客:http://blog.csdn.net/liuhe688/article/details/6532519 在Android中实现异步任务机制有两种方式,Handler和AsyncTas ...
 - Android消息机制
		
每一个Android应用在启动的时候都会创建一个线程,这个线程被称为主线程或者UI线程,Android应用的所有操作默认都会运行在这个线程中. 但是当我们想要进行数据请求,图片下载,或者其他耗时操作时 ...
 - Android消息机制不完全解析(上)
		
Handler和Message是Android开发者常用的两个API,我一直对于它的内部实现比较好奇,所以用空闲的时间,阅读了一下他们的源码. 相关的Java Class: androi ...
 - Android 消息机制 (Handler、Message、Looper)
		
综合:http://blog.csdn.net/dadoneo/article/details/7667726 与 http://android.tgbus.com/Android/androidne ...
 - Android开发之漫漫长途 ⅥI——Android消息机制(Looper Handler MessageQueue Message)
		
该文章是一个系列文章,是本人在Android开发的漫漫长途上的一点感想和记录,我会尽量按照先易后难的顺序进行编写该系列.该系列引用了<Android开发艺术探索>以及<深入理解And ...
 - Android开发之漫漫长途 Ⅶ——Android消息机制(Looper Handler MessageQueue Message)
		
该文章是一个系列文章,是本人在Android开发的漫漫长途上的一点感想和记录,我会尽量按照先易后难的顺序进行编写该系列.该系列引用了<Android开发艺术探索>以及<深入理解And ...
 - Android消息机制探索(Handler,Looper,Message,MessageQueue)
		
概览 Android消息机制是Android操作系统中比较重要的一块.具体使用方法在这里不再阐述,可以参考Android的官方开发文档. 消息机制的主要用途有两方面: 1.线程之间的通信.比如在子线程 ...
 - Android消息机制1-Handler(Java层)(转)
		
转自:http://gityuan.com/2015/12/26/handler-message-framework/ 相关源码 framework/base/core/java/andorid/os ...
 
随机推荐
- 两个关于URL解析的例子
			
例一: /* 解析URL查寻串中的name=value参数对 将name=value对存储在对象属性中,并返回对象 alert(getQuery().name) */ function getQuer ...
 - libUpnp缓冲区溢出、拒绝服务等漏洞分析
			
该漏洞存在于UPnP™设备的便携式SDK中,也叫做 libupnp.这个库是用来实现媒体播放(DLAN)或者NAT地址转换(UPnP IGD).智能手机上的应用程序可用这些功能播放媒体文件或者利用用户 ...
 - 第一个struct2程序(2)
			
第三步 需要使用ActionForm了.在Struts1.x中,必须要单独建立一个ActionForm类(或是定义一个动作Form),而在Struts2中ActionForm和Action已经二合一了 ...
 - 实现spring IOC的常见二种方法  setter注入与构造器注入
			
案例: beans.xml配置 <?xml version="1.0" encoding="UTF-8"?><beansxmlns=" ...
 - Containerpilot 配置文件reload
			
containerpilot -reload -config ./containerpilot.json 进程号不变,重新加载配置文件
 - keynote
			
[keynote] 1.如何保证文档加载完才运行代码? 2.元素选择器. 3.属性选择器. 4.更新css. 5.更复杂的例子. 6.常用事件. 7.hide & slow 8.您可以使用 t ...
 - LOG4J spring与mybatis整合
			
1.导入包log4j-1.2.17.jar <dependency> <groupId>log4j</groupId> ...
 - C++ 静态数据成员和静态成员函数
			
一 静态数据成员: 1.静态数据成员的定义. 静态数据成员实际上是类域中的全局变量.所以,静态数据成员的定义(初始化)不应该被放在头文件中,因为这样做会引起重复定义这样的错误.即使加上#ifndef ...
 - Inside Triangle
			
Inside Triangle https://hihocoder.com/contest/hiho225/problem/1 时间限制:10000ms 单点时限:1000ms 内存限制:256MB ...
 - 配置Maven从私服下载构件
			
--------------------siwuxie095 配置 Maven 从私服下载构件 从 Nexus ...