Android开发——实现子线程更新UI
Android中线程按功能分的话,可以分为两个,一个是主线程(UI线程),其他的都是子线程
主线程不能执行那些耗时过长的代码或任务(执行耗时过长的代码会出现应用未响应的提示),所以都是使用子线程来执行耗时过长的代码,比如说下载文件等任务
一般情况,子线程中执行过长的代码,都是需要进行更新UI操作。
但是Android中,为了防止安全,是不允许在子线程更新UI的,但是我们可以使用到Android官方给予的API来实现子线程更新UI的操作(本质上,这些API也是切换回了主线程来进行更新UI)
例子:点击一个按钮,过了1s后完成了下载任务,返回了数据,此数据会显示在界面上
具体解释:
点击按钮,之后开启一个子线程来模拟下载过程(线程休眠1s),之后任务执行完毕会返回数据(一个String),使用返回的数据更新UI
新建一个方法,用来模拟下载任务
/**
* 模拟下载
*/
fun download(): String {
Thread.sleep(1000)
return "this is data"
}
下面的使用6种方式和上面的模拟下载任务的方法,来实现上面例子的效果
1.Activity.runOnUiThread()
runOnUiThread
是Activity中的方法,只有当前对象是Activity,就可以直接使用,如果当前的对象不是Activity,需要找到Activity对象,才能执行此方法
runOnUiThread
方法的参数为一个Runnable接口,我使用的kotlin,所以有很多东西都是省略了
设置按钮的点击事件,点击按钮开启一个线程
btn_start.setOnClickListener {
thread {
val data = download()
runOnUiThread({
//这里进行更新UI操作
tv_show.text = data
})
}
}
Java版
btn_start.setOnClickListener(new OnClickListener(){
new Thread(new Runnable(){
String data = download();
runOnUiThread(new Runnable(){
@Override
public void run() {
tv_show.setText(data);
}
})
}).start();
});
2.View.post()
post方法是View对象的方法,参数也是接收一个runnable接口
这里我选用的view对象是需要进行更新textview的本身,当然也可以选用其他的View对象,只要是在当前Activity的对象都可以
btn_start.setOnClickListener {
thread {
val data = download()
//选择当前Activity的View对象都可以
tv_show.post {
tv_show.text = data
}
}
}
3.View.PostDelayed()
此方法和上面的post方法类似,只是多一个参数,用来实现延迟更新UI的效果
btn_start.setOnClickListener {
thread {
val data = download()
tv_show.postDelayed({
tv_show.text = data
},2000)
}
}
上面的代码实现的效果是点击按钮之后,过了3s后才会看到界面发生改变
4.Handler.post()
new一个Handler对象(全局变量)
private val handler = Handler()
使用post方法更新UI,此post方法和之前的post方法一样,参数都是为Runnable接口
btn_start.setOnClickListener {
thread {
val data = download()
handler.post {
tv_show.text = data
}
}
}
5.AsyncTask(推荐)
说明
AsyncTask是一个抽象类,必须创建一个子类类继承它
这里介绍一下关于AsyncTask的三个泛型参数和几个方法
泛型参数可以为任意类型,为空的话使用Void
参数 | 说明 |
---|---|
params | 参数泛型,doInBackground方法的参数 |
progress | 进度泛型,onProgressUpdate方法的参数 |
result | 结果泛型,onPostExecute方法的参数 |
抽象方法说明:
方法名 | 说明 |
---|---|
onPreExectute() | 此方法中,常常进行初始化操作,如进度条显示 |
doInBackground(Params...) | 此方法必须实现, |
onProgressUpdate(Progress...) | 进行更新UI的操作 |
publishProgress(Progress...) | 在doInBackground方法中调用,调用此方法后会回调执行onProgressUpdate方法进行更新UI |
onPostExcute(Result) | 任务结束之后进行更新UI |
简单来说,如果子类继承了AsyncTask,它的抽象方法的参数都会变成泛型对应的类型
例子
下面的代码是取自我的APP,简单地说明一下AsyncTask<String, DownloadingItem, DownloadedItem>
我传入的是3个泛型参数分别为String
,DownloadingItem
,DownloadedItem
,分别对应的params
,progress
和result
泛型
这里我是根据自己的需要而两个类DownloadingItem
和DownloadedItem
,从下面的代码可以看到,抽象方法的参数变为了我们的泛型的类型
internal inner class DownloadingTask : AsyncTask<String, DownloadingItem, DownloadedItem>() {
override fun onPreExecute() {
//一些初始化操作
}
override fun doInBackground(vararg params: String?): DownloadedItem {
//params是一个参数数组,如果创建DownloadingTask对象只传入了一个参数,直接取下标为0的那个即可(需要转型)
//耗时操作(如下载操作),获得进度数据
//将新的进度数据传递到onProgressUpdate方法,更新UI
publishProgress(messageItem)
//任务执行完毕,返回结果(回调onPostExecute方法)
}
override fun onProgressUpdate(vararg values: DownloadingItem?) {
//这里使用最新的进度来进行相关UI的更新
//values是一个DownloadingItem数组,取末尾那个即为最新的进度数据
}
override fun onPostExecute(result: DownloadedItem?) {
//下载成功提示或者是其他更新UI的操作
}
}
执行:
执行Task的时候需要在主线程(UI线程调用)
DownloadingTask().execute("参数")
批量下载:
//允许在同一时刻有5个任务正在执行,并且最多能够存储50个任务
private val exec = ThreadPoolExecutor(5, 50, 10, TimeUnit.SECONDS, LinkedBlockingQueue<Runnable>())
DownloadingTask().executeOnExecutor(exec, url)
6.Handler机制实现(核心)
其实,Handler机制是子进程更新UI的核心
我们上面的五种实现子进程更新UI的方式,都是基于Handler机制实现的
具体机制本文就不多说了,网上有许多的机制说明,这里就只讲一下实现的步骤
Message中有几个属性,what
,arg1
,arg2
,这三个都是接收一个Int,所以,传递数据不是很友好,这里就不准备实现之前的例子效果了
what表示来源,arg1和arg2用来传递Int数据
1.重写Handler类中的handleMessage方法
一般都是规定好一个Int的常量,来表示what
private val handler =object : Handler(){
override fun handleMessage(msg: Message?) {
if (msg.what == 1) {
//来源为1,则
}
}
}
2.发送Message
val msg = handler.obtainMessage()
//一般都是规定好一个Int的常量,来表示what
msg.what = 1
//传递Int数据
msg.arg1 = 20
handler.sendMessage(msg)
Android开发——实现子线程更新UI的更多相关文章
- [Android学习笔记]子线程更新UI线程方法之Handler
关于此笔记 不讨论: 1.不讨论Handler实现细节 2.不讨论android线程派发细节 讨论: 子线程如何简单的使用Handler更新UI 问题: android开发时,如何在子线程更新UI? ...
- Android子线程更新UI的方法总结
版权声明:本文为博主原创文章,转载请注明出处:https://i.cnblogs.com/EditPosts.aspx?postid=6121280 消息机制,对于Android开发者来说,应该是非常 ...
- Android可以子线程更新UI?
初了解Android的时候,就知道Android是不能在子线程更新UI的,不然程序会直接抛出异常,告诉你,别给我在自线程搞事情! 但是,这个是针对普通的view做的限制,而TextureView,Su ...
- android子线程更新UI
参考:https://www.cnblogs.com/joy99/p/6121280.html 子线程是不能直接更新UI的.Android实现View更新有两组方法,分别是invalidate和pos ...
- Android子线程更新UI成功
android子线程更新UI成功 今天在写demo的时候,在子线程中更新UI,发现更新成功,记录一下. protected void onCreate(Bundle savedInstanceStat ...
- Android通过子线程更新UI的几种方式
一般情况下,UI的更新都少不了Handler,首先我们先了解一下Handler机制: Handler消息机制 定义 Message 线程间通信的数据单元,可通过message携带需要的数据创建对象:M ...
- OkHttp3几个简单的例子和在子线程更新UI线程的方法
okHttp用于android的http请求.据说很厉害,我们来一起尝尝鲜.但是使用okHttp也会有一些小坑,后面会讲到如何掉进坑里并爬出来. 首先需要了解一点,这里说的UI线程和主线程是一回事儿. ...
- 子线程更新UI界面的2种方法
一.一般我们都会在子线程完成一些耗时的操作. 1.Android中消息机制: 2.知识点: Message:消息,其中包含了消息ID,消息处理对象以及处理的数据等,由MessageQueue统一列队, ...
- Python+PyQT5的子线程更新UI界面的实例《新手必学》
今天小编就为大家分享一篇Python+PyQT5的子线程更新UI界面的实例,具有很好的参考价值,希望对大家有所帮助.一起跟随小编过来看看吧子线程里是不能更新UI界面的,在移动端方面.Android的U ...
随机推荐
- 【笔记 Jvm-并发】
概述 并发处理 是使得Amadahl定律代替摩尔定律成为计算机性能发展源动力的根本原因: Amdahl定律 通过系统中串行化与并行化的比重来描述多处理器系统所能获得到的运算加速能力: 摩尔定律 描述处 ...
- C#开发BIMFACE系列25 服务端API之获取模型数据10:获取楼层对应面积分区列表
系列目录 [已更新最新开发文章,点击查看详细] 在<C#开发BIMFACE系列22 服务端API之获取模型数据7:获取多个模型的楼层信息>中,返回的楼层信息结果中包含了楼层的具体信 ...
- [DP]最长公共子串
题目 给定两个字符串str1和str2, 长度分别稳M和N,返回两个字符串的最长公共子串 解法一 这是一道经典的动态规划题,可以用M*N的二维dp数组求解.dp[i][j]代表以str1[i]和str ...
- 【Spring】编程式事务和声明式事务
一.概述 二.准备工作 1. 创建表 2. 创建项目并引入Maven依赖 3. 编写实体类 4. 编写Dao层 5. 业务层 6. XML中的配置 7. 测试 三.编程式事务 1. 在业务层代码上使用 ...
- Java网络编程 -- Netty入门
Netty简介 Netty是一个高性能,高可扩展性的异步事件驱动的网络应用程序框架,它极大的简化了TCP和UDP客户端和服务器端网络开发.它是一个NIO框架,对Java NIO进行了良好的封装.作为一 ...
- 060 Python必备库-从数据处理到人工智能
目录 一.概述 1.1 从数据处理到人工智能 二.Python库之数据分析 2.1 numpy 2.2 pandas 2.3 scipy 三.Python库之数据可视化 3.1 matplotlib ...
- Spring boot运行原理-自定义自动配置类
在前面SpringBoot的文章中介绍了SpringBoot的基本配置,今天我们将给大家讲一讲SpringBoot的运行原理,然后根据原理我们自定义一个starter pom. 本章对于后续继续学习S ...
- 从零开始入门 K8s| 阿里技术专家详解 K8s 核心概念
作者| 阿里巴巴资深技术专家.CNCF 9个 TCO 之一 李响 一.什么是 Kubernetes Kubernetes,从官方网站上可以看到,它是一个工业级的容器编排平台.Kubernetes 这个 ...
- Spring Boot(一) Hello World
一.Spring Boot之我见 Spring Boot是由Pivotal团队提供的全新框架,其设计目的是用来简化新Spring应用的初始搭建以及开发过程.该框架使用了特定的方式来进行配置,从 ...
- scrapy框架来爬取壁纸网站并将图片下载到本地文件中
首先需要确定要爬取的内容,所以第一步就应该是要确定要爬的字段: 首先去items中确定要爬的内容 class MeizhuoItem(scrapy.Item): # define the fields ...