Android線(xiàn)程主要用來(lái)操作一些耗時(shí)的任務(wù),可以在后臺運行,例如請求網(wǎng)絡(luò )、下載數據、上傳數據和加載圖片等。
無(wú)論何時(shí)啟動(dòng)App,所有的組件都會(huì )運行在一個(gè)單獨的線(xiàn)程中(默認的)叫作主線(xiàn)程。這個(gè)線(xiàn)程主要用于處理UI的操作并為視圖組件和小部件分發(fā)事件等,因此主線(xiàn)程也被稱(chēng)作UI線(xiàn)程。
如果你在UI線(xiàn)程中運行一個(gè)耗時(shí)操作,那么UI就會(huì )被鎖住,直到這個(gè)耗時(shí)操作結束。對于用戶(hù)體驗來(lái)說(shuō),這是非常糟糕的。
1 Thread線(xiàn)程的使用方式
先看一下Thread線(xiàn)程的使用方式,代碼如下:
public class MainActivity extends AppCompatActivity {private TextView tv_text;private Thread thread;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);tv_text = findViewById(R.id.tv_text);// 在UI線(xiàn)程中開(kāi)啟一個(gè)子線(xiàn)程thread = new Thread(new Runnable() {@Overridepublic void run() {//一些耗時(shí)操作//...//操作完成后可以通過(guò)Handler發(fā)送消息回調給UI線(xiàn)程Message msg = Message.obtain();msg.what = 1;msg.obj = "向UI線(xiàn)程中發(fā)送消息!";handler.sendMessage(msg);}});thread.start();}private Handler handler = new Handler() {@Overridepublic void handleMessage(Message msg) {super.handleMessage(msg);switch (msg.what) {case 1:// 把Thread線(xiàn)程發(fā)送來(lái)的消息顯示到屏幕上tv_text.setText("what=" + msg.what + ", " + msg.obj);break;}}};}
2 HandlerThread
Android提供了封裝好的Thread,叫作HandlerThread,基本使用方法如下
首先需要創(chuàng )建handlerThread類(lèi)型的線(xiàn)程對象,代碼如下:
HandlerThread myThread = new HandlerThread("MyThread");//接著(zhù)啟動(dòng)線(xiàn)程,代碼如下:myThread.start();
然后創(chuàng )建與myThread線(xiàn)程相關(guān)聯(lián)的Handler對象,代碼如下:
Handler myHandler = new Handler(myThread.getLooper()) {public void handleMessage(Message msg) {Log.i("looper", Thread.currentThread().getName());}};
3 線(xiàn)程池
線(xiàn)程池會(huì )用到ExecutorService和Executors。ExecutorService是一個(gè)接口,繼承了Executors接口,定義了一些操作線(xiàn)程池的生命周期的方法。Executors接口提供了4種線(xiàn)程池,分別是newFixedThreadPool、newCachedThreadPool、newSingleThreadExecutor和newScheduledThreadPool。
newFixedThreadPool創(chuàng )建一個(gè)可重用固定線(xiàn)程數的線(xiàn)程池,以共享的無(wú)界隊列方式來(lái)運行這些線(xiàn)程,代碼如下:
ExecutorService executorService = Executors.newFixedThreadPool(5);for (int i = 0; i < 20; i++) {Runnable syncRunnable = new Runnable() {@Overridepublic void run() {Log.e(TAG, Thread.currentThread().getName());}};executorService.execute(syncRunnable);}
運行結果:總共會(huì )創(chuàng )建5個(gè)線(xiàn)程,開(kāi)始時(shí)會(huì )執行5個(gè)線(xiàn)程,當5個(gè)線(xiàn)程都處于活動(dòng)狀態(tài)時(shí),再次提交的任務(wù)會(huì )加入隊列等待其他線(xiàn)程運行結束,當線(xiàn)程處于空閑狀態(tài)時(shí)會(huì )被下一個(gè)任務(wù)復用。
newCachedThreadPool創(chuàng )建一個(gè)可緩存線(xiàn)程池,如果線(xiàn)程池長(cháng)度超過(guò)需要,可靈活回收空閑線(xiàn)程,代碼如下:
ExecutorService executorService = Executors.newCachedThreadPool();for (int i = 0; i < 100; i++) {Runnable syncRunnable = new Runnable() {@Overridepublic void run() {Log.e(TAG, Thread.currentThread().getName());}};executorService.execute(syncRunnable);}
運行結果:可以看出緩存線(xiàn)程池大小是不定值,可以根據需要創(chuàng )建不同數量的線(xiàn)程,在使用緩存型線(xiàn)程池時(shí),先查看池中有沒(méi)有以前創(chuàng )建的線(xiàn)程。如果有,就復用;如果沒(méi)有,就創(chuàng )建新的線(xiàn)程加入池中。緩存型池通常用于執行一些生存期很短的異步型任務(wù)。
newSingleThreadExecutor創(chuàng )建一個(gè)單線(xiàn)程化的線(xiàn)程池,它只會(huì )用唯一的工作線(xiàn)程來(lái)執行任務(wù),以保證所有任務(wù)按照指定順序(FIFO、LIFO、優(yōu)先級)執行,代碼如下:
ExecutorService executorService = Executors.newSingleThreadExecutor();for (int i = 0; i < 20; i++) {Runnable syncRunnable = new Runnable() {@Overridepublic void run() {Log.e(TAG, Thread.currentThread().getName());}};executorService.execute(syncRunnable);}
運行結果:只會(huì )創(chuàng )建一個(gè)線(xiàn)程,當上一個(gè)線(xiàn)程執行完之后才會(huì )執行第二個(gè)線(xiàn)程。
newScheduledThreadPool創(chuàng )建一個(gè)定長(cháng)線(xiàn)程池,支持定時(shí)及周期性任務(wù)執行,代碼如下:
ScheduledExecutorService executorService = Executors.newScheduledThreadPool(5);for (int i = 0; i < 20; i++) {Runnable syncRunnable = new Runnable() {@Overridepublic void run() {Log.e(TAG, Thread.currentThread().getName());}};executorService.schedule(syncRunnable, 5000, TimeUnit.MILLISECONDS);}
運行結果和newFixedThreadPool線(xiàn)程池類(lèi)似,總共會(huì )創(chuàng )建5個(gè)線(xiàn)程,不同的是newScheduledThreadPool線(xiàn)程池是延遲一定時(shí)間之后才執行。
當然除了這些內置的線(xiàn)程池,也可以通過(guò)ThreadPoolExecutor定義自己的線(xiàn)程池。
4 線(xiàn)程池
由于線(xiàn)程池使用起來(lái)比較麻煩,而單獨使用Thread又不方便管理線(xiàn)程,而且可能會(huì )造成線(xiàn)程重復創(chuàng )建,開(kāi)銷(xiāo)嚴重。
為了降低開(kāi)發(fā)者的開(kāi)發(fā)難度,AsyncTask應運而生。AsyncTask是對線(xiàn)程池的一個(gè)封裝,使用其自定義的Executor來(lái)調度線(xiàn)程的執行方式(并發(fā)還是串行),并使用Handler來(lái)完成子線(xiàn)程和主線(xiàn)程數據的共享。
AsyncTask是Android提供的輕量級異步類(lèi),可以直接繼承AsyncTask,在類(lèi)中實(shí)現異步操作,并提供接口反饋當前異步執行的程度,最后給UI主線(xiàn)程反饋執行的結果。
AsyncTaskRun asyncTaskRun = new AsyncTaskRun();asyncTaskRun.execute("http://square.github.io/picasso/static/sample.png");
AsyncTaskRun 定義如下:
public class AsyncTaskRun extends AsyncTask<String, Void, Bitmap> {/*** 在doInBackground方法中進(jìn)行異步任務(wù)的處理*/@Overrideprotected Bitmap doInBackground(String... strings) {//要執行的具體任務(wù)邏輯return null;}/*** 用于異步處理前的操作*/@Overrideprotected void onPreExecute() {super.onPreExecute();}/*** 用于異步處理結束后返回結果到UI線(xiàn)程的操作*/@Overrideprotected void onPostExecute(Bitmap bitmap) {super.onPostExecute(bitmap);}/*** 用于更新任務(wù)操作進(jìn)度*/@Overrideprotected void onProgressUpdate(Void... values) {super.onProgressUpdate(values);}/*** 任務(wù)關(guān)閉回調*/@Overrideprotected void onCancelled(Bitmap bitmap) {super.onCancelled(bitmap);}}
doInBackground(Params... params):當線(xiàn)程池執行任務(wù)時(shí)調用該函數在子線(xiàn)程中處理比較耗時(shí)的操作,如執行下載任務(wù)的邏輯就寫(xiě)在這里。此函數是抽象函數,必須實(shí)現。
onPreExecute():該函數是在任務(wù)沒(méi)被線(xiàn)程池執行之前調用在UI線(xiàn)程中運行,比如在開(kāi)始下載文件操作前執行的邏輯就可以寫(xiě)在這里,也可以不用實(shí)現。
onPostExecute(Result result):該函數是任務(wù)在線(xiàn)程池中執行結束后回調給UI主線(xiàn)程的結果,如下載結果,也可以不用實(shí)現這個(gè)函數。
onProgressUpdate(Progress... values):該函數是任務(wù)在線(xiàn)程池中執行處于執行中的狀態(tài)時(shí),回調給UI主線(xiàn)程的任務(wù)進(jìn)度,比如上傳或者下載進(jìn)度。如果不需要獲取任務(wù)進(jìn)度的話(huà),也可以不用實(shí)現這個(gè)函數。
onPostExecute(Result result):該函數是任務(wù)在線(xiàn)程池中執行結束后回調給UI主線(xiàn)程的結果,如下載結果,也可以不用實(shí)現這個(gè)函數。
onCancelled(Result result)及onCancelled():表示任務(wù)關(guān)閉。
使用AsyncTask的注意事項:
· 必須在UI線(xiàn)程中創(chuàng )建AsyncTask實(shí)例;
· 只能在UI線(xiàn)程中調用AsyncTask的execute方法;
· AsyncTask被重寫(xiě)的4個(gè)方法是系統自動(dòng)調用的,不應手動(dòng)調用;
· 每個(gè)AsyncTask只能被執行(execute方法)一次,多次執行將會(huì )引發(fā)異常;
· AsyncTask的4個(gè)方法中,只有doInBackground方法是運行在其他線(xiàn)程中,其他3個(gè)方法都是運行在UI線(xiàn)程中,也就說(shuō)其他3個(gè)方法都可以進(jìn)行UI的更新操作。
完畢
聯(lián)系客服