Android多线程:Handler runOnUiThread 异步消息处理机制

news2025/2/8 5:30:11

目录

一,Android中的多线程问题

1.模拟耗时工作

2.Android开启子线程 

 二,在子线程中更新UI

1.异步消息处理机制 Handler

2.使用runOnUiThread更新UI


一,Android中的多线程问题

        Android用户界面是与用户交互的接口,对于用户的操作,Android迅速响应用户输入(200ms内)是一个重要目标。因此,一些耗时操作(如:后台下载,异步加载图片等)需要放在子线程中运行,否则会导致主线程阻塞。

1.模拟耗时工作

        例如下面这段访问百度界面的代码,如果在主线程中运行的话就会出现android.os.Network-OnMainThreadException的报错,也就是在主线程中请求了网络操作,这是一种耗时操作。为了解决这个问题,就需要把操作放在子线程中运行。

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

    findViews();

    setListeners();
}
private void setListeners() {
    btn_baidu.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
                try {
                    //获取百度链接
                    URL url = new URL("https://www.baidu.com/");
                    //获取输入流
                    InputStream inputStream = url.openStream();
                    byte[] bytes = new byte[1024];
                    //存储输入的信息
                    StringBuffer buffer = new StringBuffer();
                    while((inputStream.read(bytes)) != -1){
                        String str = new String(bytes, 0, bytes.length);
                        buffer.append(str);
                    }
                    Log.i("baidu", buffer.toString());
                    //关闭流
                    inputStream.close();
                } catch (MalformedURLException e) {
                    throw new RuntimeException(e);
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
        }
    });
}

2.Android开启子线程 

         在Android中开启线程的操作与在Java中一致,继承Thread类或实现Runnable接口,不了解的话可以阅读博客:Java线程基础:Thread Runnable 多线程 Synchronized 死锁...-CSDN博客。

例如下面用实现Runnable接口的方法来开启子线程,访问百度:

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

    findViews();

    setListeners();
}
private void setListeners() {
    btn_baidu.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        //获取百度链接
                        URL url = new URL("https://www.baidu.com/");
                        //获取输入流
                        InputStream inputStream = url.openStream();
                        byte[] bytes = new byte[1024];
                        //存储输入的信息
                        StringBuffer buffer = new StringBuffer();
                        while((inputStream.read(bytes)) != -1){
                            String str = new String(bytes, 0, bytes.length);
                            buffer.append(str);
                        }
                        //在子线程中更改Ui界面,使用runOnUiThread
                        Log.i("baidu", buffer.toString());
                        //关闭流
                        inputStream.close();
                    } catch (MalformedURLException e) {
                        throw new RuntimeException(e);
                    } catch (IOException e) {
                        throw new RuntimeException(e);
                    }
                }
            }).start();
        }
    });
}

运行并查看日志,可以发现成功访问: 

 二,在子线程中更新UI

        使用子线程解决异步执行又会带来新问题,那就是在Android中,只有UI线程(也叫主线程)可以更新UI界面,子线程不能更新。为了在子线程中更新UI,我们需要使用Android异步消息处理机制

1.异步消息处理机制 Handler

        Android中的异步消息处理主要由4个部分组成:Message,Handler,MessageQueue,Looper。

  1. Message:在线程之间传递的消息,Message中可以封装一些数据如:what(int型,表示Message的编号),obj(封装的Object对象),此外还有int型的arg1,arg2等;
  2. Handler:用于在线程间发送和处理消息,发送消息使用sendMessage()方法,处理消息使用handleMessage()方法;
  3. MessageQueue:消息队列,用于存放Handler发送的消息,这些消息直到被处理前,会一直存放在消息队列中。每个线程只会有一个MessageQueue对象;
  4. Looper:Looper是每个线程中MessageQueue的管家,调用Looper的loop方法后,会进入无限循环,每当发现MessageQueue中存在一条消息,就会将其取出,并传递到Handler的handleMessage()方法中,每个线程只会有一个Looper对象; 

 异步消息处理机制的基本流程为:

(1)首先在主线程中创建一个Handler对象,并重写handleMessage方法。

(2)当子线程需要更改UI时,就创建一个Message对象,并通过Handler将Message发送出去,Message消息会被添加到MessageQueue中等待处理,Looper会一直尝试从消息队列中取出消息,并传给Handler的handleMessage方法。

(3)Handler的构造器中我们传入了Looper.getMainLooper,所以handleMessage方法中的代码会在UI线程中运行,我们就可以放心地进行UI操作。

下面是代码实例(获取网络图片):

private void getImg() {
    //1.在主线程中创建一个Handler对象,并重写handleMessage方法。
    Handler handler = new Handler(Looper.getMainLooper()){
        @Override
        public void handleMessage(@NonNull Message msg) {
            switch (msg.what){
                case 114514:
                    Bitmap bitmap = (Bitmap) msg.obj;
                    iv_img.setImageBitmap(bitmap);
                    Log.i("114514", "获取图片成功!");
                    break;
            }
        }
    };
    //设置监听
    btn_getimg.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        //2.当子线程需要更改UI时,就创建一个Message对象
                        URL url = new URL("https://profile-avatar.csdnimg.cn/8e4c56733fdd4dda90854384976d4bb0_ih_lzh.jpg!1");
                        InputStream inputStream = url.openStream();
                        Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
                        Message msg = handler.obtainMessage();
                        //封装bitmap对象和设置对象编号
                        msg.obj = bitmap;
                        msg.what = 114514;
                        //3.通过Handler将Message发送出去
                        handler.sendMessage(msg);
                        inputStream.close();
                    } catch (MalformedURLException e) {
                        throw new RuntimeException(e);
                    } catch (IOException e) {
                        throw new RuntimeException(e);
                    }
                }
            }).start();
        }
    });
}

2.使用runOnUiThread更新UI

        runOnUiThread,在UI线程上运行指定的操作。如果当前线程是UI线程,则执行操作,如果当前线程不是UI线程,操作将被提交到UI线程的消息队列MessageQueue中。runOnUiThread只能在Activity中使用。

public final void runOnUiThread(Runnable action) {
        if (Thread.currentThread() != mUiThread) {
            mHandler.post(action);//提交到消息队列
        } else {
            action.run();//操作执行
        }
    }

还是上面获取图片的例子,将Handler改为使用runOnUiThread更改UI:

private void getImg() {
    //设置监听
    btn_getimg.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        URL url = new URL("https://profile-avatar.csdnimg.cn/8e4c56733fdd4dda90854384976d4bb0_ih_lzh.jpg!1");
                        InputStream inputStream = url.openStream();
                        Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
                        runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                iv_img.setImageBitmap(bitmap);
                            }
                        });
                    } catch (MalformedURLException e) {
                        throw new RuntimeException(e);
                    } catch (IOException e) {
                        throw new RuntimeException(e);
                    }
                }
            }).start();
        }
    });
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1598167.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

偏微分方程算法之混合边界差分

目录 一、研究对象 二、差分格式 2.1 向前欧拉格式 1. 中心差商 1.1.1 理论推导 1.1.2 算例实现 2. x0处向前差商,x1处向后差商 1.2.1 理论推导 1.2.2 算例实现 2.2 Crank-Nicolson格式 2.2.1 理论推导 2.2.2 算例实现 一、研究对象 这里我们以混合边界…

科技云报道:AI大模型疯长,存储扛住了吗?

科技云报道原创。 AI大模型正在倒逼数字基础设施产业加速升级。 过去一年半,AI大模型标志性的应用相继出现,从ChatGPT到Sora一次次刷新人们的认知。震撼的背后,是大模型参数指数级的增长。 这种数据暴涨的压力,快速传导到了大模…

Efficient Multimodal learning from data-centric perspective

[MLLM-小模型推荐-2024.3.18] Bunny 以数据的眼光看问题 - 知乎近期几天会梳理下多模态小模型相关的论文,做个汇总。为了能够每天更新点啥,先穿插一些小模型算法。等到全部算法都梳理完成后,再发布一篇最终汇总版本的。 3.15 号 BAAI 发布了 …

关于机器学习/深度学习的一些事-答知乎问(五)

嵌入学习方法在解决小样本学习问题时面临的挑战是什么? (1)过度依赖于辅助数据,预训练的模式违背了小样本学习的本质定义。几乎所有的嵌入学习方法都需要通过大量辅助样本来预训练特征嵌入函数,但在实际应用场景中&am…

葡萄书--图理论基础

图的定义 G{V,E} 节点和边的信息可以是类别型的,类别型数据的取值只能是哪一类别。一般称类别型的信息为标签。 节点和边的信息可以是数值型的,数值型数据的取值范围为实数。一般称数值型的信息为属性。 在图的计算任务中,我们认为&#x…

不消除存储瓶颈,AIGC就是梦幻泡影

大数据产业创新服务媒体 ——聚焦数据 改变商业 在大模型和AIGC的新纪元,我们正见证一个前所未有的技术革命。从更自然的人机对话,到图片、视频生成,AIGC技术正在彻底改变我们创造、学习和交流的方式。 然而,这一切进步的背后&am…

【数据结构|C语言版】顺序表应用

前言1. 基于动态顺序表实现通讯录1.1 通讯录功能1.2 代码实现1.2.1 SeqList.h1.2.2 SeqList.c1.2.3 Contact.h1.2.4 Contact.c1.2.5 test.c 1.3 控制台测试1.3.1 添加联系人1.3.2 删除联系人1.3.3 修改联系人1.3.4 查找联系人1.3.5 清空通讯录1.3.6 通讯录读档和存档 2. 好题测…

如何打开一个fbx模型

步骤 ① 下载fbx viewer ,以下是管网链接 FBX Review | Cross-platform 3D model viewer | Autodesk ②需要用邮箱进行注册+确认,这一步完成之后 ③下载之后吧fbx文件导入到这个里面就可以了

NL2SQL进阶系列(4):ConvAI、DIN-SQL、C3-浙大、DAIL-SQL-阿里等16个业界开源应用实践详解[Text2SQL]

NL2SQL进阶系列(4):ConvAI、DIN-SQL等16个业界开源应用实践详解[Text2SQL] NL2SQL基础系列(1):业界顶尖排行榜、权威测评数据集及LLM大模型(Spider vs BIRD)全面对比优劣分析[Text2SQL、Text2DSL] NL2SQL基础系列(2)&#xff1a…

前端导出excel 接口处理和导出处理

如果按照一般的请求方式,接口会返回如下乱码 此时,接口其实已经请求成功了,只需要对乱码进行一下处理就行 1.请求方式处理 1.1 如果是直接使用axios进行请求 axios({method: get,url: url,params: params,//需要添加responseType: blob }…

采用分治法求含n个实数序列中的最大元素和次大元素(C语言)

目录 实验内容: 实验过程: 1.算法设计 2.程序清单 3.复杂度分析 4.运行结果 实验内容: 设计一个程序,采用分治法求含n个实数序列中的最大元素和次大元素,并分析算法的时间复杂度。 实验过程: 1.算法…

深度学习之PyTorch实现卷积神经网络(CNN)

在深度学习领域,卷积神经网络(Convolutional Neural Networks,CNN)是一种非常强大的模型,专门用于处理图像数据。CNN通过卷积操作和池化操作来提取图像中的特征,具有较好的特征学习能力,特别适用…

华为OD机试 - 连续天数的最高利润额(Java 2024 C卷 100分)

华为OD机试 2024C卷题库疯狂收录中,刷题点这里 专栏导读 本专栏收录于《华为OD机试(JAVA)真题(A卷B卷C卷)》。 刷的越多,抽中的概率越大,每一题都有详细的答题思路、详细的代码注释、样例测试…

AI音乐,8大变现方式——Suno:音乐版的ChatGPT - 第505篇

悟纤之歌 这是利用AI为自己制作的一首歌,如果你也感兴趣,可以花点时间阅读下本篇文章。 ​ 导读 随着新一代AI音乐创作工具Suno V3、Stable audio2.0、天工SkyMusic的发布,大家玩自创音乐歌曲,玩的不亦乐乎。而有创业头脑的朋友…

一些实用的工具网站

200 css渐变底色 https://webgradients.com/ 200动画效果复制 https://css-loaders.com/classic/ 二次贝塞尔曲线 https://blogs.sitepointstatic.com/examples/tech/canvas-curves/bezier-curve.html 三次贝塞尔曲线 https://blogs.sitepointstatic.com/examples/tech/c…

百货商场用户画像描绘and价值分析(下)

目录 内容概述数据说明技术点主要内容4 会员用户画像和特征字段创造4.1 构建会员用户基本特征标签4.2 会员用户词云分析 5 会员用户细分和营销方案制定5.1 会员用户的聚类分析及可视化5.2 对会员用户进行精细划分并分析不同群体带来的价值差异 内容概述 本项目内容主要是基于P…

环形链表II

给定一个链表的头节点 head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null 如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 …

【数据结构|C语言版】单链表

前言1. 单链表的概念和结构1.1 单链表的概念1.2 单链表的结构 2. 单链表的分类3.单链表的实现3.1 新节点创建3.2 单链表头插3.3 单链表头删3.4 单链表尾插3.5 单链表尾删3.6 链表销毁 4. 代码总结4.1 SLT.h4.2 SLT.c4.3 test.c 后言 前言 各位小伙伴大家好!时隔不久…

mysql 日环比 统计

接到一个任务,要计算日环比的情况。 16、查询销售额日环比情况 日环比: (今日-昨日)/ 昨日 的一个比率情况。 1,建表 DROP TABLE IF EXISTS sale; create table sale(id int not null AUTO_INCREMENT,record_date da…

偏微分方程算法之二维初边值问题(交替方向隐(ADI)格式)

一、研究对象 以二维抛物型方程初边值问题为研究对象: 为了确保连续性,公式(1)中的相关函数满足: 二、理论推导 2.1 向前欧拉格式 首先进行网格剖分。将三维长方体空间(二维位置平面一维时间轴&#xff09…