1. 程式人生 > >Android非同步載入(UI重新整理)

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.一個任務例項只能執行一次,如果執行第二次將會丟擲異常。