編輯:關於Android編程
語法和java多線程類似,用法基本相同
一。基本用法:
方法一
class t extends Thread{
@override
public void run(){}
}
new t().start
方法二
class t implements Runnable{
@override
public void run(){}}
new Thread(new t).start();
或者
new Thread(new Runnable(){
@override
public void run(){}}).start();
在Android當中,通常將線程分為兩種,一種叫做Main Thread,除了Main Thread之外的線程都可稱為Worker Thread。
當一個應用程序運行的時候,Android操作系統就會給該應用程序啟動一個線程,這個線程就是我們的Main Thread,這個線程非常的重要,它主要用來加載我們的UI界面,完成系統和我們用戶之間的交互,並將交互後的結果又展示給我們用戶,所以Main Thread又被稱為UI Thread。
Android系統默認不會給我們的應用程序組件創建一個額外的線程,所有的這些組件默認都是在同一個線程中運行。然而,某些時候當我們的應用程序需要完成一個耗時的操作的時候,例如訪問網絡或者是對數據庫進行查詢時,此時我們的UI Thread就會被阻塞。例如,當我們點擊一個Button,然後希望其從網絡中獲取一些數據,如果此操作在UI Thread當中完成的話,當我們點擊Button的時候,UI線程就會處於阻塞的狀態,此時,我們的系統不會調度任何其它的事件,更糟糕的是,當我們的整個現場如果阻塞時間超過5秒鐘(官方是這樣說的),這個時候就會出現 ANR (Application Not Responding)的現象,此時,應用程序會彈出一個框,讓用戶選擇是否退出該程序。對於Android開發來說,出現ANR的現象是絕對不能被允許的。
另外,由於我們的Android UI控件是線程不安全的,所以我們不能在UI Thread之外的線程當中對我們的UI控件進行操作。因此在Android的多線程編程當中,我們有兩條非常重要的原則必須要遵守:
絕對不能在UI Thread當中進行耗時的操作,不能阻塞我們的UI Thread
不能在UI Thread之外的線程當中操縱我們的UI元素
android 異步處理機制;
AsyncTask:
AsyncTask:異步任務,從字面上來說,就是在我們的UI主線程運行的時候,異步的完成一些操作。AsyncTask允許我們的執行一個異步的任務在後台。我們可以將耗時的操作放在異步任務當中來執行,並隨時將任務執行的結果返回給我們的UI線程來更新我們的UI控件。通過AsyncTask我們可以輕松的解決多線程之間的通信問題。
怎麼來理解AsyncTask呢?通俗一點來說,AsyncTask就相當於Android給我們提供了一個多線程編程的一個框架,其介於Thread和Handler之間,我們如果要定義一個AsyncTask,就需要定義一個類來繼承AsyncTask這個抽象類,並實現其唯一的一個 doInBackgroud 抽象方法。要掌握AsyncTask,我們就必須要一個概念,總結起來就是: 3個泛型,4個步驟。
3個泛型指的是什麼呢?我們來看看AsyncTask這個抽象類的定義,當我們定義一個類來繼承AsyncTask這個類的時候,我們需要為其指定3個泛型參數:
AsyncTask
((Button) findViewById(R.id.load_AsyncTask)).setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View view) {
data = null;
data = new ArrayList();
adapter = null;
//顯示ProgressDialog放到AsyncTask.onPreExecute()裡
//showDialog(PROGRESS_DIALOG);
new ProgressTask().execute(data);
}
});
private class ProgressTask extends AsyncTask, Void, Integer> {
/* 該方法將在執行實際的後台操作前被UI thread調用。可以在該方法中做一些准備工作,如在界面上顯示一個進度條。*/
@Override
protected void onPreExecute() {
// 先顯示ProgressDialog
showDialog(PROGRESS_DIALOG);
}
/* 執行那些很耗時的後台計算工作。可以調用publishProgress方法來更新實時的任務進度。 */
@Override
protected Integer doInBackground(ArrayList... datas) {
ArrayList data = datas[0];
for (int i=0; i<8; i++) {
data.add("ListItem");
}
return STATE_FINISH;
}
/* 在doInBackground 執行完成後,onPostExecute 方法將被UI thread調用,
* 後台的計算結果將通過該方法傳遞到UI thread.
*/
@Override
protected void onPostExecute(Integer result) {
int state = result.intValue();
switch(state){
case STATE_FINISH:
dismissDialog(PROGRESS_DIALOG);
Toast.makeText(getApplicationContext(),
"加載完成!",
Toast.LENGTH_LONG)
.show();
adapter = new ArrayAdapter(getApplicationContext(),
android.R.layout.simple_list_item_1,
data );
setListAdapter(adapter);
break;
case STATE_ERROR:
dismissDialog(PROGRESS_DIALOG);
Toast.makeText(getApplicationContext(),
"處理過程發生錯誤!",
Toast.LENGTH_LONG)
.show();
adapter = new ArrayAdapter(getApplicationContext(),
android.R.layout.simple_list_item_1,
data );
setListAdapter(adapter);
break;
default:
}
}
Handler:
線程在代碼是使用標准的java Thread對象來建立,那麼在Android系統中提供了一系列方便的類來管理線程——Looper用來在一個線程中執行消息循環,Handler用來處理消息,HandlerThread創建帶有消息循環的線程。具體可以看下面的詳細介紹。
當一個程序第一次啟動時,Android會同時啟動一個對應的主線程(Main Thread),主線程主要負責處理與UI相關的事件,如用戶的按鍵事件,用戶接觸屏幕的事件以及屏幕繪圖事件,並把相關的事件分發到對應的組件進行處理。所以主線程通常又被叫做UI線程。
在開發Android應用時必須遵守單線程模型的原則: Android UI操作並不是線程安全的並且這些操作必須在UI線程中執行。
2.1 子線程更新UI Android的UI是單線程(Single-threaded)的。
為了避免拖住GUI,一些較費時的對象應該交給獨立的線程去執行。如果幕後的線程來執行UI對象,Android就會發出錯誤訊息 CalledFromWrongThreadException。以後遇到這樣的異常拋出時就要知道怎麼回事了!
2.2 Message Queue
在單線程模型下,為了解決類似的問題,Android設計了一個Message Queue(消息隊列), 線程間可以通過該Message Queue並結合Handler和Looper組件進行信息交換。下面將對它們進行分別介紹:
2.2.1. Message 消息
理解為線程間交流的信息,處理數據後台線程需要更新UI,則發送Message內含一些數據給UI線程。
2.2.2. Handler 處理者
是Message的主要處理者,負責Message的發送,Message內容的執行處理。後台線程就是通過傳進來的Handler對象引用來sendMessage(Message)。而使用Handler,需要implement 該類的 handleMessage(Message) 方法,它是處理這些Message的操作內容,例如Update UI。通常需要子類化Handler來實現handleMessage方法。
2.2.3. Message Queue 消息隊列
用來存放通過Handler發布的消息,按照先進先出執行。 每個message queue都會有一個對應的Handler。Handler會向message queue通過兩種方法發送消息:sendMessage或post。這兩種消息都會插在message queue隊尾並按先進先出執行。但通過這兩種方法發送的消息執行的方式略有不同:通過sendMessage發送的是一個message對象,會被Handler的handleMessage()函數處理;而通過post方法發送的是一個runnable對象,則會自己執行。
2.2.4. Looper Looper是每條線程裡的Message Queue的管家。
Android沒有Global的Message Queue,而Android會自動替主線程(UI線程)建立Message Queue,但在子線程裡並沒有建立Message Queue。所以調用Looper.getMainLooper()得到的主線程的Looper不為NULL,但調用Looper.myLooper()得到當前線程的Looper就有可能為NULL。
對於子線程使用Looper,API Doc提供了正確的使用方法:
package com.test;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
class LooperThread extends Thread {
public Handler mHandler;
public void run() {
Looper.prepare(); //創建本線程的Looper並創建一個MessageQueue
mHandler = new Handler() {
public void handleMessage(Message msg) {
// process incoming messages here
}
};
Looper.loop(); //開始運行Looper,監聽Message Queue
}
}
這個Message機制的大概流程:
1. 在Looper.loop()方法運行開始後,循環地按照接收順序取出Message Queue裡面的非NULL的Message。
2. 一開始Message Queue裡面的Message都是NULL的。當Handler.sendMessage(Message)到Message Queue,該函數裡面設置了那個Message對象的target屬性是當前的Handler對象。隨後Looper取出了那個Message,則調用該Message的target指向的Hander的dispatchMessage函數對Message進行處理。
在dispatchMessage方法裡,如何處理Message則由用戶指定,三個判斷,優先級從高到低:
1) Message裡面的Callback,一個實現了Runnable接口的對象,其中run函數做處理工作;
2) Handler裡面的mCallback指向的一個實現了Callback接口的對象,由其handleMessage進行處理;
3) 處理消息Handler對象對應的類繼承並實現了其中handleMessage函數,通過這個實現的handleMessage函數處理消息。
由此可見,我們實現的handleMessage方法是優先級最低的!
3. Handler處理完該Message (update UI) 後,Looper則設置該Message為NULL,以便回收!
首先上效果圖 第一張圖是進入該界面的效果,頂部是一個viewpager,下面每個塊都是自定義的view HomeButton,第二張圖是點擊右邊第一個方塊的效果,點擊時方
沒有辦法,米公設計的一個UI是stickyheaderlist(頭部停留)和分頁加載數據功能的整合,筆者原以為是米工自己拍著腦袋想出來的,還想進一步討論一下,後來才發現支
前言 用過微信的都知道,微信對話列表滑動刪除效果是很不錯的,這個效果我們也可以有。思路其實很簡單,弄個ListView,然後裡面的每個item做成一個可以滑動的
大家可能在做app的時候,或多或少需要使用聯系人,而根據google提供的api,你需要編寫大量的代碼,例如首先需要查詢數據庫,涉及到數據庫表和字段以及對應的SQL語句。