软件世界网 购物 网址 三丰软件 | 小说 美女秀 图库大全 游戏 笑话 | 下载 开发知识库 新闻 开发 图片素材
多播视频美女直播
↓电视,电影,美女直播,迅雷资源↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
移动开发 架构设计 编程语言 Web前端 互联网
开发杂谈 系统运维 研发管理 数据库 云计算 Android开发资料
  软件世界网 -> 移动开发 -> 深入了解android中的消息机制Handler -> 正文阅读

[移动开发]深入了解android中的消息机制Handler


什么是Handler?
handler是Android给我们提供用来更新UI的一套机制,也是一套消息处理机制.
我们可以使用它发送消息,也可以通过它处理消息.
我们为什么要使用Handler?
Android在设计的时候,就封装了一套消息创建,传递,处理机制,如果不遵循这样的机制,就没有办法更新UI,而且还会抛出异常信息.
例如:大家都知道,更新UI的操作一般都是放在main线程中,当我们需要在子线程中更新UI时,就需要使用到了Handler,虽然在子线程更新Ui的方法有好几种,但内部实现原理基本都是通过Handler发送消息处理的,不要着急,下面会提到.
Handler的使用:
  • sendMessage()方法的使用:
package com.hnthgys.mytext;

import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {
    private TextView tv;
    //创建main线程的Handler
    private Handler handler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            tv.setText("我是通过handler发送消息更新的");
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        tv = (TextView) findViewById(R.id.textview);
        //开启子线程
        new Thread(){
            @Override
            public void run() {
                super.run();
                //例如此处我们正在执行一个耗时操作,执行完毕后发送消息更新ui

                //发送一个空消息
                handler.sendEmptyMessage(0);

                //如果此处我们需要使用执行完耗时操作的数据,可以这样写
                //Message msg = handler.obtainMessage();
                //msg.obj = "数据";
                //handler.sendMessage(msg);

            }
        }.start();


    }
}

  • sendEmptyMessage(); 此方法和sendMessage使用一致,区别就是发送一个空消息.

  • sendMessageDelayed(); 发送一个延时执行的消息

  • post(Runnable);该方法可以在子线程中更新UI,该方法运行在main线程中
  • removeCallbacksAndMessages();移除回调和消息;例如:我们在使Handler轮播一些图片时,想让它停止轮播,就可以使用这个方法.

android为什么要设计只能通过handler来更新UI呢?
最根本的的目的就是解决多线程并发问题.假设如果在一个activity当中,有多个线程去更新UI,并且都没有加锁机制,那么会产生什么样子的问题呢? 更新界面错误.
你可能会说,我可以使用加锁的多线程啊,如果对更新UI的操作都进行加锁处理的话,应用程序的性能会大大下降.
处于对以上问题的考虑,Android给我们提供了一套更新UI的机制,我们只需要遵循这样的机制就可以了.
根本不用关心多线程的问题,所以更新UI的操作,都是在主线程的消息队列当中去轮询处理的.
Handler的原理是什么呢?
一,Handler封装了消息的发送,(主要包括消息发送给谁)
Looper(Handler内部自己的Looper)
1,内部包含一个消息队列,也就是MessageQueue,所有的Handler发送消息
都走向这个消息队列.
2,Looper.loop()方法,就是一个死循环,不断的从MessageQueue中取消息,
如果有消息就处理消息,没有消息就阻塞.
二,MessageQueue,就是一个消息队列,可以添加消息,并处理消息.
三,Handler,内部会跟Lopper进行关联,也就是说在Handler的
内部可以找到Looper,找到了Lopper也就找到 了MessageQueue,
在Handler中发送消息,其实就是向MessageQueue队列中发送消息.
Handler原理总结:
Handler负责发送消息,Loooper负责接收Handler发送的消息,
并直接把消息回传给Handler自己.
MessageQueue就是一个存储消息的容器.
Handler使用中遇到的问题:
在非UI线程中更新UI,抛出的异常:
[img]http://img.blog.csdn.net/20160403182602514
在子线程创建Handler,抛出的异常:
[img]http://img.blog.csdn.net/20160403182657389
注意:当需要在子线程中创建Handler时,需要先创建一个Looper,因为子线程中没有Looper对象
HandlerThread又是什么?
当我们向创建一个与线程相关的Handler时,我们可以使用HandlerThread,来解决多线程的并发问题.
[img]http://img.blog.csdn.net/20160403183104000
子线程与主线程如何互发消息:
  • 主线程Handler向子线程发送消息(伪代码)
    [img]http://img.blog.csdn.net/20160403183254376
  • 子线程Handler向主线程发送消息(伪代码)
    [img]http://img.blog.csdn.net/20160403183421361

Android在子线程中更新UI的几种方式:
使用图片吧,以前做的笔记,看着感觉更加清晰..
[img]http://img.blog.csdn.net/20160403183622721
非UI线程真的不能更新UI吗?
答案是能,对.你没有看错,非UI线程也能更新UI.可能你会觉得我在扯淡,下面看一段代码:
package com.hnthgys.mytext;

import android.os.Bundle;
import android.os.Handler;
import android.support.v7.app.AppCompatActivity;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {
    private TextView tv;
    //创建main线程的Handler
    private Handler handler = new Handler();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        tv = (TextView) findViewById(R.id.textview);
        //开启子线程
        new Thread(){
            @Override
            public void run() {
                super.run();
                //SystemClock.sleep(100);
                tv.setText("我是在子线程中更新的UI");
            }
        }.start();


    }
}

我把布局代码也贴出来,
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
   >


    <TextView
        android:id="@+id/textview"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="呵呵"
        android:textSize="40sp"
        />
</LinearLayout>


执行效果图:
[img]http://img.blog.csdn.net/20160403184312864
可能看到这,你已经目瞪口呆了,这怎么可能,fuck,这完全颠覆了啊…..
主要原因:
当我们在更新UI时,Android中的ViewRootImpl类中的checkThread()方法会检查当前更新UI所在的线程,如图
3937    void More ...checkThread() {
            //检查执行更新UI所在的线程
3938        if (mThread != Thread.currentThread()) {
                //如果不在UI线程,就会抛出下面的异常,大家应该很眼熟吧
3939            throw new CalledFromWrongThreadException(
3940                    "Only the original thread that                 created a view hierarchy can touch its views.");
3941        }
3942    }

查看系统源码后,你会发现,ViewRootImpl类会在 Activity的onResume()方法执行完成后才初始化,这也就解释了上面代码能运行的原因了,但是,你发现没有,我们在子线程中没有做任何的耗时操作,如果我在子线程中添加这句代码:
SystemClock.sleep(100);

那么系统将会抛出异常:”Only the original thread that created a view hierarchy can touch its views.”
不能在非UI线程中更新UI.
那么问题来了,如果ViewRootImpl类没有初始化完成,那么view视图是如何显示出来的呢???我也正在解决中…….
另外,当我们在子线程中获取到ViewRoot,我们可以调用addView()方法在子线程中更新UI,这其中的详情就靠大家去探索了…..
......显示全文...
    点击查看全文


上一篇文章           查看所有文章
2016-04-04 00:13:10  
移动开发 最新文章
深入了解android中的消息机制Handler
Android
Libgdx之BitmapFont字体
AndroidApp发布到应用市场的流程
Android开发找工作之前先看看这些知识点吧
View的事件分发机制解析
简单介绍了解白鹭引擎Egret
Cocos2d
android获取本地图片(二)
动画特效七:碰撞动画
360图书馆 软件开发资料 文字转语音 购物精选 软件下载 美食菜谱 新闻资讯 电影视频 小游戏 Chinese Culture 股票 租车
生肖星座 三丰软件 视频 开发 短信 中国文化 网文精选 搜图网 美图 阅读网 多播 租车 短信 看图 日历 万年历 2017年11日历
2017-11-19 0:01:10
多播视频美女直播
↓电视,电影,美女直播,迅雷资源↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  软件世界网 --