软件世界网 购物 网址 三丰软件 | 小说 美女秀 图库大全 游戏 笑话 | 下载 开发知识库 新闻 开发 图片素材
多播视频美女直播
↓电视,电影,美女直播,迅雷资源↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
移动开发 架构设计 编程语言 Web前端 互联网
开发杂谈 系统运维 研发管理 数据库 云计算 Android开发资料
  软件世界网 -> 移动开发 -> 深入了解android中的消息机制Handler -> 正文阅读
移动开发 最新文章
深入了解android中的消息机制Handler
Android
Libgdx之BitmapFont字体
AndroidApp发布到应用市场的流程
Android开发找工作之前先看看这些知识点吧
View的事件分发机制解析
简单介绍了解白鹭引擎Egret
Cocos2d
android获取本地图片(二)
动画特效七:碰撞动画

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

  2016-04-04 00:13:25

什么是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,抛出的异常:

在子线程创建Handler,抛出的异常:

注意:当需要在子线程中创建Handler时,需要先创建一个Looper,因为子线程中没有Looper对象
HandlerThread又是什么?
当我们向创建一个与线程相关的Handler时,我们可以使用HandlerThread,来解决多线程的并发问题.

子线程与主线程如何互发消息:
  • 主线程Handler向子线程发送消息(伪代码)
  • 子线程Handler向主线程发送消息(伪代码)

  • Android在子线程中更新UI的几种方式:
    使用图片吧,以前做的笔记,看着感觉更加清晰..

    非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>
    
    

    执行效果图:

    可能看到这,你已经目瞪口呆了,这怎么可能,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  
    360图书馆 论文大全 母婴/育儿 软件开发资料 网页快照 文字转语音 购物精选 软件 美食菜谱 新闻中心 电影下载 小游戏 Chinese Culture
    生肖星座解梦 三沣玩客 拍拍 视频 开发 Android开发 站长 古典小说 网文精选 搜图网 天下美图 中国文化英文 多播视频 装修知识库
    2017-1-20 13:50:12
    多播视频美女直播
    ↓电视,电影,美女直播,迅雷资源↓
    TxT小说阅读器
    ↓语音阅读,小说下载,古典文学↓
    一键清除垃圾
    ↓轻轻一点,清除系统垃圾↓
    图片批量下载器
    ↓批量下载图片,美女图库↓
      网站联系: qq:121756557 email:121756557@qq.com  软件世界网 --