Android Handler使用案例详解

什么是Handler?

Handler可以发送和处理消息对象或Runnable对象,这些消息对象和Runnable对象与一个线程相关联。每个Handler的实例都关联了一个线程和线程的消息队列。当创建了一个Handler对象时,一个线程或消息队列同时也被创建,该Handler对象将发送和处理这些消息或Runnable对象。

handler类有两种主要用途:

  • 执行Runnable对象,还可以设置延迟。
  • 两个线程之间发送消息,主要用来给主线程发送消息更新UI。

为什么要用Handler

解决多线程并发问题,假设如果在一个activity中,有多个线程去更新ui,并且都没有加锁机制,那界面显示肯定会不正常。于是andoird官方就封装了一套更新ui的机制,也可以用handler来实现多个线程之间的消息发送。

如何使用Handler

handler常用的方法有以下这些:

post(Runnable)
postAtTime(Runnable,long)
postDelayed(Runnable,long)
sendEmptyMessage(int)
sendMessage(Message)
sendMessageAtTime(Message,long)
sendMessageDelayed(Message,long)

我们可以看到这些方法主要分为两类,一种是传入一个Runnable对象,一种是传入一个Message对象。

用代码来学习post一个Runnable对象

先创建Handler对象,直接new一个就行

private Handler handler=new Handler();

实现Runnable接口,用匿名实现方式,重写run方法,就打印一个字符串。

private Runnable runnable=new Runnable() {
        @Override
        public void run() {
            Log.i("MainActivity","Handler Runnable");
        }
};

然后我们调用handler的post方法,这里需要注意的是,post一个Runnable对象,底层用的是回调,不会开启一个新的线程,所有Runnable的run方法还是在主线程里面。是可以更新UI的。

handler.post(runnable);//执行
handler.postDelayed(runnable,2000);//延迟2秒后执行

运行程序,控制台打印的log如下:

05-18 19:17:14.901 17750-17750/com.ansen.handler I/MainActivity: Handler Runnable
05-18 19:17:16.901 17750-17750/com.ansen.handler I/MainActivity: Handler Runnable

从上面的log我们可以看到两条Log的时间相差两秒。这是因为我们用postDelayed方法的时候第二个参数设置了两秒的延迟。

使用sendMessage方法传递消息

从方法的名字上我们可以理解用来发送消息,这个方法在android中使用频率比较高,因为在Android中多线程中是不能更新UI的,必须要通过Handler把消息传递给UI线程,才能更新UI。当然也可以用Handler来两个子线程发送消息。

我们给activity_main文件中TextView控件设置一个id,然后在MainActivity中查找这个控件,在多线程的for循环中给TextView赋值。增加后的代码如下:

textview= (TextView) findViewById(R.id.textview);
new Thread(new Runnable(){
    @Override
    public void run(){
        for(int i=1;i<=100;i++){
            Log.i("MainActivity","当前值是:"+i);
            textview.setText("当前值是:"+i);
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}).start();

重新运行代码,程序奔溃。控制台打印如下log:

android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
at android.view.ViewRootImpl.checkThread(ViewRootImpl.java:6024)
at android.view.ViewRootImpl.requestLayout(ViewRootImpl.java:820)

这是因为在android中不能在多线程中更新UI造成的。

每个应用启动的时候,Android会启动一个对应的主线程用来处理UI相关的事情,例如用户的按键事件,用户接触屏幕的事件以及屏幕绘图事件,并把相关的事件分发到对应的组件进行处理,所以主线程通常又被叫做UI线程。

这个时候我们就会用到Android的Handle类,Handle可以帮我们解决多线程不能更新UI问题,这里我们只要知道使用这个类就行,在后面我们会详细介绍它的原理。

接下来我们看如何用handler在主线程中接受子线程的消息,并且更新UI。首先new一个Handler的时候实现他的handleMessage方法,修改后的代码如下:

private Handler handler=new Handler(){
    @Override
    public void handleMessage(Message msg) {
        if(msg.what==UPDATE_UI){
            textview.setText("当前值是:"+msg.obj);
        }
    }
};

我们可以看到把更新TextView的代码放到这里来了,并且用到handleMessage的msg参数。这个对象我们常用的一般就两个属性,what就是一个标示,我们发送消息的时候必需要指定值。obj:发送消息的参数。

再来看看多线程的run方法做了哪些改动,首先调用obtainMessage方法,这个方法呢是从消息池里面返回一个Message对象,如果消息池没有才会创建对象,这样避免一直去new Message对象。message对象有what属性是必需要赋值的,是一个int类型。前面我们讲到过了,是一个标示。obj是发送消息用来传参,这里我们传入的是i的值。最后调用handler.sendMessage(message)方法。然后我们handler的handleMessage方法就会回调。

new Thread(new Runnable(){
            @Override
            public void run(){
                for(int i=1;i<=100;i++){
                    Log.i("MainActivity","当前值是:"+i);
                    Message message=handler.obtainMessage();
                    message.what=UPDATE_UI;
                    message.obj=i;
                    handler.sendMessage(message);
                    try {
                        Thread.sleep(200);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
}).start();

还有sendEmptyMessage跟sendMessageDelayed方法我就不一一给大家解释了,有兴趣的朋友自己去实现一下。

源码下载

到此这篇关于Android Handler使用案例详解的文章就介绍到这了,更多相关Android Handler使用内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Android Handler的postDelayed()关闭的方法及遇到问题

    前言 最近在使用Handler的时候 发现了一个错误的使用方法 就是直接new 类似这样 new Handler().postDelayed(new Runnable() { @Override public void run() { showPaySuccessDialog.dismiss(); } }, 1000); 这种用法对于业务简单的情况 也没错 比如 定时关闭一个dialog 但是对于复杂的业务场景 这么用是不对的 也不是不对吧 这么用的话有bug 遇到的问题 我用 直接new Ha

  • Android HandlerThread案例详解

    HandlerThread 顾名思义就是一种可以使用 Handler 的 Thread.日常开发中我们经常会通过创建一个 Thread 去执行任务,有多个任务就多创建几个线程实现,这时候可能出现线程同步的问题.不过有时候我们并不需要很强的并发性,只需保证按照顺序地执行各个任务即可,有什么好办法实现呢?第一反应想到的可能是通过 Executors.newSingleThreadExecutor() 方法来创建一个 SingleThreadExecutor,来统一所有的任务到一个线程中,然后按顺序执

  • android利用handler实现倒计时功能

    本文实例为大家分享了android利用handler实现倒计时的具体代码,供大家参考,具体内容如下 xml <?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app=&qu

  • Android Handler机制的工作原理详析

    写在前面 上一次写完Binder学习笔记之后,再去看一遍Activity的启动流程,因为了解了Binder的基本原理,这次看印象会更深一点,学习效果也比以前好很多.本来打算直接来写Activity的启动流程的,但总觉得Handler也需要写一下,知道Handler和Binder的原理后,再去看Activity的启动流程,应该也没什么问题了.虽然网上已经有很多Handler相关的文章了,而且Handler机制的上层原理也并不难,还是决定写一下,因为我想构建自己的知识体系.也希望给看我博客的朋友们一

  • 详解Android Handler机制和Looper Handler Message关系

    概述 我们就从以下六个问题来探讨Handler 机制和Looper.Handler.Message之前的关系? 1.一个线程有几个Handler? 2.一个线程有几个Looper?如何保证? 3.Handler内存泄漏原因?为什么其他的内部类没有说过这个问题? 4.为何主线程可以new Handler?如果在想要在子线程中new Handler 要做些什么准备? 5.子线程中维护的Looper,消息队列无消息的时候的处理方案是什么?有什么用? 6.Looper死循环为什么不会导致应用卡死? 一.

  • 深入Android HandlerThread 使用及其源码完全解析

    关联篇:深入Android的消息机制源码详解-Handler,MessageQueue与Looper关系 关联篇:Handler内存泄漏及其解决方案 本篇我们将来给大家介绍HandlerThread这个类,以前我们在使用线程执行一个耗时任务时总会new一个Thread的线程去跑,当任务执行完后,线程就会自动被销毁掉,如果又由新的任务,我们又得新建线程.....我们假设这样的一个情景,我们通过listview去加载图文列表,当我们往下滑动时,这时需要不断去请求网络资源,也就是需要不断开线程去加载

  • Android Handler使用案例详解

    什么是Handler? Handler可以发送和处理消息对象或Runnable对象,这些消息对象和Runnable对象与一个线程相关联.每个Handler的实例都关联了一个线程和线程的消息队列.当创建了一个Handler对象时,一个线程或消息队列同时也被创建,该Handler对象将发送和处理这些消息或Runnable对象. handler类有两种主要用途: 执行Runnable对象,还可以设置延迟. 两个线程之间发送消息,主要用来给主线程发送消息更新UI. 为什么要用Handler 解决多线程并

  • Android Handler的使用详解

    在Android开发中,我们经常会遇到这样一种情况:在UI界面上进行某项操作后要执行一段很耗时的代码,比如我们在界面上点击了一个"下载"按钮,那么我们需要执行网络请求,这是一个耗时操作,因为不知道什么时候才能完成.为了保证不影响UI线程,所以我们会创建一个新的线程去执行我们的耗时的代码.当我们的耗时操作完成时,我们需要更新UI界面以告知用户操作完成了.所以我们可能会写出如下的代码: package ispring.com.testhandler; import android.app.

  • Android LayoutParams使用案例详解

    LayoutParams是什么? LayoutParams主要保存了一个View的布局参数,因此可以使用LayoutParams来改变布局参数从而达到View位置的效果,一般在自定义View的时候使用. LayoutParams怎么用? 如果父控件是LinearLayout,需要使用LinearLayout.LayoutParams 代码如下: LinearLayout.LayoutParams layoutParams=(LinearLayout.LayoutParams)getLayoutP

  • Android ActivityManager使用案例详解

    前言 Activity可以获取运行中的应用信息,可以获取到servcie,process,app,memory,Task信息等. 获取信息 ActivityManager.MemoryInfo MemoryInfo中重要的字段:availMem(系统可用内存),totalMem(总内存),threshold(低内存阈值,即低内存的临界线),lowMemory(是否为低内存状态) Debug.MemoryInfo Debug.MemoryInfo主要用于获取进程下的内存信息. ActivityMa

  • Android之AttributeSet案例详解

    public interface AttributeSet { /** * Returns the number of attributes available in the set. * * @return A positive integer, or 0 if the set is empty. */ public int getAttributeCount(); /** * Returns the name of the specified attribute. * * @param in

  • Android VelocityTracker使用案例详解

       VelocityTracker顾名思义即速度跟踪,在android中主要应用于touch even.VelocityTracker通过跟踪一连串事件实时计算出当前的速度,这样的用法在android系统空间中随处可见,比如Gestures中的Fling, Scrolling等.    VelocityTracker主要用跟踪触摸屏事件(flinging事件和其他gestures手势事件)的速率.用addMovement(MotionEvent)函数将Motion event加入到Veloci

  • Android GridLayout使用案例详解

    目录 一.简介 二.常用属性介绍 三.平分问题 四.小米计算器效果 五.动态加载 一.简介 GridLayout是Android4.0引入的网格布局,使用它可以减少布局嵌套.也算是常用,但一直没仔细看过,今天研究一下 二.常用属性介绍 GridLayout 使用属性 属性 作用 android:columnCount 最大列数 android:rowCount 最大行数 android:orientation GridLayout中子元素的布局方向 android:alignmentMode a

  • Android Handler内存泄漏详解及其解决方案

    关联篇:深入Android的消息机制源码详解-Handler,MessageQueue与Looper关系 关联篇:HandlerThread 使用及其源码完全解析 在android开发过程中,我们可能会遇到过令人奔溃的OOM异常,面对这样的异常我们是既熟悉又深恶痛绝的,因为造成OOM的原因有很多种情况,如加载图片过大,某已不再使用的类未被GC及时回收等等......本篇我们就来分析其中一种造成OOM的场景,它就是罪恶的内存泄漏.对于这样的称呼,我们并不陌生,甚至屡次与之"并肩作战",

  • Android Handle原理(Looper,Handler和Message三者关系案例详解

    介绍 前面的内容对Handler做了介绍,也讲解了如何使用handler,但是我们并不知道他的实现原理.本文从源码的角度来分析如何实现的. 首先我们得知道Handler,Looper,Message Queue三者之间的关系 - Handler封装了消息的发送,也负责接收消.内部会跟Looper关联. - Looper 消息封装的载,内部包含了MessageQueue,负责从MessageQueue取出消息,然后交给Handler处理 - MessageQueue 就是一个消息队列,负责存储消息

  • Android Handle原理(Looper,Handler和Message)三者关系案例详解

    介绍 前面的内容对Handler做了介绍,也讲解了如何使用handler,但是我们并不知道他的实现原理.本文从源码的角度来分析如何实现的. 首先我们得知道Handler,Looper,Message Queue三者之间的关系 - Handler封装了消息的发送,也负责接收消.内部会跟Looper关联. - Looper 消息封装的载,内部包含了MessageQueue,负责从MessageQueue取出消息,然后交给Handler处理 - MessageQueue 就是一个消息队列,负责存储消息

随机推荐