編輯:Android開發實例
大家都知道,在PC上的應用程序當需要進行一些復雜的數據操作,但不需要界面UI的時候,我們會為應用程序專門寫一個線程去執行這些復雜的數據操作。通過線程,可以執行例如:數據處理、數據下載等比較耗時的操作,同時對用戶的界面不會產生影響。在Android應用程序開發中,同樣會遇到這樣的問題。當我們需要訪問網絡,從網上下載數據並顯示在我們的UI上時,就會啟動後台線程去下載數據,下載線程執行完成後將結果返回給主用戶界面線程。
對於線程的控制,我們將介紹一個Handler類,使用該類可以對運行在不同線程中的多個任務進行排隊,並使用Message和Runnable對象安排這些任務。在javadoc中,對Handler是這樣解釋的:Handler可以發送和處理消息對象或Runnable對象,這些消息對象和Runnable對象與一個線程相關聯。每個Handler的實例都關聯了一個線程和線程的消息隊列。當創建了一個Handler對象時,一個線程或消息隊列同時也被創建,該Handler對象將發送和處理這些消息或Runnable對象。
下面有幾種對Handler對象的構造方法需要了解一下:
a、如果new一個無參構造函數的Handler對象,那麼這個Handler將自動與當前運行線程相關聯,也就是說這個Handler將與當前運行的線程使用同一個消息隊列,並且可以處理該隊列中的消息。
private Handler handler = new Handler();
我們做這樣一個實驗,在主用戶界面中創建一個帶有無參構造函數的Handler對象,該Handler對象向消息隊列推送一個Runnable對象,在Runnable對象的run函數中打印當前線程Id,我們比較主用戶界面線程ID和Runnable線程ID是否相同。具體代碼如下:
HandlerTest01
public class HandlerTest01 extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
System.out.println("Activity ---> " + Thread.currentThread().getId());
handler.post(r);
}
private Handler handler = new Handler();
private Runnable r = new Runnable() {
@Override
public void run() {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("Runnalbe ---> " + Thread.currentThread().getId());
}
};
}
通過這個例子的輸出可以發現,Runnable對象和主用戶界面線程的ID是相同。在這個例子中,我們直接利用handler對象post了一個runnable對象,相當於直接調用了Runnable對象的run函數,也就說沒有經過start函數調用run(),那麼就不會創建一個新線程,而是在原有線程內部直接調用run()方法,因此輸出的線程Id是相同的。
b、如果new一個帶參構造函數的Handler對象,那麼這個Handler對象將與參數所表示的Looper相關聯。注意:此時線程類應該是一個特殊類HandlerThread類,一個Looper類的Thread類,它繼承自Thread類。
HandlerThread handlerthread = new HandlerThread("MyThread");handlerthread.start();
private MyHandler handler = new MyHandler(handlerthread.getLooper());
class MyHandler extends Handler {
public MyHandler() {
}
public MyHandler(Looper looper) {
super(looper);
}
}
下面這個例子,將介紹如何開啟一個新的線程,並通過Handler處理消息。
HandlerTest02.java
public class HandlerTest02 extends Activity {
private MyHandler myhandler = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
this.setContentView(R.layout.main);
System.out.println("Activity ---> " + Thread.currentThread().getId());
// 生成一個HandlerThread對象,使用Looper來處理消息隊列
HandlerThread thread = new HandlerThread("MyThread");
// 必須啟動這個線程
thread.start();
// 將一個線程綁定到Handler對象上,則該Handler對象就可以處理線程的消息隊列
myhandler = new MyHandler(thread.getLooper());
// 從Handler中獲取消息對象
Message msg = myhandler.obtainMessage();
// 將msg對象發送給目標對象Handler
msg.sendToTarget();
}
class MyHandler extends Handler {
public MyHandler() {
}
// 帶有參數的構造函數
public MyHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
System.out.println("MyHandler ---> " + Thread.currentThread().getId());
}
}
}
根據這個例子返回的結果,可以看出,新線程Id與主用戶界面的線程Id不同。由於我們調用了thread.start()方法,真正的創建了一個新線程,與原來的線程處於不同的線程上下文中,因此打印輸出的線程Id是不同的。
c、如果需要Handler對象去處理消息,那麼就要重載Handler類的handleMessage函數。
private Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
// TODO : Handle the msg
// Usually we update UI here.
}
}
注意到注釋部分,我們通常在handleMessage中處理更新UI界面的操作。
前面介紹了Handler類的基本使用,但是還是沒有涉及到Thread類。要想實現在後台重新開啟一個新的線程,通過該線程執行一些費時的操作,我們也使用Thread類來完成這個功能。下面我們先給出一個使用Thread類的例子程序。
這個程序執行的結果如下。新線程在創建對象時,傳入了Runnable類的一個對象,在Runnable對象中重載了run()方法去執行耗時的操作;新的線程實例執行了start方法,開啟了一個新的線程執行Runnable的run方法。
上面這些就是我現在接觸到執行線程的方法,在線程中,可以完成我們所需要的操作(比如:下載,處理數據,檢測網絡狀態等),使其與UI界面分離,那麼UI界面不會因為耗時操作導致界面被阻塞。
在《解密Google Android》一書中,發現了這樣一個啟動線程的模型。利用該模型,我們可以把一些耗時的操作放到doStuff方法中去執行,同時在updateUIHere方法中進行更新UI界面的操作,就可以完成一個線程所需要的功能。其他的說明寫在注釋部分了。
Handler myHandler = new Handler() {
public void handleMessage(Message msg) {
updateUIHere();
}
}
new Thread() {
public void run() {
doStuff(); // 執行耗時操作
Message msg = myHandler.obtainMessage();
Bundle b = new Bundle();
b.putString("key", "value");
m.setData(b); // 向消息中添加數據
myHandler.sendMessage(m); // 向Handler發送消息,更新UI
}
}.start();
ThreadTest.java
public class ThreadTest extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
this.setContentView(R.layout.main);
System.out.println("Activity ---> " + Thread.currentThread().getId());
Thread thread = new Thread(r);
thread.start();
try {
Thread.currentThread().sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
thread.stop();
}
Runnable r = new Runnable() {
@Override
public void run() {
System.out.println("Runnable ---> " + Thread.currentThread().getId());
}
};
}
登錄應用程序的屏幕,詢問憑據登錄到一些特定的應用。可能需要登錄到Facebook,微博等本章介紹了,如何創建一個登錄界面,以及如何管理安全問題和錯誤嘗試。首先,必須定義兩
本文實例講述了Android中ListView下拉刷新的實現方法。分享給大家供大家參考,具體如下: ListView中的下拉刷新是非常常見的,也是經常使用的,看
Android應用可以包含,多個Activity,某個Activity可以啟動另外的Activit
在android中,LayoutInflater有點類似於Activity的findViewById(id),不同的是LayoutInflater是用來找layo