Android非同步載入(UI重新整理)
指切正題,為何要選擇非同步載入?
由於UI執行緒(也可叫主縣城執行緒)負責處理使用者輸入事件(TP事件,顯示事件等),直接與使用者互動,如果UI執行緒阻塞,直接會影響使用者的體驗效果,嚴重的會報ANR錯誤。所以我們需要把耗時操作移出主執行緒,在子執行緒中進行處理。
下面羅列幾種實現非同步載入的方式。
傳統JAVA方法實現非同步
1.繼承Thread類
程式碼如下
package UseThred; public class TestThread extends Thread{ public String behavior; public TestThread(String behavior){ this.behavior = behavior; } @Override public void run() { System.out.println(behavior); } }
實現如下:
package UseThred;
public class UseThread {
public UseThread() {
// TODO Auto-generated constructor stub
}
public static void main(String[] args) {
TestThread thread1 = new TestThread("行為1");
TestThread thread2 = new TestThread("行為2");
}
}
自定義一個類繼承Thread類,在run()裡面執行耗時操作,start()執行
2.實現Runnble介面
class TestRunnable implements Runnable { private String behavior; public TestRunnable(String behavior) { this.behavior = behavior; } @Override public void run() { System.out.println(behavior); } } public class UseThread { public UseThread() { // TODO Auto-generated constructor stub } public static void main(String[] args) { TestRunnable runnable1 = new TestRunnable("runnable1"); TestRunnable runnable2 = new TestRunnable("runnable2"); TestRunnable runnable3 = new TestRunnable("runnable3"); Thread t1 = new Thread(runnable1); Thread t2 = new Thread(runnable1); Thread t3 = new Thread(runnable1); t1.start(); t2.start(); t3.start(); } }
這種方式感覺繁瑣一點,自定義類實現Runnable介面,然後加入new Thread,最後start(). 但是java中是單繼承方式,需要實際的類進行操作,所以使用實現介面的方式較多一點。
當然我一般選擇偷懶:
new Thread(new Runnable() {
@Override
public void run() {
//耗時操作執行
}
}).start();
Android非同步
作為一個Android開發,怎麼能忘了Android獨有的非同步載入方式呢?因為有時候我們需要在子執行緒能更新UI,這些方式就比較繁瑣了。
先說一下Android使用傳統Java執行緒方法非同步並更新UI的方法
1.使用runOnUiThread
new Thread() {
public void run() {
// 1.執行耗時操作
runOnUiThread(new Runnable(){
@Override
public void run() {
// 2.更新UI
button_show.setText("refresh");
}
});
}
}.start();
ps: runOnUiThread是Activity的方法,注意引用上下文物件。
2.post或者posrDelay
new Thread() {
public void run() {
// 1.執行耗時操作 postDelay/post
button.post(new Runnable() {
@Override
public void run() {
// 2.UI
button_show.setText("post");
}
});
}
}.start();
3.Handler + Message或者Handler + Thread + Message
簡單說就是主執行緒寫一個Handler,子執行緒中通過handler傳遞訊息。程式碼如下。
Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case 0:
//拿到資料 ,更新UI
String data = (String)msg.obj;
button.setText(data);
break;
default:
break;
}
}
};
private void setUI() {
new Thread(new Runnable(){
@Override
public void run() {
// 1.進行耗時操作
// 2.傳遞資料
mHandler.sendEmptyMessage(0);
Message msg =new Message();
msg.obj = "資料";//傳送Object;
mHandler.sendMessage(msg);
}
}).start();
}
4.AsyncTask
這是最普遍的用法之一了,無聊的面試官總會問你這個非同步載入怎麼實現,其實我想回答他,百度,然後CV大法進行面向搜尋引擎開發。附上程式碼吧,也省的我以後百度了。
private class MyTask extends AsyncTask<String, Integer, String> {
//執行後臺任務前做一些UI操作
@Override
protected void onPreExecute() {
button.setText("loading...");
}
//執行後臺任務(耗時操作),不可在此方法內修改UI
@Override
protected String doInBackground(String... params) {
return null;
}
//更新進度資訊
@Override
protected void onProgressUpdate(Integer... progresses) {
progressBar.setProgress(progresses[0]);
button.setText("loading..." + progresses[0] + "%");
}
//執行完後臺任務後更新UI
@Override
protected void onPostExecute(String result) {
button.setText(result);
}
//取消執行中的任務時更改UI
@Override
protected void onCancelled() {
button.setText("cancelled");
}
}
下面說幾個關於AnsysTask老生長談的幾個注意點:
1.必須在UI執行緒中建立非同步任務的例項。
2.必須在UI執行緒中呼叫execute(Params... params)方法。
3.不要手動呼叫其中繼承的方法。
4.不能在doInBackground(Params... params)中更改UI元件的資訊。
5.一個任務例項只能執行一次,如果執行第二次將會丟擲異常。