android通过线程来解决主线程的的一些耗时操作。android的线程通过Handler,Looper,Message Queues和Message来进行线程之间的通信。在android中有两种实现线程thread的方法:一种是,扩展java.lang.Thread类 ,另一种是,实现Runnable接口。它的两个最主要的方法是: run()——包含线程运行时所执行的代码 Start()——用于启动线程。
1. Message
Message消息,理解为线程间交流的信息,处理数据后台线程需要更新UI,则发送Message内含一些数据给UI线程。
2. Handler
Handler处理者,是Message的主要处理者,负责Message的发送,Message内容的执行处理。后台线程就是通过传进来的Handler对象引用来sendMessage(Message)。而使用Handler,需要implement 该类的 handleMessage(Message)方法,它是处理这些Message的操作内容,例如Update UI。通常需要子类化Handler来实现handleMessage方法。
3. Message Queue
Message Queue消息队列,用来存放通过Handler发布的消息,按照先进先出执行。
每个message queue都会有一个对应的Handler。Handler会向message queue通过两种方法发送消息:sendMessage或post。这两种消息都会插在message queue队尾并按先进先出执行。但通过这两种方法发送的消息执行的方式略有不同:通过sendMessage发送的是一个message对象,会被Handler的handleMessage()函数处理;而通过post方法发送的是一个runnable对象,则会自己执行。
4. Looper
Looper是每条线程里的Message Queue的管家。Android没有Global的Message Queue,而Android会自动替主线程(UI线程)建立Message Queue,但在子线程里并没有建立Message Queue。所以调用Looper.getMainLooper()得到的主线程的Looper不为NULL,但调用Looper.myLooper()得到当前线程的Looper就有可能为NULL。
现在来看一个例子,模拟从网络获取数据,加载到ListView的过程:
1 public class ListProgressDemo extends ListActivity { 2 3 @Override 4 public void onCreate(Bundle savedInstanceState) { 5 super.onCreate(savedInstanceState); 6 setContentView(R.layout.listprogress); 7 8 ((Button) findViewById(R.id.load_Handler)).setOnClickListener(new View.OnClickListener(){ 9 10 @Override 11 public void onClick(View view) { 12 data = null; 13 data = new ArrayList<String>(); 14 15 adapter = null; 16 17 showDialog(PROGRESS_DIALOG); 18 new ProgressThread(handler, data).start(); 19 } 20 }); 21 } 22 23 @Override 24 protected Dialog onCreateDialog(int id) { 25 switch(id) { 26 case PROGRESS_DIALOG: 27 return ProgressDialog.show(this, "", 28 "Loading. Please wait...", true); 29 30 default: return null; 31 } 32 } 33 34 private class ProgressThread extends Thread { 35 36 private Handler handler; 37 private ArrayList<String> data; 38 39 public ProgressThread(Handler handler, ArrayList<String> data) { 40 this.handler = handler; 41 this.data = data; 42 } 43 44 @Override 45 public void run() { 46 for (int i=0; i<8; i++) { 47 data.add("ListItem"); //后台数据处理 48 try { 49 Thread.sleep(100); 50 }catch(InterruptedException e) { 51 52 Message msg = handler.obtainMessage(); 53 Bundle b = new Bundle(); 54 b.putInt("state", STATE_ERROR); 55 msg.setData(b); 56 handler.sendMessage(msg); 57 58 } 59 } 60 Message msg = handler.obtainMessage(); 61 Bundle b = new Bundle(); 62 b.putInt("state", STATE_FINISH); 63 msg.setData(b); 64 handler.sendMessage(msg); 65 } 66 67 } 68 69 // 此处甚至可以不需要设置Looper,因为Handler默认就使用当前线程的Looper 70 private final Handler handler = new Handler(Looper.getMainLooper()) { 71 72 public void handleMessage(Message msg) { // 处理Message,更新ListView 73 int state = msg.getData().getInt("state"); 74 switch(state){ 75 case STATE_FINISH: 76 dismissDialog(PROGRESS_DIALOG); 77 Toast.makeText(getApplicationContext(), 78 "加载完成!", 79 Toast.LENGTH_LONG) 80 .show(); 81 82 adapter = new ArrayAdapter<String>(getApplicationContext(), 83 android.R.layout.simple_list_item_1, 84 data ); 85 86 setListAdapter(adapter); 87 88 break; 89 90 case STATE_ERROR: 91 dismissDialog(PROGRESS_DIALOG); 92 Toast.makeText(getApplicationContext(), 93 "处理过程发生错误!", 94 Toast.LENGTH_LONG) 95 .show(); 96 97 adapter = new ArrayAdapter<String>(getApplicationContext(), 98 android.R.layout.simple_list_item_1, 99 data ); 100 101 setListAdapter(adapter); 102 103 break; 104 105 default: 106 107 } 108 } 109 }; 110 111 112 private ArrayAdapter<String> adapter; 113 private ArrayList<String> data; 114 115 private static final int PROGRESS_DIALOG = 1; 116 private static final int STATE_FINISH = 1; 117 private static final int STATE_ERROR = -1; 118 }
AsyncTask版:
1 ((Button) findViewById(R.id.load_AsyncTask)).setOnClickListener(new View.OnClickListener(){ 2 3 @Override 4 public void onClick(View view) { 5 data = null; 6 data = new ArrayList<String>(); 7 8 adapter = null; 9 10 //显示ProgressDialog放到AsyncTask.onPreExecute()里 11 //showDialog(PROGRESS_DIALOG); 12 new ProgressTask().execute(data); 13 } 14 }); 15 16 private class ProgressTask extends AsyncTask<ArrayList<String>, Void, Integer> { 17 18 /* 该方法将在执行实际的后台操作前被UI thread调用。可以在该方法中做一些准备工作,如在界面上显示一个进度条。*/ 19 @Override 20 protected void onPreExecute() { 21 // 先显示ProgressDialog 22 showDialog(PROGRESS_DIALOG); 23 } 24 25 /* 执行那些很耗时的后台计算工作。可以调用publishProgress方法来更新实时的任务进度。 */ 26 @Override 27 protected Integer doInBackground(ArrayList<String>... datas) { 28 ArrayList<String> data = datas[0]; 29 for (int i=0; i<8; i++) { 30 data.add("ListItem"); 31 } 32 return STATE_FINISH; 33 } 34 35 /* 在doInBackground 执行完成后,onPostExecute 方法将被UI thread调用, 36 * 后台的计算结果将通过该方法传递到UI thread. 37 */ 38 @Override 39 protected void onPostExecute(Integer result) { 40 int state = result.intValue(); 41 switch(state){ 42 case STATE_FINISH: 43 dismissDialog(PROGRESS_DIALOG); 44 Toast.makeText(getApplicationContext(), 45 "加载完成!", 46 Toast.LENGTH_LONG) 47 .show(); 48 49 adapter = new ArrayAdapter<String>(getApplicationContext(), 50 android.R.layout.simple_list_item_1, 51 data ); 52 53 setListAdapter(adapter); 54 55 break; 56 57 case STATE_ERROR: 58 dismissDialog(PROGRESS_DIALOG); 59 Toast.makeText(getApplicationContext(), 60 "处理过程发生错误!", 61 Toast.LENGTH_LONG) 62 .show(); 63 64 adapter = new ArrayAdapter<String>(getApplicationContext(), 65 android.R.layout.simple_list_item_1, 66 data ); 67 68 setListAdapter(adapter); 69 70 break; 71 72 default: 73 74 } 75 }
Android另外提供了一个工具类:AsyncTask。它使得UI thread的使用变得异常简单。它使创建需要与用户界面交互的长时间运行的任务变得更简单,不需要借助线程和Handler即可实现。
1) 子类化AsyncTask
2) 实现AsyncTask中定义的下面一个或几个方法
onPreExecute() 开始执行前的准备工作;
doInBackground(Params...) 开始执行后台处理,可以调用publishProgress方法来更新实时的任务进度;
onProgressUpdate(Progress...) 在publishProgress方法被调用后,UI thread将调用这个方法从而在界面上展示任务的进展情况,例如通过一个进度条进行展示。
onPostExecute(Result) 执行完成后的操作,传送结果给UI 线程。
这4个方法都不能手动调用。而且除了doInBackground(Params...)方法,其余3个方法都是被UI线程所调用的,所以要求:
1) AsyncTask的实例必须在UI thread中创建;
2) AsyncTask.execute方法必须在UI thread中调用;
同时要注意:该task只能被执行一次,否则多次调用时将会出现异常。而且是不能手动停止的,这一点要注意,看是否符合你的需求!
浙公网安备 33010602011771号