详解android异步更新UI的几种方法
作者:宿罪 发布时间:2022-03-07 08:27:22
前言
我们知道在Android开发中不能在非ui线程中更新ui,但是,有的时候我们需要在代码中执行一些诸如访问网络、查询数据库等耗时操作,为了不阻塞ui线程,我们时常会开启一个新的线程(工作线程)来执行这些耗时操作,然后我们可能需要将查询到的数据渲染到ui组件上,那么这个时候我们就需要考虑异步更新ui的问题了。
android中有下列几种异步更新ui的解决办法:
Activity.runOnUiThread(Runnable)
View.post(Runnable)
long) View.postDelayed(Runnable, long)
使用handler(线程间通讯)(推荐)
AsyncTask(推荐)
对于下面这段代码:
public void onClick(View v) {
new Thread(new Runnable() {
public void run() {
Bitmap bitmap = loadImageFromNetwork("http://example.com/image.png");
mImageView.setImageBitmap(bitmap);
}
}).start();
}
这段代码是一个按钮点击事件的响应方法,当点击了这个按钮后开启了一个子线程去网络上加载图片,然后在这个线程中给imageView设置了图片(更新了ui),这段代码在非ui线程中更新了ui,运行会引发错误。
1. Activity.runOnUiThread:
通常,在Activity,我们可以使用Activity的runOnUiThread方法来更新ui。
如:
public void onClick(View v) {
new Thread(new Runnable() {
public void run() {
Bitmap bitmap = loadImageFromNetwork("http://example.com/image.png");
runOnUiThread(new Runnable() {
@Override
public void run() {
mImageView.setImageBitmap(bitmap);
}
});
}
}).start();
}
2. View.post(Runable)
View类及其子类提供了一个post(Runable)方法允许我们将我们要做的操作放到这个匿名Runable对象的run方法中,在这个方法里面我们可以直接更新ui。
如:
public void onClick(View v) {
new Thread(new Runnable() {
public void run() {
Bitmap bitmap = loadImageFromNetwork("http://example.com/image.png");
imageView.post(new Runnable() {
@Override
public void run() {
mImageView.setImageBitmap(bitmap);
}
});
}
}).start();
}
3. long) View.postDelayed(Runnable, long)
和View.post(Runable)方法一样,只是延迟第二个参数指定的时间后执行,而View.post(Runable)是立即执行。
public void onClick(View v) {
new Thread(new Runnable() {
public void run() {
Bitmap bitmap = loadImageFromNetwork("http://example.com/image.png");
imageView.postDelayed(new Runnable() {
@Override
public void run() {
mImageView.setImageBitmap(bitmap);
}
},2000);
}
}).start();
}
4. 使用Handler(推荐)
前面说道的几种方法当这种操作过多的时候,我们的代码会显得臃肿,代码及业务都难于管理控制,所以,当这类代码多的时候我们就应该采取Handler的方式了。
如:
new Thread(new Runnable() {
public void run() {
Bitmap bitmap = loadImageFromNetwork("http://example.com/image.png");
Message message = mHandler.obtainMessage();
message.what = 1;
message.obj = bitmap;
mHandler.sendMessage(message);
}
}).start();
Handler mHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
switch (msg.what){
case 1:
Bitmap bitmap = (Bitmap) msg.obj;
imageView.setImageBitmap(bitmap);
break;
case 2:
// ...
break;
default:
break;
}
}
};
5. AsyncTask(推荐)
android为我们提供了异步任务AsyncTask,我们可以使用AsyncTask轻松地实现异步加载数据及更新ui。
如:
AsyncTask<String,Void,Bitmap> asyncTask = new AsyncTask<String, Void, Bitmap>() {
/**
* 即将要执行耗时任务时回调,这里可以做一些初始化操作
*/
@Override
protected void onPreExecute() {
super.onPreExecute();
}
/**
* 在后台执行耗时操作,其返回值将作为onPostExecute方法的参数
* @param params
* @return
*/
@Override
protected Bitmap doInBackground(String... params) {
Bitmap bitmap = loadImageFromNetwork(params[0]);
return bitmap;
}
/**
* 当这个异步任务执行完成后,也就是doInBackground()方法完成后,
* 其方法的返回结果就是这里的参数
* @param bitmap
*/
@Override
protected void onPostExecute(Bitmap bitmap) {
imageView.setImageBitmap(bitmap);
}
};
asyncTask.execute("http://example.com/image.png");
需要知道的是doInBackground方法工作在工作线程中,所以,我们在这个方法里面执行耗时操作。同时,由于其返回结果会传递到onPostExecute方法中,而onPostExecute方法工作在UI线程,这样我们就在这个方法里面更新ui,达到了异步更新ui的目的。
事实上,对于android的异步加载数据及更新ui,我们不仅可以选择AsyncTask异步任务,还可以选择许多开源的网络框架,如xUtils,Volley,Okhttp,…,这些优秀的网络框架让我们异步更新ui变得非常简单,而且,效率和性能也非常高。
总结:
对于上面的许多解决办法,其实它们做的都是同一件事情,即在工作线程中执行耗时任务,然后在ui线程中更新ui,只不过过程不一样,有得直接给我们封装好了,有得需要我们自己控制管理。
来源:http://blog.csdn.net/ydxlt/article/details/51247822


猜你喜欢
- 本文实例讲述了C#判断系统是32位还是64位的方法。分享给大家供大家参考。具体如下:public static int GetOSBit()
- 用一个7 x 7的矩形表示迷宫,0和1分别表示的是通路和障碍。通过设计编写程序找到蓝色小球达到蓝色旗子的路线思路:构建一个迷宫(用二维数组)
- 本文实例讲述了Android游戏开发学习①弹跳小球实现方法。分享给大家供大家参考。具体如下:在学习了一点点Android之后,觉得有必要记录
- 带你手把手,用 java swing实现抖音上的表白程序1.准备工作a.需要下载一个带着swing插件的eclipseb.需要配置好JDKc
- Java解压缩zip - 多个文件(包括文件夹),对多个文件和文件夹进行压缩,对复杂的文件目录进行解压。压缩方法使用的是可变参数,可以压缩1
- 工作中因业务需求,将数据库中的树状结构的数据根据父节点获取所有的子节点实现思路1.获取整个数据的list集合数据2.将数据分组,java8
- 在使用jQuery时候,我们经常会看到或者使用到方法链,例如:$("#p1").css("color"
- gcc 命令使用 gcc 编译 c语言-c 编译、汇编到目标代码,不进行链接,也就是直接生成目标文件-o 将输出的文件以指定文件名来储存,有
- 这篇文章主要介绍了SpringBoot 使用Mybatis分页插件实现详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参
- Spring的注解@Qualifier小结近期在捯饬spring的注解,现将遇到的问题记录下来,以供遇到同样问题的童鞋解决~先说明下场景,代
- 需要用到的知识:注解、AOP、ExpiringMap(带有有效期的映射)我们可以自定义注解,把注解添加到我们的接口上。定义一个切面,执行方法
- 目录通过Resource接口手动加载通过@Value自动转换通过ResourceLoader加载使用ResourceUtils加载资源读取资
- 本文实例讲述了C#实现汉字转拼音或转拼音首字母的方法。分享给大家供大家参考。具体实现方法如下:/// <summary>///
- 返回Json实体类属性大小写问题总归上述问题Rt,其实今天开发刚遇到,当时找了半天为啥前台传参后台却接收不到,原来是返回的时候返回小写,但是
- 本文详细讲述了Android的开机流程。分享给大家供大家参考,具体如下:开机过程中无线模块的初始化过程;如果sim卡锁开启,或者pin被锁住
- 一、Stream流引入Lambda表达式,基于Lambda所带来的函数式编程,又引入了一个全新的Stream概念,用于解决集合类库既有的鼻端
- 一、简介当我们没有在子类构造函数中写上 base(),默认会先调用父类中无参的构造函数,再调用子类。当在有参构造函数后写上base时,只调用
- 本文实例为大家分享了C#字符串倒序写法的实现代码,供大家参考,具体内容如下//string concatenation with for l
- 1. Mybatis的@param注解自定义对象也用@param注解注:使用@param注解,mapper.xml 不加parameterT
- java内存分析类加载的过程类的加载与ClassLoader的理解类的初始化package Collections;public class