详解android异步更新UI的几种方法

发布时间 - 2026-01-11 01:55:45    点击率:

前言

我们知道在Android开发中不能在非ui线程中更新ui,但是,有的时候我们需要在代码中执行一些诸如访问网络、查询数据库等耗时操作,为了不阻塞ui线程,我们时常会开启一个新的线程(工作线程)来执行这些耗时操作,然后我们可能需要将查询到的数据渲染到ui组件上,那么这个时候我们就需要考虑异步更新ui的问题了。

android中有下列几种异步更新ui的解决办法:

  1. Activity.runOnUiThread(Runnable)
  2. View.post(Runnable)
  3. long) View.postDelayed(Runnable, long)
  4. 使用handler(线程间通讯)(推荐)
  5. 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,只不过过程不一样,有得直接给我们封装好了,有得需要我们自己控制管理。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。


# android异步更新UI  # android异步UI  # 详解android进行异步更新UI的四种方式  # Android异步更新UI的四种方式  # android开发教程之handler异步更新ui  # 在这个  # 这段  # 加载  # 可以使用  # 解决办法  # 有得  # 的是  # 都是  # 是一个  # 完成后  # 好了  # 就在  # 还可以  # 让我们  # 子类  # 中有  # 给我们  # 能在  # 我们可以  # 这类 


相关栏目: 【 网站优化151355 】 【 网络推广146373 】 【 网络技术251813 】 【 AI营销90571


相关推荐: Android中AutoCompleteTextView自动提示  详解jQuery中的事件  Laravel怎么实现微信登录_Laravel Socialite第三方登录集成  百度输入法ai组件怎么删除 百度输入法ai组件移除工具  HTML5空格和nbsp有啥关系_nbsp的作用及使用场景【说明】  教你用AI将一段旋律扩展成一首完整的曲子  Laravel怎么调用外部API_Laravel Http Client客户端使用  简单实现Android文件上传  Laravel如何使用Collections进行数据处理?(实用方法示例)  html文件怎么打开证书错误_https协议的html打开提示不安全【指南】  如何在万网自助建站中设置域名及备案?  Laravel如何使用Livewire构建动态组件?(入门代码)  ChatGPT常用指令模板大全 新手快速上手的万能Prompt合集  Laravel如何记录日志_Laravel Logging系统配置与自定义日志通道  如何用PHP工具快速搭建高效网站?  Laravel怎么实现搜索高亮功能_Laravel结合Scout与Algolia全文检索【实战】  如何在景安云服务器上绑定域名并配置虚拟主机?  Laravel Pest测试框架怎么用_从PHPUnit转向Pest的Laravel测试教程  Laravel如何实现数据导出到CSV文件_Laravel原生流式输出大数据量CSV【方案】  HTML5建模怎么导出为FBX格式_FBX格式兼容性及导出步骤【指南】  iOS验证手机号的正则表达式  Laravel如何安装Breeze扩展包_Laravel用户注册登录功能快速实现【流程】  使用Dockerfile构建java web环境  INTERNET浏览器怎样恢复关闭标签页_INTERNET浏览器标签恢复快捷键与方法【指南】  LinuxShell函数封装方法_脚本复用设计思路【教程】  青岛网站建设如何选择本地服务器?  在线教育网站制作平台,山西立德教育官网?  laravel怎么为应用开启和关闭维护模式_laravel应用维护模式开启与关闭方法  如何基于PHP生成高效IDC网络公司建站源码?  合肥制作网站的公司有哪些,合肥聚美网络科技有限公司介绍?  英语简历制作免费网站推荐,如何将简历翻译成英文?  Laravel怎么多语言本地化设置_Laravel语言包翻译与Locale动态切换【手册】  Laravel如何使用Telescope进行调试?(安装和使用教程)  微信小程序 scroll-view组件实现列表页实例代码  Python图片处理进阶教程_Pillow滤镜与图像增强  Laravel如何优化应用性能?(缓存和优化命令)  香港服务器网站卡顿?如何解决网络延迟与负载问题?  如何用AI帮你把自己的生活经历写成一个有趣的故事?  什么是JavaScript解构赋值_解构赋值有哪些实用技巧  消息称 OpenAI 正研发的神秘硬件设备或为智能笔,富士康代工  西安市网站制作公司,哪个相亲网站比较好?西安比较好的相亲网站?  重庆市网站制作公司,重庆招聘网站哪个好?  高端云建站费用究竟需要多少预算?  JavaScript如何实现音频处理_Web Audio API如何工作?  Laravel如何实现事件和监听器?(Event & Listener实战)  香港服务器WordPress建站指南:SEO优化与高效部署策略  Laravel如何使用Socialite实现第三方登录?(微信/GitHub示例)  C++用Dijkstra(迪杰斯特拉)算法求最短路径  简历在线制作网站免费版,如何创建个人简历?  宙斯浏览器文件分类查看教程 快速筛选视频文档与图片方法