Android 之异步任务(AsyncTask,Handler,Message,looper)

AsyncTask: 3个类型(Params,Progress和Result),4个步骤(onPreExecute(),doInBackground(Params…),onProgressUpdate(Progress…), onPostExecute(Result) )

Android的AsyncTask比Handler更轻量级一些,适用于简单的异步处理。
首先明确Android之所以有Handler和AsyncTask,都是为了不阻塞主线程(UI线程),且UI的更新只能在主线程中完成,因此异步处理是不可避免的。
 
Android为了降低这个开发难度,提供了AsyncTask。AsyncTask就是一个封装过的后台任务类,顾名思义就是异步任务。

AsyncTask直接继承于Object类,位置为android.os.AsyncTask。要使用AsyncTask工作我们要提供三个泛型参数,并重载几个方法(至少重载一个)。

 AsyncTask定义了三种泛型类型 Params,Progress和Result。可以为Void表示无类型

  • Params 启动任务执行的输入参数,比如HTTP请求的URL。
  • Progress 后台任务执行的百分比。
  • Result 后台执行任务最终返回的结果,比如String。

使用过AsyncTask 的同学都知道一个异步加载数据最少要重写以下这两个方法:

  • doInBackground(Params…) 后台执行,比较耗时的操作都可以放在这里。注意这里不能直接操作UI。此方法在后台线程执行,完成任务的主要工作,通常需要较长的时间。在执行过程中可以调用publicProgress(Progress…)来更新任务的进度。
  • onPostExecute(Result)  相当于Handler 处理UI的方式,在这里面可以使用在doInBackground 得到的结果处理操作UI。 此方法在主线程执行,任务执行的结果作为此方法的参数返回

有必要的话你还得重写以下这三个方法,但不是必须的:

  • onProgressUpdate(Progress…)   可以使用进度条增加用户体验度。 此方法在主线程执行,用于显示任务执行的进度。
  • onPreExecute()        这里是最终用户调用Excute时的接口,当任务执行之前开始调用此方法,可以在这里显示进度对话框。
  • onCancelled()             用户调用取消时,要做的操作

使用AsyncTask类,以下是几条必须遵守的准则:

  • Task的实例必须在UI thread中创建;
  • execute方法必须在UI thread中调用;
  • 不要手动的调用onPreExecute(), onPostExecute(Result),doInBackground(Params...), onProgressUpdate(Progress...)这几个方法;
  • 该task只能被执行一次,否则多次调用时将会出现异常;

一个最简单的异步任务例子:从网上下载一副图片

  1 package com.example.android_03asynctask;
  2 
  3 import org.apache.http.HttpEntity;
  4 import org.apache.http.HttpResponse;
  5 import org.apache.http.client.HttpClient;
  6 import org.apache.http.client.methods.HttpGet;
  7 import org.apache.http.impl.client.DefaultHttpClient;
  8 import org.apache.http.util.EntityUtils;
  9 
 10 import android.app.Activity;
 11 import android.app.ProgressDialog;
 12 import android.graphics.Bitmap;
 13 import android.graphics.BitmapFactory;
 14 import android.os.AsyncTask;
 15 import android.os.Bundle;
 16 import android.view.Menu;
 17 import android.view.MenuItem;
 18 import android.view.View;
 19 import android.widget.Button;
 20 import android.widget.ImageView;
 21 
 22 public class MainActivity extends Activity {
 23 
 24     private Button button;
 25     private ImageView imageView;
 26     private String image_Path="http://pic14.nipic.com/20110522/7411759_164157418126_2.jpg";
 27     private ProgressDialog progressDialog;
 28     @Override
 29     protected void onCreate(Bundle savedInstanceState) {
 30         super.onCreate(savedInstanceState);
 31         setContentView(R.layout.activity_main);
 32         button=(Button)this.findViewById(R.id.button1);
 33         imageView=(ImageView)this.findViewById(R.id.imageView1);
 34         imageView=(ImageView)this.findViewById(R.id.imageView1);
 35         progressDialog=new ProgressDialog(this);
 36         progressDialog.setTitle("提示信息");
 37         progressDialog.setMessage("正在下载....");
 38         button.setOnClickListener(new View.OnClickListener() {
 39             
 40             @Override
 41             public void onClick(View v) {
 42                 // TODO Auto-generated method stub
 43                 //在UI主线程中不能直接访问网络,所以下面的写法是不正确的,必须使用异步任务
 44             /*    HttpClient httpClient=new DefaultHttpClient();
 45                 HttpGet httpGet=new HttpGet(image_Path);
 46                 try {
 47                     httpClient.execute(httpGet);
 48                 } catch (Exception e) {
 49                     // TODO: handle exception
 50                     e.printStackTrace();
 51                 }*/
 52                 
 53                 //执行异步任务操作
 54                 new myTask().execute(image_Path);
 55             }
 56         });
 57     }
 58  
 59     /**
 60      * 1.声明异步类继承AsyncTask,含有三个参数
 61      *     params 要执行的任务,一般为网络路径url
 62      *     progress 进度的刻度 一般为 Void,表示没有类型
 63      *     result任务执行的返回值
 64      * 2.
 65      * @author Administrator
 66      *
 67      */
 68 public class myTask extends AsyncTask<String, Void, Bitmap>{
 69 
 70     //任务执行之前的操作
 71     @Override
 72         protected void onPreExecute() {
 73             // TODO Auto-generated method stub
 74             super.onPreExecute();
 75             progressDialog.show();
 76         }
 77  
 78     //主要完成耗时操作
 79     @Override
 80     protected Bitmap doInBackground(String... params) {
 81         // TODO Auto-generated method stub
 82         //使用网络连接类HttpClient完成对网络数据的提取
 83         HttpClient httpClient=new DefaultHttpClient();
 84         HttpGet httpGet=new HttpGet(params[0]);//从可变参数取得第一个参数
 85         Bitmap bitmap=null;
 86         try {
 87             HttpResponse httpResponse=httpClient.execute(httpGet);
 88             if(httpResponse.getStatusLine().getStatusCode()==200){
 89                 HttpEntity httpEntity=httpResponse.getEntity();//获取结果实体
 90                 byte[] data=EntityUtils.toByteArray(httpEntity);//将结果实体转换成字节数组
 91                 bitmap=BitmapFactory.decodeByteArray(data, 0, data.length);//将数据转换成bitmap对象
 92                 
 93             }
 94             
 95         } catch (Exception e) {
 96             // TODO: handle exception
 97             e.printStackTrace();
 98         }
 99         return bitmap;
100     }
101     
102     //主要是更新UI操作
103     @Override
104     protected void onPostExecute(Bitmap result) {
105         // TODO Auto-generated method stub
106         super.onPostExecute(result);
107         imageView.setImageBitmap(result);
108         progressDialog.dismiss();
109     }
110 }
111     @Override
112     public boolean onCreateOptionsMenu(Menu menu) {
113         // Inflate the menu; this adds items to the action bar if it is present.
114         getMenuInflater().inflate(R.menu.main, menu);
115         return true;
116     }
117 
118     @Override
119     public boolean onOptionsItemSelected(MenuItem item) {
120         // Handle action bar item clicks here. The action bar will
121         // automatically handle clicks on the Home/Up button, so long
122         // as you specify a parent activity in AndroidManifest.xml.
123         int id = item.getItemId();
124         if (id == R.id.action_settings) {
125             return true;
126         }
127         return super.onOptionsItemSelected(item);
128     }
129 }
View Code

上面的实例中并未显示进度条上的刻度,对上个例子完善如下:

  1 package com.example.android_03asynctsk2;
  2 
  3 import java.io.ByteArrayOutputStream;
  4 import java.io.IOException;
  5 import java.io.InputStream;
  6 import java.io.OutputStream;
  7 
  8 import org.apache.http.HttpEntity;
  9 import org.apache.http.HttpResponse;
 10 import org.apache.http.client.HttpClient;
 11 import org.apache.http.client.methods.HttpGet;
 12 import org.apache.http.impl.client.DefaultHttpClient;
 13 import org.apache.http.util.EntityUtils;
 14 
 15 import android.app.Activity;
 16 import android.app.ProgressDialog;
 17 import android.graphics.Bitmap;
 18 import android.graphics.BitmapFactory;
 19 import android.os.AsyncTask;
 20 import android.os.Bundle;
 21 import android.view.Menu;
 22 import android.view.MenuItem;
 23 import android.view.View;
 24 import android.widget.Button;
 25 import android.widget.ImageView;
 26 
 27 public class MainActivity extends Activity {
 28     private Button button;
 29     private ImageView imageView;
 30     private String image_Path = "http://pic14.nipic.com/20110522/7411759_164157418126_2.jpg";
 31     private ProgressDialog progressDialog;
 32 
 33     @Override
 34     protected void onCreate(Bundle savedInstanceState) {
 35         super.onCreate(savedInstanceState);
 36         setContentView(R.layout.activity_main);
 37         button = (Button) this.findViewById(R.id.button1);
 38         imageView = (ImageView) this.findViewById(R.id.imageView1);
 39         progressDialog = new ProgressDialog(this);
 40         progressDialog.setTitle("提示");
 41         progressDialog.setMessage("正在下载....");
 42         progressDialog.setCancelable(false);// 使屏幕失去焦点,直至下载完成才恢复焦点
 43         progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);// 设置进度条为横向的
 44         button.setOnClickListener(new View.OnClickListener() {
 45 
 46             @Override
 47             public void onClick(View v) {
 48                 // TODO Auto-generated method stub
 49                 new myTask().execute(image_Path);
 50 
 51             }
 52         });
 53     }
 54 
 55     public class myTask extends AsyncTask<String, Integer, Bitmap> {
 56 
 57         @Override
 58         protected void onPreExecute() {
 59             // TODO Auto-generated method stub
 60             super.onPreExecute();
 61             progressDialog.show();
 62         }
 63 
 64         @Override
 65         protected Bitmap doInBackground(String... params) {
 66             // TODO Auto-generated method stub
 67             HttpClient httpClient = new DefaultHttpClient();
 68             HttpGet httpGet = new HttpGet(params[0]);// 从可变参数取得第一个参数
 69             Bitmap bitmap = null;
 70             ByteArrayOutputStream byteArrayOutputStream=new ByteArrayOutputStream();
 71             InputStream inputStream=null;
 72             try {
 73                 HttpResponse httpResponse = httpClient.execute(httpGet);
 74                 if (httpResponse.getStatusLine().getStatusCode() == 200) {
 75                     inputStream=httpResponse.getEntity().getContent();//得到输入流
 76                     long file_Length=httpResponse.getEntity().getContentLength();//获得文件总长度
 77                     int len=0,total_length=0;
 78                     byte[] data=new byte[1024];//每次读取的内容
 79                     while((len=inputStream.read(data))!=-1){
 80                         total_length+=len;
 81                         int value=(int)((total_length/(float)file_Length)*100);
 82                         publishProgress(value);//发布刻度到onProgressUpdate
 83                         byteArrayOutputStream.write(data, 0, len);
 84                     }
 85                     byte []result=byteArrayOutputStream.toByteArray();
 86                     bitmap=BitmapFactory.decodeByteArray(result, 0, result.length);//将数据转换成bitmap对象
 87                 }
 88 
 89             } catch (Exception e) {
 90                 // TODO: handle exception
 91                 e.printStackTrace();
 92             }
 93             finally{
 94                 if(inputStream!=null){
 95                     try {
 96                         inputStream.close();
 97                     } catch (IOException e) {
 98                         // TODO Auto-generated catch block
 99                         e.printStackTrace();
100                     }
101                 }
102             }
103             return bitmap;
104         }
105 
106         @Override
107         protected void onProgressUpdate(Integer... values) {
108             // TODO Auto-generated method stub
109             super.onProgressUpdate(values);
110             progressDialog.setProgress(values[0]);
111         }
112 
113         @Override
114         protected void onPostExecute(Bitmap result) {
115             // TODO Auto-generated method stub
116             super.onPostExecute(result);
117             imageView.setImageBitmap(result);
118             progressDialog.dismiss();
119         }
120 
121     }
122 
123     @Override
124     public boolean onCreateOptionsMenu(Menu menu) {
125         // Inflate the menu; this adds items to the action bar if it is present.
126         getMenuInflater().inflate(R.menu.main, menu);
127         return true;
128     }
129 
130     @Override
131     public boolean onOptionsItemSelected(MenuItem item) {
132         // Handle action bar item clicks here. The action bar will
133         // automatically handle clicks on the Home/Up button, so long
134         // as you specify a parent activity in AndroidManifest.xml.
135         int id = item.getItemId();
136         if (id == R.id.action_settings) {
137             return true;
138         }
139         return super.onOptionsItemSelected(item);
140     }
141 }
View Code

Handler:异步处理大师发送、处理消息,

Handler扮演了往MQ上添加消息和处理消息的角色(只处理由自己发出的消息),即:

通知MQ它要执行一个任务(sendMessage),并在loop到自己的时候执行该任务(handleMessage),整个过程是异步的。

handler创建时会关联一个looper,默认的构造方法将关联当前线程的looper,不过这也是可以set的。

andriod提供了Handler 和 Looper 来满足线程间的通信。

Handler先进先出原则。Looper类用来管理特定线程内对象之间的消息交换(MessageExchange)。

1)Looper: 一个线程可以产生一个Looper对象,由它来管理此线程里的MessageQueue(消息队列)。 
2)Handler: 你可以构造Handler对象来与Looper沟通,以便push新消息到MessageQueue里;或者接收Looper从Message Queue取出)所送来的消息。
3) Message Queue(消息队列):用来存放线程放入的消息。

 4)线程:UIthread 通常就是main thread,而Android启动程序时会替它建立一个MessageQueue。 

1.Handler创建消息

 每一个消息都需要被指定的Handler处理,通过Handler创建消息便可以完成此功能。Android消息机制中引入了消息池。

Handler创建消息时首先查询消息池中是否有消息存在,如果有直接从消息池中取得,如果没有则重新初始化一个消息实例。

使用消息池的好处是:消息不被使用时,并不作为垃圾回收,而是放入消息池,可供下次Handler创建消息时使用。

消息池提高了消息对象的复用,减少系统垃圾回收的次数。消息的创建流程如图1所示。

2.Handler发送消息

主要接受子线程发送的数据, 并用此数据配合主线程更新UI.

解释: 当应用程序启动时,Android首先会开启一个主线程 (也就是UI线程,默认有一个消息队列) , 主线程为管理界面中的UI控件,进行事件分发,

比如说, 你要是点击一个 Button ,Android会分发事件到Button上,来响应你的操作。 如果此时需要一个耗时的操作,例如:

联网读取数据, 或者读取本地较大的一个文件的时候,你不能把这些操作放在主线程中,,如果你放在主线程中的话,界面会

出现假死现象,如果5秒钟还没有完成的话,会收到Android系统的一个错误提示 "强制关闭".

这个时候我们需要把这些耗时的操作,放在一个子线程中,因为子线程涉及到UI更新,Android主线程是线程不安全的,也就是说,

更新UI只能在主线程中更新,子线程中操作是危险的.

这个时候,Handler就出现了.,来解决这个复杂的问题 , 由于Handler运行在主线程中(UI线程中), 它与子线程可以通过Message对象来传递数据,

这个时候,Handler就承担着接受子线程传过来的(子线程用sedMessage()方法传弟)Message对象,(里面包含数据) , 把这些消息放入主线程队列中,配合主线程进行更新UI。

 

UI主线程初始化第一个Handler时会通过ThreadLocal创建一个Looper,该Looper与UI主线程一一对应。

使用ThreadLocal的目的是保证每一个线程只创建唯一一个Looper。之后其他Handler初始化的时候直接获取第一个Handler创建的Looper。

Looper初始化的时候会创建一个消息队列MessageQueue。至此,主线程、消息循环、消息队列之间的关系是1:1:1。
Handler、Looper、MessageQueue的初始化流程如图2所示:

 

                             图1                                                                  图2                                                              图3

一个最简单的异步任务例子:从网上下载一副图片(handler+message)

  1 package com.example.android_03handler;
  2 
  3 import org.apache.http.HttpResponse;
  4 import org.apache.http.client.HttpClient;
  5 import org.apache.http.client.methods.HttpGet;
  6 import org.apache.http.impl.client.DefaultHttpClient;
  7 import org.apache.http.util.EntityUtils;
  8 
  9 import android.app.Activity;
 10 import android.app.ProgressDialog;
 11 import android.graphics.Bitmap;
 12 import android.graphics.BitmapFactory;
 13 import android.os.Bundle;
 14 import android.os.Handler;
 15 import android.os.Message;
 16 import android.view.Menu;
 17 import android.view.MenuItem;
 18 import android.view.View;
 19 import android.widget.Button;
 20 import android.widget.ImageView;
 21 
 22 public class MainActivity extends Activity {
 23     private Button button;
 24     private ImageView imageView;
 25     private String image_Path = "http://pic14.nipic.com/20110522/7411759_164157418126_2.jpg";
 26     private final int IS_FINISHED=1;
 27     private ProgressDialog progressDialog;
 28     /**
 29      * Handler必须开启一个子线程
 30      * 该子线程必须通过Message传递数据给Handler
 31      */
 32     private Handler handler=new Handler(){
 33 
 34         @Override
 35         public void handleMessage(Message msg) {
 36             // TODO Auto-generated method stub
 37             super.handleMessage(msg);
 38             byte[] data=(byte[]) msg.obj;//将message发送回来的数据强制转换成字节数组
 39             Bitmap bitmap=BitmapFactory.decodeByteArray(data, 0, data.length);
 40             imageView.setImageBitmap(bitmap);
 41             if(msg.what==IS_FINISHED){
 42                 progressDialog.dismiss();
 43             }
 44         }
 45         
 46     };
 47     
 48     public class myThread implements Runnable{
 49 
 50         //完成耗时任务操作
 51         @Override
 52         public void run() {
 53             // TODO Auto-generated method stub
 54             HttpClient httpClient = new DefaultHttpClient();
 55             HttpGet httpGet = new HttpGet(image_Path);
 56             HttpResponse httpResponse =null;
 57             try {
 58                  httpResponse = httpClient.execute(httpGet);
 59                  if (httpResponse.getStatusLine().getStatusCode() == 200) {
 60                      byte[] data=EntityUtils.toByteArray(httpResponse.getEntity());
 61                      Message message=Message.obtain();
 62                      message.obj=data;
 63                      message.what=IS_FINISHED;
 64                      handler.sendMessage(message);
 65                      
 66                  }
 67             } catch (Exception e) {
 68                 // TODO: handle exception
 69                 e.printStackTrace();
 70             }
 71         }
 72         
 73     }
 74     @Override
 75     protected void onCreate(Bundle savedInstanceState) {
 76         super.onCreate(savedInstanceState);
 77         setContentView(R.layout.activity_main);
 78         button = (Button) this.findViewById(R.id.button1);
 79         imageView = (ImageView) this.findViewById(R.id.imageView1);
 80         progressDialog=new ProgressDialog(this);
 81         progressDialog.setTitle("提示");
 82         progressDialog.setMessage("downloading.....");
 83         progressDialog.setCancelable(false);
 84         button.setOnClickListener(new View.OnClickListener() {
 85             
 86             @Override
 87             public void onClick(View v) {
 88                 // TODO Auto-generated method stub
 89                 new Thread(new myThread()).start();
 90                 progressDialog.show();
 91             }
 92         });
 93     }
 94 
 95     @Override
 96     public boolean onCreateOptionsMenu(Menu menu) {
 97         // Inflate the menu; this adds items to the action bar if it is present.
 98         getMenuInflater().inflate(R.menu.main, menu);
 99         return true;
100     }
101 
102     @Override
103     public boolean onOptionsItemSelected(MenuItem item) {
104         // Handle action bar item clicks here. The action bar will
105         // automatically handle clicks on the Home/Up button, so long
106         // as you specify a parent activity in AndroidManifest.xml.
107         int id = item.getItemId();
108         if (id == R.id.action_settings) {
109             return true;
110         }
111         return super.onOptionsItemSelected(item);
112     }
113 }
View Code

message简单代码(不建议使用new生成消息,建议使用message.obtain()或者Handler.obtainMessage(....))

  1 package com.example.android_03message;
  2 
  3 import android.app.Activity;
  4 import android.os.Bundle;
  5 import android.os.Handler;
  6 import android.os.Message;
  7 import android.view.Menu;
  8 import android.view.MenuItem;
  9 import android.view.View;
 10 import android.widget.Button;
 11 
 12 public class MainActivity extends Activity {
 13     private Button button;
 14     private Handler handler=new Handler(){
 15 
 16         @Override
 17         public void handleMessage(Message msg) {
 18             // TODO Auto-generated method stub
 19             super.handleMessage(msg);
 20             int arg1=msg.arg1;
 21             int arg2=msg.arg2;
 22             int what=msg.what;
 23             Object obj=msg.obj;
 24             System.out.println("-->"+arg1+"-->"+arg2+"-->"+what+"-->"+obj);
 25             Bundle bundle=msg.getData();
 26             System.out.println(bundle.getStringArray("str").length);
 27         }
 28         
 29     };
 30     public class myThread implements Runnable{
 31 
 32         @Override
 33         public void run() {
 34             // TODO Auto-generated method stub
 35             //第一种方式
 36              /*Message message=Message.obtain();
 37              message.arg1=1;
 38              message.arg2=2;
 39              message.what=3;
 40              message.obj="mlj";
 41              handler.sendMessage(message);*/
 42             //第二种方式,源码中提示,默认执行了message.target=handler表明将消息交给某个handler去发送,
 43             //因此与第一种发送消息方式不同
 44             /* Message message=Message.obtain(handler);
 45              message.arg1=1;
 46              message.arg2=2;
 47              message.what=3;
 48              message.obj="mlj";
 49              message.sendToTarget();*/
 50             //第三种方式Message.obtain(handler,what);
 51             /* Message message=Message.obtain(handler,3);
 52              message.arg1=1;
 53              message.arg2=2;
 54              message.obj="mlj";
 55              message.sendToTarget();*/
 56             //第四种方式Message.obtain(handler,what,obj);
 57             /*Message message=Message.obtain(handler,3,"mlj");
 58              message.arg1=1;
 59              message.arg2=2;
 60              message.sendToTarget();*/
 61             //第五种方式Message.obtain(handler,what,arg1,arg2,obj);
 62             Message message=Message.obtain(handler,3,1,2,"mlj");
 63             //在传基本数据之外还可以通过setData传一些复杂数据
 64             Bundle  bundle=new Bundle();
 65             bundle.putStringArray("str", new String []{"mlj","mlj","mlj"});
 66             message.setData(bundle);
 67              message.sendToTarget();
 68             
 69         }
 70         
 71     }
 72     @Override
 73     protected void onCreate(Bundle savedInstanceState) {
 74         super.onCreate(savedInstanceState);
 75         setContentView(R.layout.activity_main);
 76         button = (Button) this.findViewById(R.id.button1);
 77         button.setOnClickListener(new View.OnClickListener() {
 78             
 79             @Override
 80             public void onClick(View v) {
 81                 // TODO Auto-generated method stub
 82                 new Thread(new myThread()).start();
 83             }
 84         });
 85     }
 86 
 87     @Override
 88     public boolean onCreateOptionsMenu(Menu menu) {
 89         // Inflate the menu; this adds items to the action bar if it is present.
 90         getMenuInflater().inflate(R.menu.main, menu);
 91         return true;
 92     }
 93 
 94     @Override
 95     public boolean onOptionsItemSelected(MenuItem item) {
 96         // Handle action bar item clicks here. The action bar will
 97         // automatically handle clicks on the Home/Up button, so long
 98         // as you specify a parent activity in AndroidManifest.xml.
 99         int id = item.getItemId();
100         if (id == R.id.action_settings) {
101             return true;
102         }
103         return super.onOptionsItemSelected(item);
104     }
105 }
View Code

handler的send(在线程内部发送消息方式)和post(new Runnable()...)两种发送消息方式的简单代码

 1 package com.example.android_03handler_message;
 2 
 3 import android.app.Activity;
 4 import android.os.Bundle;
 5 import android.os.Handler;
 6 import android.os.Message;
 7 import android.view.Menu;
 8 import android.view.MenuItem;
 9 import android.view.View;
10 import android.view.View.OnClickListener;
11 import android.widget.Button;
12 
13 public class MainActivity extends Activity implements OnClickListener{
14     private Button button;
15     private Button button2;
16     private Handler handler=new Handler(){
17 
18         @Override
19         public void handleMessage(Message msg) {
20             // TODO Auto-generated method stub
21             super.handleMessage(msg);
22             System.out.println("-->"+msg.what);
23         }
24         
25     };
26     @Override
27     protected void onCreate(Bundle savedInstanceState) {
28         super.onCreate(savedInstanceState);
29         setContentView(R.layout.activity_main);
30         button = (Button) this.findViewById(R.id.button1);
31         button2 = (Button) this.findViewById(R.id.button2);
32         button.setOnClickListener(this);
33         button2.setOnClickListener(this);
34     }
35 
36     @Override
37     public boolean onCreateOptionsMenu(Menu menu) {
38         // Inflate the menu; this adds items to the action bar if it is present.
39         getMenuInflater().inflate(R.menu.main, menu);
40         return true;
41     }
42 
43     @Override
44     public boolean onOptionsItemSelected(MenuItem item) {
45         // Handle action bar item clicks here. The action bar will
46         // automatically handle clicks on the Home/Up button, so long
47         // as you specify a parent activity in AndroidManifest.xml.
48         int id = item.getItemId();
49         if (id == R.id.action_settings) {
50             return true;
51         }
52         return super.onOptionsItemSelected(item);
53     }
54 
55     @Override
56     public void onClick(View v) {
57         // TODO Auto-generated method stub
58         switch (v.getId()) {
59         case R.id.button1:
60             new Thread(new Runnable() {
61                 
62                 @Override
63                 public void run() {
64                     // TODO Auto-generated method stub
65                     //handler.sendEmptyMessage(3);
66                     //handler.sendEmptyMessageAtTime(4, 1000);
67                     handler.sendEmptyMessageDelayed(3, 3000);
68                 }
69             }).start();
70             break;
71         case R.id.button2:
72              handler.post(new Runnable() {
73                 
74                 @Override
75                 public void run() {
76                     // TODO Auto-generated method stub
77                     handler.sendEmptyMessageDelayed(3, 4000);
78                 }
79             });
80             break;
81         default:
82             break;
83         }
84     }
85 }
View Code

Looper:

字面意思是“循环者”,它被设计用来使一个普通线程变成Looper线程。所谓Looper线程就是循环工作的线程。

在程序开发中(尤其是GUI开发中),我们经常会需要一个线程不断循环,一旦有新任务则执行,执行完继续等待下一个任务,这就是Looper线程。

使用Looper类创建Looper线程很简单:

 

public class LooperThread extends Thread {
    @Override
    public void run() {
        // 将当前线程初始化为Looper线程
        Looper.prepare();
        
        // ...其他处理,如实例化handler
        
        // 开始循环处理消息队列
        Looper.loop();
    }
}
View Code

Looper.prepare()之后线程就升级为Looper线程了,线程中有一个Looper对象,它的内部维护了一个消息队列MQ。注意,一个Thread只能有一个Looper对象

prepare()背后的工作方式一目了然,其核心就是将looper对象定义为ThreadLocal

调用loop方法后,Looper线程就开始真正工作了,它不断从自己的MQ中取出队头的消息(也叫任务)执行。

除了prepare()和loop()方法,Looper类还提供了一些有用的方法,比如:

Looper.myLooper()得到当前线程looper对象:

1 public static final Looper myLooper() {
2         // 在任意线程调用Looper.myLooper()返回的都是那个线程的looper
3         return (Looper)sThreadLocal.get();
4     }
View Code

getThread()得到looper对象所属线程:

1 public Thread getThread() {
2         return mThread;
3     }
View Code

quit()方法结束looper循环:

1 public void quit() {
2         // 创建一个空的message,它的target为NULL,表示结束循环消息
3         Message msg = Message.obtain();
4         // 发出消息
5         mQueue.enqueueMessage(msg, 0);
6     }
View Code

简单的looper代码:

 1 package com.example.android_08looper;
 2 
 3 import android.app.Activity;
 4 import android.os.Bundle;
 5 import android.os.Handler;
 6 import android.os.Looper;
 7 import android.os.Message;
 8 import android.view.Menu;
 9 import android.view.MenuItem;
10 import android.view.View;
11 import android.widget.Button;
12 import android.widget.TextView;
13 
14 public class MainActivity extends Activity {
15 
16     private  Button button1;
17     private TextView textView1;
18     private myHandler mHandler;
19     @Override
20     protected void onCreate(Bundle savedInstanceState) {
21         super.onCreate(savedInstanceState);
22         setContentView(R.layout.activity_main);
23         button1=(Button)this.findViewById(R.id.button1);
24         textView1=(TextView)this.findViewById(R.id.textView1);
25         //使用无参构造方法时handler并未与looper关联,但是为什么可以发送并接收消息呢?
26         //原因是Activity中默认有一个Looper对象来处理子线程发送的消息,其实相当于一下内容
27         //Looper looper=Looper.myLooper();//从UI主线程中得到looper
28         //mHandler=new myHandler(looper);
29         Looper looper=Looper.myLooper();
30         mHandler=new myHandler();
31         button1.setOnClickListener(new View.OnClickListener() {
32             
33             @Override
34             public void onClick(View v) {
35                 // TODO Auto-generated method stub
36                 new Thread(new myThread()).start();//在主线程中开启一个子线程
37             }
38         });
39     }
40 
41     public class myThread implements Runnable{
42 
43         @Override
44         public void run() {
45             // TODO Auto-generated method stub
46             Message message=Message.obtain();
47             message.obj="mlj";
48             mHandler.sendMessage(message);
49         }
50         
51     }
52     public class myHandler extends Handler{
53 
54         public myHandler(Looper looper) {
55             super(looper);
56             // TODO Auto-generated constructor stub
57         }
58         public myHandler() {
59         
60         }
61 
62 
63         @Override
64         public void handleMessage(Message msg) {
65             // TODO Auto-generated method stub
66             super.handleMessage(msg);
67             textView1.setText("-接收消息->>"+msg.obj);
68         }
69         
70     }
71     @Override
72     public boolean onCreateOptionsMenu(Menu menu) {
73         // Inflate the menu; this adds items to the action bar if it is present.
74         getMenuInflater().inflate(R.menu.main, menu);
75         return true;
76     }
77 
78     @Override
79     public boolean onOptionsItemSelected(MenuItem item) {
80         // Handle action bar item clicks here. The action bar will
81         // automatically handle clicks on the Home/Up button, so long
82         // as you specify a parent activity in AndroidManifest.xml.
83         int id = item.getItemId();
84         if (id == R.id.action_settings) {
85             return true;
86         }
87         return super.onOptionsItemSelected(item);
88     }
89 }
View Code

在以上例子中,如果handler的实例化脱离了UI主线程,而在子线程中实例化的话,就无法使用Activity中默认的looper对象,

就需要手工开启Looper,代码如下:

 

 1 package com.example.android_08looper;
 2 
 3 import android.app.Activity;
 4 import android.os.Bundle;
 5 import android.os.Handler;
 6 import android.os.Looper;
 7 import android.os.Message;
 8 import android.view.Menu;
 9 import android.view.MenuItem;
10 import android.view.View;
11 import android.widget.Button;
12 import android.widget.TextView;
13 
14 public class MainActivity extends Activity {
15 
16     private  Button button1;
17     private TextView textView1;
18     private Handler mHandler;
19     @Override
20     protected void onCreate(Bundle savedInstanceState) {
21         super.onCreate(savedInstanceState);
22         setContentView(R.layout.activity_main);
23         button1=(Button)this.findViewById(R.id.button1);
24         textView1=(TextView)this.findViewById(R.id.textView1);
25         new Thread(new myThread()).start();
26         button1.setOnClickListener(new View.OnClickListener() {
27             
28             @Override
29             public void onClick(View v) {
30                 // TODO Auto-generated method stub
31                 Message message=Message.obtain();
32                 message.obj="mlj";
33                 mHandler.sendMessage(message);
34             }
35         });
36     }
37 
38     public class myThread implements Runnable{
39 
40         @Override
41         public void run() {
42             // TODO Auto-generated method stub
43             Looper.prepare();
44             mHandler=new Handler(){
45 
46                 @Override
47                 public void handleMessage(Message msg) {
48                     // TODO Auto-generated method stub
49                     super.handleMessage(msg);
50                     //textView1.setText("--->>接收UI主线程的消息"+msg.obj);//在子线程中无法更新UI所以改成以下语句
51                     System.out.println("--->>接收UI主线程的消息"+msg.obj);
52                 }
53                 
54             };
55             Looper.loop();
56         }
57         
58     }
59     @Override
60     public boolean onCreateOptionsMenu(Menu menu) {
61         // Inflate the menu; this adds items to the action bar if it is present.
62         getMenuInflater().inflate(R.menu.main, menu);
63         return true;
64     }
65 
66     @Override
67     public boolean onOptionsItemSelected(MenuItem item) {
68         // Handle action bar item clicks here. The action bar will
69         // automatically handle clicks on the Home/Up button, so long
70         // as you specify a parent activity in AndroidManifest.xml.
71         int id = item.getItemId();
72         if (id == R.id.action_settings) {
73             return true;
74         }
75         return super.onOptionsItemSelected(item);
76     }
77 }
View Code

 

总结几点:

1.每个线程有且最多只能有一个Looper对象,它是一个ThreadLocal

2.Looper内部有一个消息队列,loop()方法调用后线程开始不断从队列中取出消息执行

3.Looper使一个线程变成Looper线程。

 ---------------------

综合案例(图文混排):客户端(AsyncTask,Handler,Message,listView)+服务器端,未缓存

服务器端最终返回给客户端的是jsonString,内容是:

1 {"products":[{"proprice":"5","proaddress":"河南","proimage":"1.jpg","proname":"苹果","proid":"4a6c8e"},{"proprice":"2","proaddress":"北京","proimage":"1.jpg","proname":"猕猴桃","proid":"5fd850"},{"proprice":"4","proaddress":"广州","proimage":"1.jpg","proname":"香蕉","proid":"7c39b7"},{"proprice":"1","proaddress":"广州","proimage":"1.jpg","proname":"","proid":"850995"},{"proprice":"3","proaddress":"北京","proimage":"1.jpg","proname":"西瓜","proid":"be3314"},{"proprice":"7","proaddress":"上海","proimage":"1.jpg","proname":"桃子","proid":"c84833"}]} 
View Code

客户端源文件目录如图:

 步骤:

第一步:在布局文件中添加listView

 1 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
 2     xmlns:tools="http://schemas.android.com/tools"
 3     android:layout_width="match_parent"
 4     android:layout_height="match_parent"
 5     android:paddingBottom="@dimen/activity_vertical_margin"
 6     android:paddingLeft="@dimen/activity_horizontal_margin"
 7     android:paddingRight="@dimen/activity_horizontal_margin"
 8     android:paddingTop="@dimen/activity_vertical_margin"
 9     tools:context="com.example.android_08handler_product.MainActivity" >
10 
11     <ListView
12         android:id="@+id/listView1"
13         android:layout_width="match_parent"
14         android:layout_height="wrap_content"
15         android:layout_alignParentTop="true"
16         android:layout_centerHorizontal="true" >
17     </ListView>
18 
19 </RelativeLayout>
View Code

第二步:在清单文件中添加网络授权

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

第三步:定义一个公共类CommonURL.java,存放客户端访问的网络地址

1 package com.example.android_08handler_product;
2 
3 public class CommonURL {
4 
5     //访问服务器产品url 
6      static String Pro_URL="http://122.206.79.193:8080/xianfengProject/servlet/JsonAction?action_flag=more";
7     //访问服务器产品图片url 
8      static String Pro_ImgURL="http://122.206.79.193:8080/xianfengProject/upload/";
9 }
View Code

第四步:编写主程序

注:图文混排时,不建议文字和图片在同一线程中出现或解决,一般是先处理文字再处理图片。

4.1 定义listView控件并取得 

4.2为listView定义适配器(全局的)并在oncreate()方法中初始化,通常分以下几步

1.声明Context context,LayoutInflater layoutInflater两个变量并在构造方法中取值:this.**=**;

2.提供void setData()方法,由于取json数据时,数据类型是map类型,因此在适配器中需定义全局变量List<Map<String,Object>> list=null,

并在该方法中设置 this.list=list;

3. 完成适配器中除getView()方法以外的其他方法;

4.为适配器定义布局文件item.xml

 1 <?xml version="1.0" encoding="utf-8"?>
 2 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
 3     android:layout_width="match_parent"
 4     android:layout_height="match_parent" >
 5 
 6     <ImageView
 7         android:id="@+id/imageView1"
 8         android:layout_width="wrap_content"
 9         android:layout_height="wrap_content"
10         android:layout_alignParentLeft="true"
11         android:layout_alignParentTop="true"
12         android:layout_marginLeft="16dp"
13         android:src="@drawable/ic_launcher" />
14 
15     <TextView
16         android:id="@+id/textView1"
17         android:layout_width="wrap_content"
18         android:layout_height="wrap_content"
19         android:layout_alignParentTop="true"
20         android:layout_toRightOf="@+id/imageView1"
21         android:text="TextView" />
22 
23     <TextView
24         android:id="@+id/textView2"
25         android:layout_width="wrap_content"
26         android:layout_height="wrap_content"
27         android:layout_alignLeft="@+id/textView1"
28         android:layout_below="@+id/textView1"
29         android:text="TextView" />
30 
31     <TextView
32         android:id="@+id/textView3"
33         android:layout_width="wrap_content"
34         android:layout_height="wrap_content"
35         android:layout_alignLeft="@+id/textView2"
36         android:layout_below="@+id/textView2"
37         android:text="TextView" />
38 
39 </RelativeLayout>
View Code

5. 完成适配器中getView()方法;

 1 @Override
 2         public View getView(int position, View convertView, ViewGroup parent) {
 3             // TODO Auto-generated method stub
 4             View view=null;
 5             if(convertView==null){
 6                 view=layoutInflater.inflate(R.layout.item, null);
 7             }
 8             else
 9                 view=convertView;
10             TextView name=(TextView)view.findViewById(R.id.textView1);
11             TextView address=(TextView)view.findViewById(R.id.textView2);
12             TextView price=(TextView)view.findViewById(R.id.textView3);
13             final ImageView imageView=(ImageView)view.findViewById(R.id.imageView1);
14             //接下来需要给name address price赋值成从服务器上取下来的数据,这就需要定义异步任务
15             name.setText(list.get(position).get("proname").toString());
16             address.setText(list.get(position).get("proaddress").toString());
17             price.setText(list.get(position).get("proprice").toString());
18          //图片待会儿再处理
19             return view;
20         }
View Code

由于在5中需要对name  address price image赋值,这些值是从服务器取下来的json数据并解析后传回来的,这就需要定义异步任务AsyncTask了

4.3 定义异步任务

1.通常需要定义一个ProgressDialog并在oncreate方法中初始化

1     dialog=new ProgressDialog(this);
2     dialog.setTitle("提示");
3     dialog.setMessage("正在下载,请稍后......");
View Code

2.定义异步任务,实现3个方法

 1     public class myTask extends AsyncTask<String, Void, List<Map<String,Object>>>{
 2 
 3         @Override
 4         protected void onPreExecute() {
 5             // TODO Auto-generated method stub
 6             dialog.show();
 7             super.onPreExecute();
 8         }
 9 
10         @Override
11         protected void onPostExecute(List<Map<String, Object>> result) {
12             // TODO Auto-generated method stub
13             super.onPostExecute(result);
14             adapter.setData(result);
15             listView.setAdapter(adapter);
16             adapter.notifyDataSetChanged();
17             dialog.dismiss();
18             
19         }
20 
21         @Override
22         protected List<Map<String, Object>> doInBackground(String... params) {
23             // TODO Auto-generated method stub
24             //list 服务器返回的最终经过解析后的json数据
25             List<Map<String, Object>> list=new ArrayList<Map<String,Object>>();
26             //连接网络 获取json数据并解析
27             try {
28                 HttpClient client=new DefaultHttpClient();
29                 //HttpGet httpGet=new HttpGet(params[0]);//不建议使用 因为大小受限制
30                 HttpPost httpPost=new HttpPost(params[0]);
31                 HttpResponse response=client.execute(httpPost);
32                 if(response.getStatusLine().getStatusCode()==200){
33                     String jsonString=EntityUtils.toString(response.getEntity(), "utf-8");
34                     //以上获取数据
35                     //以下解析数据
36                     JSONObject jsonObject=new JSONObject(jsonString);//返回的数据key为products,Value为数组,数组中的每个元素又是jsonObject
37                     JSONArray jsonArray=jsonObject.getJSONArray("products");
38                     for (int i = 0; i < jsonArray.length(); i++) {
39                         JSONObject jsonObject2=jsonArray.getJSONObject(i);
40                         Map<String,Object> map=new HashMap<String, Object>();
41                         Iterator<String> iterator=jsonObject2.keys();
42                         while(iterator.hasNext()){
43                             String key=iterator.next();
44                             Object val=jsonObject2.get(key);
45                             map.put(key, val);
46                         }
47                         list.add(map);
48                     }
49                 }
50                 
51             } catch (Exception e) {
52                 // TODO: handle exception
53                 e.printStackTrace();
54             }
55             return list;
56         }
57         
58     }
59     @Override
60     
View Code

3.在oncreate()方法中开启任务,传递的参数是CommonURL中的地址

1 new myTask().execute(CommonURL.Pro_URL);
View Code

 在onpostExcute()方法执行时,通过适配器的setData方法填充适配器,并为listView绑定数据源

1 protected void onPostExecute(List<Map<String, Object>> result) {
2             // TODO Auto-generated method stub
3             super.onPostExecute(result);
4             adapter.setData(result);
5             listView.setAdapter(adapter);
6             adapter.notifyDataSetChanged();
7             dialog.dismiss();
8             
9         }
View Code

之后 就得回到第四步4.2的最后一小步,即更新UI

1 name.setText(list.get(position).get("proname").toString());
2             address.setText(list.get(position).get("proaddress").toString());
3             price.setText(list.get(position).get("proprice").toString());
View Code

----------接下来得用接口回调来加载图片---------------

需要专门定义一个用来处理图片的类DownLoadImg.java,该类包括:

一个用来传递图片地址的构造方法,一个提供得到图片方法的接口,和一个下载图片、开启子线程返回消息给handler的方法(其参数是回调接口的一个对象)

该类接收activity传过来的图片路径并方法中开启一个子线程中下载图片作为消息返回给handler处理,handler的处理方式是通过回调对象获得该图片的引用,

然后在activity中调用该方法时,需要new一个接口对象作为参数,该参数是一个匿名内部类,在该类的实现接口方法中即可获得图片

因为该类需要开启一个子线程,得到图片

接口回调:定义一个接口,该接口提供了一个得到图片的方法getDrawable,方法参数为Drawable类型

1 public interface ImgCallBack{
2         public void getDrawable(Drawable drawable);
3     }
View Code

最终代码:

MainActivity:

  1 package com.example.android_08handler_product;
  2 
  3 import java.util.ArrayList;
  4 import java.util.HashMap;
  5 import java.util.Iterator;
  6 import java.util.List;
  7 import java.util.Map;
  8 
  9 import org.apache.http.HttpResponse;
 10 import org.apache.http.client.HttpClient;
 11 import org.apache.http.client.methods.HttpPost;
 12 import org.apache.http.impl.client.DefaultHttpClient;
 13 import org.apache.http.util.EntityUtils;
 14 import org.json.JSONArray;
 15 import org.json.JSONObject;
 16 
 17 import android.app.Activity;
 18 import android.app.ProgressDialog;
 19 import android.content.Context;
 20 import android.graphics.drawable.Drawable;
 21 import android.os.AsyncTask;
 22 import android.os.Bundle;
 23 import android.view.LayoutInflater;
 24 import android.view.Menu;
 25 import android.view.MenuItem;
 26 import android.view.View;
 27 import android.view.ViewGroup;
 28 import android.widget.BaseAdapter;
 29 import android.widget.ImageView;
 30 import android.widget.ListView;
 31 import android.widget.TextView;
 32 
 33 import com.example.android_08handler_product.DownLoadImg.ImgCallBack;
 34 
 35 public class MainActivity extends Activity {
 36 
 37     private ListView listView;
 38     private ProgressDialog dialog;
 39     private myAdapter adapter;
 40     @Override
 41     protected void onCreate(Bundle savedInstanceState) {
 42         super.onCreate(savedInstanceState);
 43         setContentView(R.layout.activity_main);
 44         listView=(ListView)this.findViewById(R.id.listView1);
 45         dialog=new ProgressDialog(this);
 46         dialog.setTitle("提示");
 47         dialog.setMessage("正在下载,请稍后......");
 48         adapter=new myAdapter(this);
 49         new myTask().execute(CommonURL.Pro_URL);
 50     }
 51 
 52     public class myAdapter extends BaseAdapter{
 53 
 54         private Context context;
 55         private LayoutInflater layoutInflater;
 56         private List<Map<String,Object>> list=null;//存放最终解析过的json数据
 57         public  myAdapter(){
 58             
 59         }
 60         public  myAdapter(Context context){
 61             this.context=context;
 62             layoutInflater=layoutInflater.from(context);
 63         }
 64          public void setData(List<Map<String,Object>> list){
 65              this.list=list;
 66          }
 67        @Override
 68         public int getCount() {
 69             // TODO Auto-generated method stub
 70             return list.size();
 71         }
 72 
 73         @Override
 74         public Object getItem(int position) {
 75             // TODO Auto-generated method stub
 76             return list.get(position);
 77         }
 78 
 79         @Override
 80         public long getItemId(int position) {
 81             // TODO Auto-generated method stub
 82             return position;
 83         }
 84 
 85         @Override
 86         public View getView(int position, View convertView, ViewGroup parent) {
 87             // TODO Auto-generated method stub
 88             View view=null;
 89             if(convertView==null){
 90                 view=layoutInflater.inflate(R.layout.item, null);
 91             }
 92             else
 93                 view=convertView;
 94             TextView name=(TextView)view.findViewById(R.id.textView1);
 95             TextView address=(TextView)view.findViewById(R.id.textView2);
 96             TextView price=(TextView)view.findViewById(R.id.textView3);
 97             final ImageView imageView=(ImageView)view.findViewById(R.id.imageView1);
 98             //接下来需要给name address price赋值成从服务器上取下来的数据,这就需要定义异步任务
 99             name.setText(list.get(position).get("proname").toString());
100             address.setText(list.get(position).get("proaddress").toString());
101             price.setText(list.get(position).get("proprice").toString());
102             DownLoadImg downLoadImg=new DownLoadImg(CommonURL.Pro_ImgURL+list.get(position).get("proimage").toString());
103             downLoadImg.loadImg(new ImgCallBack() {
104                 
105                 @Override
106                 public void getDrawable(Drawable drawable) {
107                     // TODO Auto-generated method stub
108                     imageView.setImageDrawable(drawable);
109                 }
110             });
111             return view;
112         }
113         
114     }
115     public class myTask extends AsyncTask<String, Void, List<Map<String,Object>>>{
116 
117         @Override
118         protected void onPreExecute() {
119             // TODO Auto-generated method stub
120             dialog.show();
121             super.onPreExecute();
122         }
123 
124         @Override
125         protected void onPostExecute(List<Map<String, Object>> result) {
126             // TODO Auto-generated method stub
127             super.onPostExecute(result);
128             adapter.setData(result);
129             listView.setAdapter(adapter);
130             adapter.notifyDataSetChanged();
131             dialog.dismiss();
132             
133         }
134 
135         @Override
136         protected List<Map<String, Object>> doInBackground(String... params) {
137             // TODO Auto-generated method stub
138             //list 服务器返回的最终经过解析后的json数据
139             List<Map<String, Object>> list=new ArrayList<Map<String,Object>>();
140             //连接网络 获取json数据并解析
141             try {
142                 HttpClient client=new DefaultHttpClient();
143                 //HttpGet httpGet=new HttpGet(params[0]);//不建议使用 因为大小受限制
144                 HttpPost httpPost=new HttpPost(params[0]);
145                 HttpResponse response=client.execute(httpPost);
146                 if(response.getStatusLine().getStatusCode()==200){
147                     String jsonString=EntityUtils.toString(response.getEntity(), "utf-8");
148                     //以上获取数据
149                     //以下解析数据
150                     JSONObject jsonObject=new JSONObject(jsonString);//返回的数据key为products,Value为数组,数组中的每个元素又是jsonObject
151                     JSONArray jsonArray=jsonObject.getJSONArray("products");
152                     for (int i = 0; i < jsonArray.length(); i++) {
153                         JSONObject jsonObject2=jsonArray.getJSONObject(i);
154                         Map<String,Object> map=new HashMap<String, Object>();
155                         Iterator<String> iterator=jsonObject2.keys();
156                         while(iterator.hasNext()){
157                             String key=iterator.next();
158                             Object val=jsonObject2.get(key);
159                             map.put(key, val);
160                         }
161                         list.add(map);
162                     }
163                 }
164                 
165             } catch (Exception e) {
166                 // TODO: handle exception
167                 e.printStackTrace();
168             }
169             return list;
170         }
171         
172     }
173     @Override
174     public boolean onCreateOptionsMenu(Menu menu) {
175         // Inflate the menu; this adds items to the action bar if it is present.
176         getMenuInflater().inflate(R.menu.main, menu);
177         return true;
178     }
179 
180     @Override
181     public boolean onOptionsItemSelected(MenuItem item) {
182         // Handle action bar item clicks here. The action bar will
183         // automatically handle clicks on the Home/Up button, so long
184         // as you specify a parent activity in AndroidManifest.xml.
185         int id = item.getItemId();
186         if (id == R.id.action_settings) {
187             return true;
188         }
189         return super.onOptionsItemSelected(item);
190     }
191 }
View Code

DownLoadImg

 1 package com.example.android_08handler_product;
 2 
 3 import java.io.IOException;
 4 import java.io.InputStream;
 5 import java.net.MalformedURLException;
 6 import java.net.URL;
 7 
 8 import android.graphics.drawable.Drawable;
 9 import android.os.Handler;
10 import android.os.Message;
11 
12 public class DownLoadImg {
13 
14     private String img_path;
15     public DownLoadImg(String img_path) {
16         // TODO Auto-generated constructor stub
17         this.img_path=img_path;
18     }
19 
20     public void loadImg(final ImgCallBack back){
21         final Handler handler=new Handler(){
22 
23             @Override
24             public void handleMessage(Message msg) {
25                 // TODO Auto-generated method stub
26                 super.handleMessage(msg);
27                 back.getDrawable((Drawable)msg.obj);
28             }
29         };
30         new Thread(new Runnable() {
31             
32             @Override
33             public void run() {
34                 InputStream is;
35                 try {
36                     is = new URL(img_path).openStream();
37                     Drawable drawable=Drawable.createFromStream(is, "");
38                     Message message=Message.obtain();
39                     message.obj=drawable;
40                     handler.sendMessage(message);
41                 } catch (MalformedURLException e) {
42                     // TODO Auto-generated catch block
43                     e.printStackTrace();
44                 } catch (IOException e) {
45                     // TODO Auto-generated catch block
46                     e.printStackTrace();
47                 }
48                 // TODO Auto-generated method stub
49                 
50             }
51         }).start();
52     }
53     //接口的回调方式
54     public interface ImgCallBack{
55         public void getDrawable(Drawable drawable);
56     }
57 }
View Code

 

posted @ 2015-11-14 10:06  孟想阳光  阅读(581)  评论(0编辑  收藏  举报