更新UI的四种方式分析

wpf线程中更新UI的4种方式 总结:通过案例,可以了解到,上面4种方式,对于此案例来说都可以达到最终的效果,但是那一种效果最好,并没有体现出来。博主认为:第三种最好,原因是从这个需求上考虑的,因为需求需要更新的就是txtUsername上面的数据,那么直接作用于它,对于资源的耗损,将是最少得。在wpf中,更新UI上面的数据,那是必经之路,搞不好,就是死锁,或者没反应,很多时候,都是嵌套的非常深导致的。但是更新UI的方式,有很多的种,不同的方式,表示的意思不一样,但是眼睛看到的,似乎是一回事。点击确定后,和前面的效果是一样的。 阅读详情
在Android开发中,更新UI有以下四种常用方式。

方式一:

Handler类的sendEmptyMessage()或sendMessage()方法。

private Handler mHandler = new Handler() {
    @Override
    public void handleMessage(Message msg) {
	if (msg.what == MSG_REFRESH) {
	    mTextView.setText("blog.youkuaiyun.com/ruancoder");
	}
    }
};

private void refresh1() {
    mHandler.sendEmptyMessage(MSG_REFRESH);
}

方式二:
Handler类的post()方法。

private void refresh2() {
    mHandler.post(new Runnable() {
        @Override
        public void run() {
            mTextView.setText("blog.youkuaiyun.com/ruancoder");
        }
    });
}

方式三:
View类的post()方法。

private void refresh3() {
    mTextView.post(new Runnable() {
        @Override
        public void run() {
            mTextView.setText("blog.youkuaiyun.com/ruancoder");
        }
    });
}

方式四:
Activity类的runOnUiThread()方法。

private void refresh4() {
    runOnUiThread(new Runnable() {
        @Override
        public void run() {
            mTextView.setText("blog.youkuaiyun.com/ruancoder");
        }
    });
}

先来看一下方式一sendEmptyMessage()的实现。

public final boolean sendEmptyMessage(int what)
{
    return sendEmptyMessageDelayed(what, 0);
}


再来看一下方式二Handler类的post()方法。

public final boolean post(Runnable r)
{
    return  sendMessageDelayed(getPostMessage(r), 0);
}

我们会发现,这两种方式内部都是调用了sendEmptyMessageDelayed()方法,即都是采用Handler类发送消息的方式。

接着看方式三View类的post()方法。
public boolean post(Runnable action) {
    final AttachInfo attachInfo = mAttachInfo;
    if (attachInfo != null) {
        return attachInfo.mHandler.post(action);
    }
    // Assume that post will succeed later
    ViewRootImpl.getRunQueue().post(action);
    return true;
}
其内部调用的是Handler类的post()方法,即上述方式二。


再看Activity类的runOnUiThread()方法。

public final void runOnUiThread(Runnable action) {
    if (Thread.currentThread() != mUiThread) {
        mHandler.post(action);
    } else {
        action.run();
    }
}
其内部调用的是也是Handler类的post()方法,即上述方式二。

可以看到,上述四种方式都会执行到sendEmptyMessageDelayed()方法。

也就是说,即使采用后三种方式,最终都会执行第一种方式的实现。即Handler发送消息,然后在Handler类的handlerMessage()中接收消息。


我们接着sendEmptyMessageDelayed()方法继续往下走。

public final boolean sendMessageDelayed(Message msg, long delayMillis)
{
    if (delayMillis < 0) {
        delayMillis = 0;
    }
    return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}

public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
    MessageQueue queue = mQueue;
    if (queue == null) {
        RuntimeException e = new RuntimeException(
                this + " sendMessageAtTime() called with no mQueue");
        Log.w("Looper", e.getMessage(), e);
        return false;
    }
    return enqueueMessage(queue, msg, uptimeMillis);
}

private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
    msg.target = this;
    if (mAsynchronous) {
        msg.setAsynchronous(true);
    }
    return queue.enqueueMessage(msg, uptimeMillis);
}

可以看到,最终会执行到下面两行代码。
msg.target = this;

mQueue.enqueueMessage(msg, uptimeMillis);
(1).将当前发送msg的Handler对象,赋值给msg的target属性。
(2).将msg添加到消息队列mQueue。


此时,在Handler类中,我们已经无法进行接下来的执行流程了。那么最终消息是如何到达Handler类的handleMessage(Message msg)方法的呢?
下面我们来进行分析。

在Handler机制中涉及到四个重要的类,Handler、Looper、MessageQueue、Message。

Handler类中定义了成员变量mQueue和mLooper,分别是MessageQueue和Looper类型对象。

Handler类的成员变量:

public class Handler {

    // other code

    final MessageQueue mQueue;
    final Looper mLooper;

    // other code
}

Handler类的构造方法:

public Handler(Callback callback, boolean async) {

    // other code

    mLooper = Looper.myLooper();
    if (mLooper == null) {
        throw new RuntimeException(
            "Can't create handler inside thread that has not called Looper.prepare()");
    }
    mQueue = mLooper.mQueue;

    // other code

}

在构造方法中,Looper.myLooper()从当前线程中获取绑定的Looper对象,赋值给成员变量mLooper,再从mLooper对象中获取到mQueue对象。

Looper类的mQueue对象是何时创建的呢?
看一下Looper类的构造方法。

private Looper(boolean quitAllowed) {
    mQueue = new MessageQueue(quitAllowed);
    mThread = Thread.currentThread();
}
当Looper对象创建时,就会创建一个MessageQueue类型对象mQueue。

接下来,我们将要关心的就是,Looper对象是在哪里创建的。

这时需要进入到ActivityThread类。
(注:ActivityThread.java文件的路径:\platform_frameworks_base\core\java\android\app\ActivityThread.java)

ActivityThread管理应用程序的主线程的执行。主线程之所以可以使用Handler进行通信,是因为主线程中已经创建了Looper。如果子线程需要使用Handler通信,需要自己去创建Looper。

来看一下ActivityThread类的main()方法。
public static void main(String[] args) {

    // other code

    Looper.prepareMainLooper();

    Looper.loop();

    // other code
}

在main()方法中,调用了Looper.prepareMainLooper()和Looper.loop()两个方法。


(1).Looper.prepareMainLooper()方法

public static void prepareMainLooper() {
    prepare(false);
    synchronized (Looper.class) {
        if (sMainLooper != null) {
            throw new IllegalStateException("The main Looper has already been prepared.");
        }
        sMainLooper = myLooper();
    }
}

private static void prepare(boolean quitAllowed) {
   if (sThreadLocal.get() != null) {
        throw new RuntimeException("Only one Looper may be created per thread");
   }
   sThreadLocal.set(new Looper(quitAllowed));
}

在prepareMainLooper()方法中调用prepare()新建了一个looper对象,并通过threadLocal.set()方法与当前线程进行了绑定。

这里再回到Handler类的构造方法,在构造方法中是通过mLooper = Looper.myLooper()获取Looper对象。
进入Looper.myLooper()方法:
public static @Nullable Looper myLooper() {
    return sThreadLocal.get();
}
该方法返回的就是上面sThreadLocal通过set()添加的Looper对象。


(2).Looper.loop()方法

public static void loop() {
    final Looper me = myLooper();
    final MessageQueue queue = me.mQueue;

    // other code

    for (;;) {
        Message msg = queue.next();

        msg.target.dispatchMessage(msg);

	// other code
    }

    // other code
}

在Looper.loop()方法中,循环从MessageQueue中获取Message对象,调用msg.target.dispatchMessage(msg)进行处理,即将msg交给发送它的Handler对象的dispatchMessage()方法。

兜了一大圈,我们又再次回到Handler类。

在Handler类的dispatchMessage()方法中,我们终于看到了熟悉的handleMessage(Message msg)方法。

/**
 * Handle system messages here.
 */
public void dispatchMessage(Message msg) {
    if (msg.callback != null) {
        handleCallback(msg);
    } else {
        if (mCallback != null) {
            if (mCallback.handleMessage(msg)) {
                return;
            }
        }
        handleMessage(msg);
    }
}

/**
 * Subclasses must implement this to receive messages.
 */
public void handleMessage(Message msg) {
}

到这里,我们已经明白了,通过Handler类的的sendMessage(msg)发送的消息,最终是如何执行到handleMessage(Message msg)方法中。

Android的更新ui大合集,统共4种方法 android更新ui方法大合集,整合了4种方法,做成了一个小demo 立即下载

相关推荐

告别交越失真:手把手教你设计高性能互补输出级电路(LTspice实测)

本文深入剖析音频放大器中常见的交越失真问题,并提供基于LTspice仿真的实战解决方案。通过对比二极管偏置、Vbe倍增器和集成运放驱动三种经典方案,手把手指导设计高性能互补输出级电路,涵盖原理分析、仿真验证及实物调试要点,助力消除音频失真,提升音质。

weixin_29190573的博客 551

java 多线程更新ui_多线程 – Javafx从线程更新UI而无需直接调用Platform.runLater

我认为使用Platform.runLater(…)从后台线程更新UI并不“合适”.有些情况下,这是正确的做法,如Task Javadocs所示.javafx.concurrent API提供的是一个“更高级”的接口,用于编写多线程JavaFX应用程序时通常需要的功能.这个包中的类是由具有多线程编程专业知识的人编写的,因此它们很可能已经解释了普通程序员可能不知道的微妙之处.作为一个例子,虽然upda...

weixin_42515014的博客 1093

MySQL8.2.0下载安装

4、点击No thanks,just start my download,就是只是开始下载的意思,点击下载,等待下载完成。5、新建空白行,或直接双击紧挨的空白行,把复制的mysql的安装路径bin路径复制粘贴过来,确定,确定,确定。1、上面点击finish后,自动勾选了run mysql配置,自动会打开配置页面,点击Next。1、双击安装包,进入安装流程,勾选我同意 I accept,next。2、根据自己需要选择,我选的第二个,可以自己改安装路径。2、默认,点击Next,记住默认端口3306。

m0_59681797的博客 1万+

java 更新ui,java thread立即更新UI

I have a javaFX application which visualizes compuational geometry algorithms. The execution of an algorithm happens in another thread, lets call it mainComputingThread.An algorithm can update the UI ...

weixin_35748716的博客 195

西门子200SMART PID温控实战:从配置到避坑(附加热棒控制案例)

本文详细介绍了西门子200SMART PLC在PID温控系统中的实战应用,涵盖硬件配置、PID参数整定及工程避坑技巧。通过加热棒控制案例,重点解析了信号处理、固态继电器选型、断电保持和无扰切换等关键问题,为工业自动化领域的温度控制提供可靠解决方案。

weixin_28727975的博客 356

论文理解【LLM-Agent】——【SkillOpt】Executive Strategy for Self-Evolving Agent Skills

SkillOpt 将 agent skill 从人工或一次性 prompt artifact 转化为可验证、可控、可迁移的文本空间“可训练状态”,通过有界编辑、验证门控、拒绝编辑反馈和 slow/meta update,在不更新模型权重的情况下显著提升多类 agent 任务表现

佚失的诗篇 578

Android开发中更新UI的几种常用方式

Android开发中,我们经常会头疼UI更新的问题,尤其是跨线程更新UI。今天我们就来聊一聊具体有哪些能够可靠更新UI的的方式: 1、EventBus更新UI; 2、RunOnUiThread更新UI; 3、Handller; 4、runOnUiThread + EventBus更新UI; 5、runOnUiThread + Interface接口; 6、子线程 + runOnUiThr

haoyuegongzi的博客 2226

SD-WAN组网案例——数据中心

SD-WAN组网案例——数据中心

2301_78457663的博客 705

知识梳理:Android子线程中更新UI的3种方法

在Android项目中经常有碰到这样的问题,在子线程中完成耗时操作之后要更新UI,下面就自己经历的一些项目总结一下更新的方法: 在看方法之前看一下Android中消息机制: [img]http://dl2.iteye.com/upload/attachment/0101/9078/241481c3-2d08-3468-bb21-a6f989e77e6a.jpg[/img] [quot...

沉淀之路—Android 848

YOLOv8 改进有效涨点专栏目录 | 含卷积、主干、注意力机制、Neck、检测头、损失函数、二次创新C2PSA/C3k2等各种网络结构改进

YOLOv8在目标检测领域的地位与优势模型改进的意义与价值本专栏的特色与创新点读者学习路径建议关键改进点回顾不同场景的模型选型建议开源社区资源汇总持续学习路径指南YOLOv8在目标检测领域的地位与优势模型改进的意义与价值本专栏的特色与创新点读者学习路径建议关键改进点回顾不同场景的模型选型建议开源社区资源汇总持续学习路径指南。

weixin_39818775的博客 1072

【DRAM存储器六十五】DDR5介绍--训练相关之MPC、Read Training Pattern、Read Preamble Training Mode

简述DDR5 MPC操作和读训练时颗粒输出pattern的配置

highman110的博客 359

Android子线程可以更新UI

Android子线程可以更新UI

kayyoo的博客 1815

uniapp - 详细手机端h5网页调用手机摄像头进行二维码识别扫描,在uniapp的H5移动端微信网页平台中,在浏览器中调用手机扫码功能详细教程,识别二维码并获取扫描结果(完整示例源码,一键复制即用

uniapp,h5,手机端网页,H5手机网页,uniapp开发h5实现扫码功能,uniapp微信h5网页扫码sdk使用教程,uniapp h5网页如何实现浏览器扫码,uniapp扫码功能怎么兼容h5_uniapph5怎么做扫码功能,uniapp的手机网页如何实现扫二维码一维码,浏览器H5实现js扫码,H5调用摄像头和扫一扫功能,亲测可用,H5调用本地摄像头实现扫一扫,uni-h5项目解决扫码功能,uniapp实现微信H5扫码,解决uniapp在H5端使用不能扫码问题,uni-app的h5扫码(二维码、条形码

✅ 精选推荐文章 1万+

你真正了解UI线程更新的几种方式吗—面试必备之深度揭秘

你真正了解UI线程更新的几种方式吗——面试必备之UI刷新大解密 我们都知道一般面试的时候都会问道Handler的运行机制。有些时候面试官不会直接问道。但是如果问道UI线程更新的方式有哪几种,你知道多少? 今天我们用demo来探讨一下主线程中更新的几种方式 通过简单的点击按钮来实现更新一张我女神的图片 测试效果: 效果图.gif 首先我们要知道Handler的运行机制: Handler运行机制之流程...

weixin_34259232的博客 110

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

Handler详解

Handler剖析1.概念:1.当运行项目时,会首先创建MainActivity,当用户进行一些处理例如,点击事件时,Ui会响应用户的操作,直接进行更新UI操作,但是当执行一些耗时操作时,必须在子线程中进行,子线程中无法更新UI,这就需要用到Handler的消息队列,发送Message消息队列,通过Handler进行Ui的更新Handler是Android提供的更新UI的一套机制,也是一套消息处理机

kafly的博客 701

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

android Handler机制源码详解

1、Handler介绍 Handler机制是android系统提供给我们的一种消息处理机制,最常见的应用就是在子线程更新UI操作。其实查看android源码可以发现,activity中所有的生命周期方法的回调都是应用的Handler机制。 Handler机制主要是为了解决安卓系统中多线程并发的问题,试想如果如果在没有加锁的情况下在多个子线程中更新主线程即UI线程界面,会造成界面错乱,我们也无法

wenqiaoqqq的博客 711

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

Superpowers Codex App 兼容设计解析:只读 Git 探测与沙箱 Worktree 环境下的技能适配

本文以 Superpowers 仓库中的设计文档 [2026-03-23-codex-app-compatibility-design.md](https://link.gitcode.com/i/9656602cf67f042ea0709b6eda39f1dc)(工单 PRI-823)为主体,完整解析“让技能在 Codex App 的受沙箱限制的 worktree 环境中正常工作、且不破坏 Cl

gitblog_01132的博客 298

为什么我们可以在非UI线程中更新UI

看到这样的标题……估计N多人会说我是逗比…………因为很多盆友在学习Android(特别是从4.0之后开始入门的)的时候都会常看见或听到别人说我们更新UI呢要在UI线程(或者说主线程)中去更新UI,不要在子线程中更新UI,而Android官方呢也建议我们不要在非UI线程直接更新UI,为什么呢?借助Android官方的一句话来说就是: “The Android UI toolkit is not thread-safe and the view must always be manipulated on the

AigeStudio 2万+

Android更新UI的方式

目录Activity.runOnUiThread(Runnable)View.post(Runnable) View.postDelay(Runnable,long) Activity.runOnUiThread(Runnable) 流程介绍: 1.首先入口Handler类中runOnUiThread方法,如果当前线程不是UI线程,就调用mHandler.post(action); public final void runOnUiThread(Runnable action) {

上地,我在角落里守望 1359

android-更新UI的几种方式

在android中,为了避免在子线程中更新UI造成多线程安全问题(View中更新UI的方法大多不是同步方法),就将UI的更新切换到主线程更新,使用的就是android的Handler机制。在android中可以直接使用Handler进行更新UI,也可以使用Handler的实现进行更新UI,接下来我们盘点下android中更新UI的几种方法,也算是对Handler学习的使用

oheg2010的博客 1343

Android UI 线程更新UI也会崩溃???

本文已经授权公众号「鸿洋」原创首发。 大家好,我是鸿洋。 上个周末是双休,我决定来颠覆一下大家的认知。 在平时的Android开发中,如果一个新手遇到一个这样的错: android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy ca...

Hongyang 1万+

异步更新UI的四种方法和Handler浅分析

1.Handler消息传递机制 通过结合Handler与Message可简单有效地实现线程之间的通信。 传递消息的步骤主要有4步: 在主线程构造一个Handler对象,并启动分线程 关键代码 Handler handler=new Handler(); { public void handleMessage(android.os.Message msg) { if(msg...

qq_37961962的博客 264

Handler: 更新UI的方法

总是感觉 android 中 UI 更新很让人纠结!自己小结一下,算是抛砖引玉。 读这篇文章之前,假设你已经明白线程、Handler 的使用。 在文章的最后,附录一张草图,主要用于说明 Handler、Message、MessageQueue、Looper 之间的关系。 1. 在 onCreate() 方法中开启线程更新 UI public class MasterActivity ex...

CodingMan 4万+

Android中子线程真的不能更新UI吗?

Android的UI访问是没有加锁的,这样在多个线程访问UI是不安全的。所以Android中规定只能在UI线程中访问UI。但是有没有极端的情况?使得我们在子线程中访问UI也可以使程序跑起来呢?

yinhuanxu 1万+

android在服务中更新ui,Android更新UI的几种方法

第一种场景:在UI线程中更新UI,这种是最简单的,直接更新UI即可。代码如下public class MainActivity extends AppCompatActivity{private Button bt_click_me;private TextView tv_text;@Overrideprotected void onCreate(Bundle savedInstanceState...

weixin_35798118的博客 1535

Recovery UI更新分析

文章目录1.Recovery流程2.Recovery UI初始化流程分析3.字体加载函数`gr_init`4.下面看一下图片加载函数`LoadBitmap`5.Recovery按键事件的监听6.Recovery 中图片的显示7.Recovery UI 更新 1.Recovery流程 2.Recovery UI初始化流程分析 之前讲过Recovery 的流程。那么在定制化的过程当中,可能涉及到Re...

li_liuliu的博客 2111
上一篇: 使用PinnedHeaderListView实现固定头部的列表
下一篇: inflate()方法详解和源码分析
ruancoder
博客等级 码龄10年 42粉丝 66原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值