下面接着上篇继续谈谈我对Handler机制的认识。

五、Handler, Looper, MessageQueue的关系详解

  1. 关系图见上一篇http://blog.csdn.net/u014294166/article/details/50677910

  2. ActivityThread会创建所有的Activity并回调所有的Activity的方法,同时默认创建main线程,在创建main线程中会创建Looper,在创建Looper过程中又会默认创建Message。
    源码跟踪分析如下:(先用word做的处理)
    Android--Handler机制(二)(Android Studio)_第1张图片

  3. Handler和Looper的关联源码
    Android--Handler机制(二)(Android Studio)_第2张图片
  4. Looper轮询

小结:Handler(sendMessage())负责发送消息,Looper(Looper.looper())负责接收Handler发送的消息,并直接把消息传给Handler自己(handMessage())。MessageQueue就是一个容器。

六、Handler与子线程

  1. 自定义与线程相关的Handler
/** * 自定义与线程相关的Handler */public class MainActivity extends AppCompatActivity {    private Handler mainHandler = new Handler(){        @Override        public void handleMessage(Message msg) {            System.out.println("用来更新主线程中UI的handler---->" + Thread.currentThread());        }    };    class MyThread implements Runnable{        private Handler handler;// handler的自定义线程        // 以下注释处的过程已经通过以上源码分析说明        @Override        public void run() {            Looper.prepare();// 创建一个loop对象            handler = new Handler(){// 获取当前线程的Looper对象                @Override                public void handleMessage(Message msg) {                    //Toast.makeText(MainActivity.this, "current thread:" + Thread.currentThread(), Toast.LENGTH_LONG).show();                    System.out.println("自定义的用来更新UI的handler------>" + Thread.currentThread());                }            };            Looper.loop();// 死循环处理消息        }    }    @Override    protected void onCreate(Bundle savedInstanceState){        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        MyThread myThreadt = new MyThread();        new Thread(myThreadt).start();        try {            Thread.sleep(1000);        } catch (InterruptedException e) {            e.printStackTrace();        }        myThreadt.handler.sendEmptyMessage(1);// handler自定义的线程        mainHandler.sendEmptyMessage(1);// 主线程的handler        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);        setSupportActionBar(toolbar);        FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);        fab.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View view) {                Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)                        .setAction("Action", null).show();            }        });    }}

耗时操作一般不直接在UI主线程上进行,否则容易出现卡死现象。

2 . HandlerThread
HandlerThread 继承于Thread,其本质就是Thread。与普通的Thread的差别在于,HandlerThread有Looper 成员变量,即主要的区别就在Looper的创建上,具体区别如下:
(1). 在普通Thread中实例化Handler时的一般步骤是:在线程run()方法当中先调用Looper.prepare()初始化Looper,然后再run()方法最后调用Looper.loop(),这样我们就在该线程当中创建好Looper。(注意:Looper.loop()方法默认是死循环)
(2). 在HandlerThread中创建一个HandlerThread即创建了一个Looper的线程,步骤如下:
*创建一个HandlerThread,即创建了一个包含Looper的线程。
HandlerThread handlerThread = new HandlerThread(“HandlerThread”);
handlerThread.start(); //创建HandlerThread后一定要记得start()
获取HandlerThread的Looper
Looper looper = handlerThread.getLooper();
创建Handler,通过Looper初始化
Handler handler = new Handler(looper);*

可以避免多线程并发时出现的空指针异常问题。比如说线程切换时Handler所需要Looper还没有创建。
protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        handlerThread = new HandlerThread("HandlerThread");        handlerThread.start();// !!        // Handler获取指定的Looper,无参时为默认个给定的Looper        handler = new Handler(handlerThread.getLooper()){            @Override            public void handleMessage(Message msg) {                System.out.println("current thread----->" + Thread.currentThread());            }        };        handler.sendEmptyMessage(1);// 以上三步创建HandlerThread,然后通过handler发送消息        //handlerThread.quit();// 如果想让HandlerThread退出,则需要调用handlerThread.quit();    }

3 . 主线程向子线程发送消息

   以上所谈的都是子线程向主线程发送消息,通知主线程更新UI,但是也有主线程向子线程发送消息的情况。下面谈谈这种情况。
public class MainActivity extends AppCompatActivity implements View.OnClickListener {    private Button b_send;// 发送消息    private Button b_stop;// 停止发送消息    // 主线程的Handler    private Handler mainHandler = new Handler(){        @Override        public void handleMessage(Message msg) {            Message message = new Message();            System.out.println("=====》Main Handler");            // 在主线程中给子线程每秒发送一个message            subHandler.sendMessageDelayed(message, 1000);        }    };    private Handler subHandler;// 子线程的Handler    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        b_send = (Button) findViewById(R.id.btn_send);        b_stop = (Button) findViewById(R.id.btn_stop);        b_send.setOnClickListener(this);        b_stop.setOnClickListener(this);        // 子线程的looper的轮询是通过创建HandlerThread指定的        HandlerThread hthread = new HandlerThread("Handler Thread");        hthread.start();        subHandler = new Handler(hthread.getLooper()){            @Override            public void handleMessage(Message msg) {                Message message = new Message();                System.out.println("=====》Sub Handler");                // 在子线程中给主线程每秒发送一个message                mainHandler.sendMessageDelayed(message, 1000);            }        };    }    @Override    public void onClick(View v) {        switch (v.getId()){            case R.id.btn_send:                mainHandler.sendEmptyMessage(1);                break;            case R.id.btn_stop:                mainHandler.removeMessages(1);                break;            default:                break;        }    }}
   子线程中利用主线程的Handler向主线程发消息,主线程中利用子线程的Handler向子线程发消息。

七、Android中更新UI的几种方式

  • handler的post
  • runOnUiThread
  • handler的sendMessage
  • View控件自身调用post方法
public class MainActivity extends AppCompatActivity {    private TextView tv;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        tv = (TextView) findViewById(R.id.tv);        //updateUI1();        //updateUI2();        //updateUI3();        updateUI4();    }    public void updateUI1(){        new MyThread().start();    }    class MyThread extends Thread{        @Override        public void run() {            runOnUiThread(new Runnable() {                @Override                public void run() {                    try {                        Thread.sleep(2000);                        tv.setText("使用runOnUiThread的方法更新UI");                    } catch (InterruptedException e) {                        e.printStackTrace();                    }                }            });        }    }    public void updateUI2(){        Handler handler = new Handler();        handler.post(new Runnable() {            @Override            public void run() {                try {                    Thread.sleep(2000);                    tv.setText("Handler的post方法更新UI");                } catch (InterruptedException e) {                    e.printStackTrace();                }            }        });    }    private Handler handler3 = new Handler(){        @Override        public void handleMessage(Message msg) {            if (msg.what == 3){                tv.setText("利用Handler的sendMessage方法更新UI");            }        }    };    public void updateUI3(){        new Thread(new MyThread3()).start();    }    class MyThread3 implements Runnable{        @Override        public void run() {            try {                Thread.sleep(2000);                handler3.sendEmptyMessage(3);            } catch (InterruptedException e) {                e.printStackTrace();            }        }    }    public void updateUI4(){        tv.post(new Runnable() {            @Override            public void run() {                try {                    Thread.sleep(1000);                    tv.setText("View控件自身调用post方法更新UI");                } catch (InterruptedException e) {                    e.printStackTrace();                }            }        });    }}

八、再谈“非UI线程更新UI”的问题

(1). 如下代码能正常更新UI
Android--Handler机制(二)(Android Studio)_第3张图片
(2). 如下代码报如下异常:
FATAL EXCEPTION: Thread-186 android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
Android--Handler机制(二)(Android Studio)_第4张图片

    不难看出,Android系统框架在对非UI线程直接操作UI信息进行判断的时候,准确度不够。在时间差内(代码片段中进行耗时操作,在本例中使用Thread.sleep模拟耗时操作)是可以在非UI线程直接更新UI信息的。

原因分析:
一步步查看setText()源码做分析:View中是通过如下代码检测当前线程是否是UI线程的,其中mThread即主线程。
这里写图片描述
View视图是通过ViewRootImpl类来绘制的,ViewRootImpl是在调用onResume()方法时创建的,而onResume()方法是在onCreate()之后调用的,在不休眠的情况下,ViewRootImpl还没有被创建出来,进而没来得及调用TextView里setText()方法后续的checkThread()方法。

更多相关文章

  1. android实现app通过jni调用C/C++方法
  2. android为按钮添加事件的三种方法
  3. Android在初始化时弹出popwindow的方法 .
  4. android开发环境搭建最新方法
  5. Android自定义属性 及 TypedArray的使用方法
  6. android程序退出当前activity的方法
  7. 获取Android的key的MD5和SHA1的方法
  8. Android AsyncTask两种线程池分析和总结
  9. Android中杀进程的几种方法 (1) - killBackgroundProcesses

随机推荐

  1. 知识主题间先序关系挖掘
  2. 深度学习模型训练全流程!
  3. Linux安装
  4. 没搞明白哪里错了 我的天
  5. 我的XGBoost学习经历及动手实践
  6. Linux相关网络基础详解——OSI&TCP/IP&数
  7. 如何优雅地展示机器学习项目!
  8. 数据分析之Pandas合并操作总结
  9. 在期数较短的微观面板数据中使用双重差分
  10. k8s 网络