- Date:2015-4-29
- Tag:android; AsyncTask、異步加載、Thread、handler、message
- Author:踏雪
- Email:[email protected]
一、 介紹
當一個Android app啓動同時,也會啓動一個UI主線程,所有的UI操作都必須在這個UI主線程上執行,如果在子線程執行UI操作則會出現奔潰。一些android上耗時的操作,如圖片加載、數據庫訪問、複雜的業務邏輯處理都應該放在子線程中來完成,否則會出現ANR的問題。現在介紹兩種最常用的異步加載方案。分別是AsyncTask和Thread、Handler實現。
二、 AsyncTask實現異步加載
AsyncTask比較適合那種短時的操作,例如就幾秒鐘。如果想要線程長時間運行,最好用Executor、ThreadPoolExecutor或者FutureTask。繼承AsyncTask的子類至少要實現doInBackground方法。
1、AsyncTask基本參數
AsyncTask< Params, Progress, Result >
(1)Params:傳遞給子線程的參數類型,可以是String、Integer等基本數據類型,也可以是類對象。
(2)Progress:進度參數的數據類型
(3)Result:線程返回結果的數據類型
2、AsyncTask基本方法
(1) onPreExecute: 在線程被執行前執行的一些操作,如初始化工作等。
(2) doInBackground:在onPreExecute執行後被調用的函數,上面說的Params參數就是被傳遞到這個函數方法裏。運行結果也是在這裏返回。在這個函數裏,可以調用publishProgress公佈進度情況。
(3) publishProgress:公佈線程執行的進度。
(4) onProgressUpdate:在publishProgress執行後被調用的函數,用於更新進度信息。
(5) onPostExecute:線程執行完後調用該函數,線程執行的結果作爲該函數的參數。
(6) cancle:終止線程的運行。
3、代碼實例
public class MainActivity extends Activity {
private TextView textView = null;
private SeekBar seekBar = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = (TextView)findViewById(R.id.progress_text);
seekBar = (SeekBar)findViewById(R.id.progress_bar);
Worker workder = new Worker("wgc", 90);
new DemoAsyncTask().execute(workder);
}
class Worker {
private String name;
private int progress;
public Worker(String name, int progress) {
this.name = name;
this.progress = progress;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getProgress() {
return progress;
}
public void setProgress(int progress) {
this.progress = progress;
}
}
class DemoAsyncTask extends AsyncTask<Worker, Integer, String>{
@Override
protected void onPreExecute() {
Log.v("test", "onPreExecute() is called!");
textView.setText("Loading......");
}
@Override
protected String doInBackground(Worker... params) {
Log.v("test", "doInBackground() is called!");
Worker worker = params[0];
for(int i = 1; i<= worker.getProgress(); i++) {
publishProgress(i);//每次使用該函數會調用onProgressUpdate來更新UI的進度
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return "loading finished!";//這個結果將作爲onPostExecute的參數
}
@Override
protected void onProgressUpdate(Integer... values) {
Log.v("test", "onProgressUpdate() is called!");
//更新UI的進度
textView.setText(values[0] + "");
seekBar.setProgress(values[0]);
if(values[0] == 60) this.cancel(true);//終止線程的運行
}
@Override
protected void onPostExecute(String result) {
Log.v("test", "onPostExecute() is called!");
textView.setText(result);
}
}
}
下面是日誌的輸出結果:可以看到onPreExecute是最先被執行的,然後是doInBackground,在doInBackground裏,每一次調用publishProgress都會onProgressUpdate來更新UI。最後就是調用onPostExecute函數。
三、 Thread+handler實現異步加載
public class MainActivity extends Activity {
private TextView textView = null;
private SeekBar seekBar = null;
private Handler handler;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = (TextView)findViewById(R.id.progress_text);
seekBar = (SeekBar)findViewById(R.id.progress_bar);
//2.Thread+handler實現異步加載
handler = new Handler() {
@Override
public void handleMessage(Message msg) {
Bundle data = msg.getData();
textView.setText(data.getInt("progress") + "");
seekBar.setProgress(data.getInt("progress"));
}
};
new Thread(){
public void run() {
for(int i = 1; i<= 100; i++) {
Message msg = handler.obtainMessage();
Bundle bundle = new Bundle();
bundle.putInt("progress", i);
msg.setData(bundle);
handler.sendMessage(msg);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}}.start();
}
}
四、 HandlerThread實現異步加載
public class MainActivity extends Activity {
private Handler handler1;
private TextView text;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
text = (TextView)findViewById(R.id.text);
Log.v("thread_id","UI thread: " + Thread.currentThread().getId());
HandlerThread handlerThread = new HandlerThread("handler_thread");
handlerThread.start();
handler1 = new Handler(handlerThread.getLooper()) {
@Override
public void handleMessage(Message msg) {
Log.v("thread_id","Looper thread1: " + getLooper().getThread().getId());
text.setText(msg.arg1 + "");
}
};
new Thread(){
public void run() {
Message msg = new Message();
msg.arg1 = 1;
handler1.sendMessage(msg);
};
}.start();
}
}
參考:
http://www.cnblogs.com/codingmyworld/archive/2011/09/12/2174255.html#!comments