在我们开发当中很多时候都会遇到:从网络上获取数据的操作或大量的IO数据操作时,会耗费很长时间,为了使用户的体验效果更好,现在大多数开发者都会使用异步的方式去处理这些的操作,异步的方式有好多种,在此我汇总了以下两种:

       1.Handler + Thread的方式

       2.AsyncTask异步更新UI界面

   这两种方式各自有各自的优缺点,这里先介绍一下第一种方式


1.Hanlder介绍:

   官方文档:

 A Handler allows you to send and process Message and Runnable objects associated with a thread's MessageQueue. Each Handler instance is associated with a single thread and that thread's message queue. When you create a new Handler, it is bound to the thread / message queue of the thread that is creating it -- from that point on, it will deliver messages and runnables to that message queue and execute them as they come out of the message queue.

    一个处理程序允许你发送和处理消息或者Runnable对象关联到的一个线程的MessageQueue。每个处理程序的实例相关联着一个单个线程和一个线程的消息队列。当你创建一个新的处理程序,它被绑定到线程/消息队列的线程时创建它——从那时起,它将提供消息和runnables给消息队列和执行他们出来的消息队列。

   Handler主要方法:

               常用方法                 解释
Message obtainMessage(int what, Object obj) 获取一个Message对象,包含了一个标识和value
boolean post(Runnable r) 将Runnable r添加到消息队列,之后会被UI线程执行
boolean postDelayed(Runnable r, long delayMillis) 延迟多少毫秒之后,再将该线程加入到消息队列中
boolean sendEmptyMessage(int what) 发送一个只有标识的消息
boolean sendMessage(Message msg) 添加一条消息到消息队列的末尾
void handleMessage(Message msg) 用于处理接收到的消息


   简单的说Android采用UI单线程模型,所以只能在主线程中对UI元素进行操作。如果在非UI线程直接对UI进行了操作,就会报错,当然为了提高效率,Android为我们提供了消息循环的机制,我们可以利用这个机制来实现线程间的通信,在非UI线程发送消息到UI线程,最终让Ui线程来进行ui的操作


2.在非UI线程中发送消息通知UI线程更新界面:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
import  java.io.InputStream;
import  java.net.HttpURLConnection;
import  java.net.URL;
import  android.os.Bundle;
import  android.os.Handler;
import  android.os.Message;
import  android.view.View;
import  android.view.View.OnClickListener;
import  android.widget.Button;
import  android.widget.ImageView;
import  android.widget.Toast;
import  android.app.Activity;
import  android.graphics.Bitmap;
import  android.graphics.BitmapFactory;
/**
  * Handler + Thread 实现异步加载图片
  * @author ZHF
  *
  */
public  class  MainActivity  extends  Activity {
     private  static  final  int  MSG_SUCCESS =  0 ; //成功获取图片
     private  static  final  int  MSG_FAILURE =  1 ; //获取图片失败
     public  static  final  String IMG_URL =  "http://images.51cto.com/images/index/Images/Logo.gi" ;
                                                                                                                                                                                                                                                                                                                                                                                                                                               
     Button btn_handler;
     ImageView imageView;
                                                                                                                                                                                                                                                                                                                                                                                                                                               
     private  DownloadImgThread downloadImgThread;
                                                                                                                                                                                                                                                                                                                                                                                                                                               
     private  Handler mHandler =  new  Handler(){
         public  void  handleMessage(Message msg) {  //该方法是在UI主线程中执行
             switch (msg.what) {
             case  MSG_SUCCESS:
                 imageView.setImageBitmap((Bitmap)msg.obj);   //显示图片
                 break ;
             case  MSG_FAILURE:
                 Toast.makeText(MainActivity. this "获取图片失败" , Toast.LENGTH_LONG);
                 break ;
             }
         };
     };
     @Override
     protected  void  onCreate(Bundle savedInstanceState) {
         super .onCreate(savedInstanceState);
         setContentView(R.layout.activity_main);
                                                                                                                                                                                                                                                                                                                                                                                                                                                   
         imageView = (ImageView)  this .findViewById(R.id.imageView);
                                                                                                                                                                                                                                                                                                                                                                                                                                                   
         btn_handler = (Button)  this .findViewById(R.id.btn_handler);
         btn_handler.setOnClickListener( new  OnClickListener() {
             @Override
             public  void  onClick(View v) {
                 //开启一个非UI线程,用于下载图片
                 downloadImgThread =  new  DownloadImgThread();
                 downloadImgThread.start();
             }
         });
     }
                                                                                                                                                                                                                                                                                                                                                                                                                                               
     /**图片下载线程**/
     private  class  DownloadImgThread  extends  Thread{
         HttpURLConnection conn;
         InputStream inputStream;
         Bitmap imgBitmap;
                                                                                                                                                                                                                                                                                                                                                                                                                                                   
         @Override
         public  void  run() {
             try  {
                 URL url =  new  URL(IMG_URL);
                 if (url !=  null ) {
                     HttpURLConnection connection = (HttpURLConnection) url.openConnection();
                     connection.setConnectTimeout( 2000 );
                     connection.setDoInput( true );
                     connection.setRequestMethod( "GET" );
                     int  code = connection.getResponseCode();
                     if ( 200  == code) {
                         inputStream = connection.getInputStream();
                         imgBitmap = BitmapFactory.decodeStream(inputStream);
                         //获取图片成功,向ui线程发送MSG_SUCCESS标识和bitmap对象
                         mHandler.obtainMessage(MSG_SUCCESS,imgBitmap).sendToTarget();
                     } else  {
                         //获取图片失败,向ui线程发送MSG_FAILURE
                         mHandler.obtainMessage(MSG_FAILURE).sendToTarget();
                     }
                 }
             catch  (Exception e) {
                 e.printStackTrace();
             }
         }
     }
                                                                                                                                                                                                                                                                                                                                                                                                                                               
}

在自己的线程中获取到imgBitmap,不能直接imageView.setImageBitmap(imgBitmap),会报错的哦! 通过Message中obj将其存储起来,传递到UI线程中再对其操作。

权限:

1
< uses-permission  android:name = "android.permission.INTERNET" />



2.View的post(Runnable r)方法

   在获取到imgBitmap之后,可以通过下面代码实现UI界面的更新哦:

1
2
3
4
5
6
7
//另外一种更简洁的发送消息给ui线程的方法。 
mImageView.post( new  Runnable() {
          @Override 
         public  void  run() { //run()方法会在ui线程执行 
             mImageView.setImageBitmap(bm); 
         
      });

这是为什么那?

   因为Android框架为每个应用的主线程创建了一个隐式的handler,使用post方法的原理就是给这个隐式的handler发送一个Runnable对象,然后隐式的handler会在ui线程执行Runnable对象的run()方法。


下一篇(AsyncTask):http://smallwoniu.blog.51cto.com/3911954/1252156