出于性能优化考虑,android的UI操作并不是线程安全的,这意味着意味着如果有多个线程并发操作UI组件,可能导致线程安全问题,未解决此问题,

从开发的角度来说, Handler 是 Android 消息机制的上层接口, 这使得在开发过程中只需要和 Handler 交互即可。
Handler 的使用过程很简单,通过它可以轻松地将一个任务切换到 Handler 所在的线程中去执行。很多人认为
Handler的作用是更新 UI, 这的确没错,但是更新 UI 仅仅是 Handler 的一个特殊的使用场景.具体来说是这样的:
有时候需要在子线程中进行耗时的 I/O 操作,可能是读取文件或者访问网络等, 当耗时操作完成以后可能需要在 UI 上做一些改变, 由于
Android 开发规范的限制,我们并不能在子线程中访问 UI 控件,否则就会触发程序异常, 这个时候通过Handler 就可 以将更新
UI 的操作切换到主线程中执行。 因此,本质上来说, Handler 并是专门用于更新 UI 的,它只是常被开发者用来更新 UI。

Android 的消息机制主要是指 Handler 的运行机制, Handler 的运行需要底层的MessageQueue 和
Looper 的支撑。 MessageQueue 的中文翻译是消息队列,顾名思义,
它的内部存储了一组消息,以队列的形式对外提供插入和删除的工作。 虽然叫消息队列,但是它的内部存储结构并不是真正的队列,
而是采用单链表的数据结构来存储消息列表。 Looper的中文翻译为循环, 在这里可以理解为消息循环。由于 MessageQueue
只是一个消息的存储单元,它不能去处理消息,而 Looper 就填补了这个功能, Looper
会以无限循环的形式去查找是否有新消息,如果有的话就处理消息,否则就一直等待着。 Looper 中还有一个特殊的概念,那就是
ThreadLocal, ThreadLocal 并不是线程,它的作用是可以在每个线程中存储数据。我们知道, Handler
创建的时候会采用当前线程的 Looper 来构造消息循环系统,那么 Handler 内部如何获取到当前线程的 Looper 呢?
这就要使用 ThreadLocal 了,ThreadLocal可以在不同的线程中互不干扰地存储并提供数据,通过 ThreadLocal
可以轻松获取每个线程的 Looper。当然需要注意的是,线程是默认没有 Looper 的,如果需要使用 Handler 就必须为线程创建
Looper。我们经常提到的主线程,也叫 UI 线程,它就是ActivityThread,ActivityThread被创建时就会初始化
Looper,这也是在主线程中默认可以使用 Handler 的原因。 上面这段话是任玉刚老师书中对于android消息传递机制的描述我觉得描述的非常清晰。

android定下规则:只允许UI线程(主线程)修改Activity里的UI组件

但是应用中有时需要操作UI如获取短信验证码,有个倒计时,为此需要借助Handler消息传递机制

Handler类简介

【1】作用:
1在新启动的线程中发送消息
2在主线程中获取处理消息
主要方法
方法签名
public void handleMessage (Message msg)

子类对象通过该方法接收信息

public final boolean sendEmptyMessage (int what)

发送一个只含有what值的消息

public final boolean sendMessage (Message msg)

发送消息到Handler,通过handleMessage方法接收

public final boolean hasMessages (int what)

监测消息队列中是否还有what值的消息
public final boolean hasMessages (int what,Objectobject)

监测消息队列中是否还有what值的消息且object属性为制定对象的消息

public final boolean post (Runnable r)
将一个线程添加到消息队列

下面一个倒计时例子

public class MainActivity extends Activity {    private Button button;    private  int count;    private  Message message;    private static final int  TIME_DESC=0;    private Handler handler=new Handler(){        @Override        public void handleMessage(Message msg) {            super.handleMessage(msg);        switch (message.what){            case TIME_DESC:                String time= (String) message.obj;                button.setText(time);                break;        }        }    } ;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        button= (Button) findViewById(R.id.button);        button.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {              count=60;                new Thread(new Runnable() {                    @Override                    public void run() {                        while(count>0){                            count--;                            try {                                Thread.sleep(1000);                            } catch (InterruptedException e) {                                e.printStackTrace();                            }                            message=new Message();                            message.obj=count+"秒";                            message.what=TIME_DESC;                            handler.sendMessage(message);                        }                    }                }).start();            }        });    }}

精简一下上面的代码如下

public class MainActivity2 extends Activity {    private Button button;    private  int count;    private  Message message;    private static final int  TIME_DESC=0;    private Handler handler=new Handler(){        @Override        public void handleMessage(Message msg) {            super.handleMessage(msg);            switch (message.what){                case TIME_DESC:                    count--;                    button.setText(count+"秒");                   if(count>0){                       handler.sendEmptyMessage(TIME_DESC);                       try {                           Thread.sleep(1000);                       } catch (InterruptedException e) {                           e.printStackTrace();                       }                   }                    break;            }        }    } ;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        button= (Button) findViewById(R.id.button);         //message初始化        message=new Message();        button.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                count=60;               handler.sendEmptyMessage(TIME_DESC);            }        });    }}

Looper简介

Android中的Looper类,是用来封装消息循环和消息队列的一个类,用于在android线程中进行消息处理。handler其实可以看做是一个工具类,用来向消息队列中插入消息的。

(1) Looper类用来为一个线程开启一个消息循环。
默认情况下android中新诞生的线程是没有开启消息循环的。(主线程除外,主线程系统会自动为其创建Looper对象,开启消息循环。)
Looper对象通过MessageQueue来存放消息和事件。一个线程只能有一个Looper,对应一个MessageQueue。

(2) 通常是通过Handler对象来与Looper进行交互的。Handler可看做是Looper的一个接口,用来向指定的Looper发送消息及定义处理方法。
默认情况下Handler会与其被定义时所在线程的Looper绑定,比如,Handler在主线程中定义,那么它是与主线程的Looper绑定。
mainHandler = new Handler() 等价于new Handler(Looper.myLooper()).
Looper.myLooper():获取当前进程的looper对象,类似的 Looper.getMainLooper() 用于获取主线程的Looper对象。

(3) 在非主线程中直接new Handler() 会报如下的错误:
E/AndroidRuntime( 6173): Uncaught handler: thread Thread-8 exiting due to uncaught exception
E/AndroidRuntime( 6173): java.lang.RuntimeException: Can’t create handler inside thread that has not called Looper.prepare()
原因是非主线程中默认没有创建Looper对象,需要先调用Looper.prepare()启用Looper。

(4) Looper.loop(); 让Looper开始工作,从消息队列里取消息,处理消息。

注意:写在Looper.loop()之后的代码不会被执行,这个函数内部应该是一个循环,当调用mHandler.getLooper().quit()后,loop才会中止,其后的代码才能得以运行。

(5) 基于以上知识,可实现主线程给子线程(非主线程)发送消息。

public class MainActivity3 extends Activity {    private Button button_send;    private Handler handler;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.mainthreadsend);        handler=new Handler();        button_send = (Button) findViewById(R.id.button_send);        button_send.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                MyThread thread = new MyThread();                thread.start();                handler.sendEmptyMessage(0);            }        });    }    class MyThread extends Thread {        @Override        public void run() {            Looper.prepare();            handler = new Handler() {                @Override                public void handleMessage(Message msg) {                    Log.d("handle", "收到主线程发送的消息");                }            };            Looper.loop();        }    }}

结果

更多相关文章

  1. android消息机制总结
  2. Android(安卓)handler使用
  3. Android(安卓)异步消息处理机制(Handler 、 Looper 、MessageQueu
  4. Android消息机制之ThreadLocal浅析
  5. Android多线程下载远程图片
  6. ANDROID音频系统散记之五:如何绕开多媒体音轨的重采样
  7. Android开发实践:多线程编程小结
  8. Android多线程下载远程图片
  9. AsyncTask总结

随机推荐

  1. android 之PopupWindow的使用
  2. 2011.07.06(2)——— android apiDemos 之
  3. Unity—Android通讯
  4. [置顶] Android(安卓)百度地图 简单实现-
  5. CheckedTextView 显示问题
  6. [Android(安卓)Memory] Android(安卓)的
  7. 监听Android应用程序是否卸载成功
  8. android圆角矩形的实现
  9. virtualbox 安装android设置分辨率(自定
  10. 【Android】Android(安卓)Studio百问