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

作者:宿罪 时间:2022-03-07 08:27:22 

前言

我们知道在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,只不过过程不一样,有得直接给我们封装好了,有得需要我们自己控制管理。

来源:http://blog.csdn.net/ydxlt/article/details/51247822

标签:android,异步,更新UI
0
投稿

猜你喜欢

  • C语言多种获取字符串长度的方法

    2021-07-01 16:30:29
  • Android 完整购物商城界面的实现案例

    2023-06-14 01:33:06
  • Spring启动过程中实例化部分代码的分析之Bean的推断构造方法

    2022-08-26 02:00:07
  • java自定义注解验证手机格式的实现示例

    2023-06-24 10:42:44
  • 详解Java中final的用法

    2022-09-22 10:20:32
  • C#飞行棋小程序设计代码

    2021-10-06 23:45:25
  • c#栈变化规则图解示例(栈的生长与消亡)

    2021-10-12 05:11:11
  • 基于Mock测试Spring MVC接口过程解析

    2023-11-27 12:04:30
  • jpa多数据源时Hibernate配置自动生成表不生效的解决

    2023-04-24 06:19:55
  • Android App实现监听软键盘按键的三种方式

    2021-09-14 10:39:27
  • Android实现热门标签的流式布局

    2023-01-29 02:32:36
  • C#实现求一组数据众数的方法

    2023-06-07 00:11:53
  • Jetpack Compose图片组件使用实例详细讲解

    2021-06-09 08:15:24
  • Unity3D基于UGUI实现虚拟摇杆

    2023-03-15 15:42:37
  • Java线程状态变换过程代码解析

    2023-08-06 18:05:29
  • WPF+ASP.NET SignalR实现简易在线聊天功能的示例代码

    2023-01-09 09:34:07
  • Android Java调用自己C++类库的实例讲解

    2023-06-16 19:09:17
  • Java多线程的实现方式比较(两种方式比较)

    2023-06-06 13:00:12
  • unity实现摄像头跟随

    2021-07-26 12:50:10
  • Java线程的调度与优先级详解

    2023-04-30 13:48:13
  • asp之家 软件编程 m.aspxhome.com