編輯:關於Android編程
當我們在處理下載或是其他需要長時間執行的任務時,如果直接把處理函數放在Activity的OnCreate或是OnStart中,會導致執行過程中整個Activity無響應,如果時間過長,程序就會掛掉。Handler就是把這些功能放到一個當初的線程裡執行,與Activity互不影響。
一、Handler的定義:
Handler主要接收子線程發送的數據, 並用此數據配合主線程更新UI,用來跟UI主線程交互用。比如可以用handler發送一個message,然後在handler的線程中來接收、處理該消息,以避免直接在UI主線程中處理事務導致影響UI主線程的其他處理工作,Android提供了Handler作為主線程和子線程的紐帶;也可以將handler對象傳給其他進程,以便在其他進程中通過handler給你發送事件;還可以通過handler的延時發送message,可以延時處理一些事務的處理。
解釋:當應用程序啟動時,Android首先會開啟一個主線程 (也就是UI線程) , 主線程為管理界面中的UI控件,進行事件分發。比如說,你要是點擊一個button,android會分發事件到button上,來影響你的操作。如果此時需要一個耗時的操作,例如:聯網讀取數據,或者讀取本地較大的一個文件的時候,你不能把這些操作放在主線程中,如果你放在主線程中的話,界面會出現假死現象,如果5秒鐘還沒有完成的話,會收到Android系統的一個錯誤提示"強制關閉". 這個時候我們需要把這些耗時的操作,放在一個子線程中,因為子線程涉及到UI更新,但是當子線程中有涉及到操作UI的操作時,就會對主線程產生危險,也就是說,更新UI只能在主線程中更新,在子線程中操作是危險的. 這個時候,Handler就出現了,來解決這個復雜的問題,由於Handler運行在主線程中(UI線程中),它與子線程可以通過Message對象來傳遞數據,這個時候,Handler就承擔著接受子線程傳過來的(子線程用sedMessage()方法傳遞)Message對象,(裡面包含數據), 把這些消息放入主線程隊列中,配合主線程進行更新UI。
二、Handler一些特點
handler可以分發Message對象和Runnable對象到主線程中, 每個Handler實例,都會綁定到創建他的線程中(一般是位於主線程), 也就是說Handler對象初始化後,就默認與對它初始化的進程的消息隊列綁定,因此可以利用Handler所包含的消息隊列,制定一些操作的順序。
它有兩個作用: (1): 安排消息或Runnable 在某個主線程中某個地方執行, (2)安排一個動作在不同的線程中執行
Handler中分發消息的一些方法
post(Runnable)
postAtTime(Runnable,long)
postDelayed(Runnablelong)
post類方法允許你排列一個Runnable對象到主線程隊列中
sendEmptyMessage(int)
sendMessage(Message)
sendMessageAtTime(Message,long)
sendMessageDelayed(Message,long)
sendMessage類方法, 允許你安排一個帶數據的Message對象到隊列中
三、handler的簡單工作原理圖
四、應用實例:<喎?/kf/ware/vc/" target="_blank" class="keylink">vcD4KPHA+ICAgMaOstKu13U1lc3NhZ2Who9PD09q908rc19PP37PMt6LLzbXEyv2+3SwgsqLTw7TLyv2+3cXkus/W98/fs8y4/NDCVUmhozwvcD4KPHA+ICAgICAgICAgINTaQW5kcm9pZNbQo6y21NPaVUm1xLLZ1/fNqLOj0OjSqrfF1NrW98/fs8zW0L340NCy2df3oaPI57n71NrX08/fs8zW0NPQudjT2lVJtcSy2df3o6zEx8O0vs3Q6NKqsNHK/b7dz/vPotf3zqrSu7j2TWVzc2FnZbbUz/O3osvNtb3P+8+ittPB0NbQo6zIu7rzo6zTw0hhbmRsZXLW0LXEaGFuZGxlck1lc3NnZbe9t6i0psDttKu5/cC0tcTK/b7d0MXPoqOssqKy2df3VUmho8Dgc2VuZE1lc3NhZ2UoTWVzc2FnZW1zZym3vbeoyrXP1reiy83P+8+itcSy2df3oaMg1Nqz9cq8u69IYW5kbGVyttTP88qx1tjQtLXEaGFuZGxlTWVzc2FnZbe9t6jAtL3TytVNZXNzZ2FlsqK9+NDQz+C52LLZ1/ehozwvcD4KPHA+ICAyo6y0q7XdUnVubmFibGW21M/zoaPTw9Pazai5/UhhbmRsZXKw87aotcTP+8+ittPB0KOssLLFxbK7zayy2df3tcTWtNDQy7PQ8qGjPC9wPgo8cD5IYW5kbGVyttTP89TavfjQ0LP1yry7r7XEyrG68qOsu+HErMjPtcTX1LavsPO2qM/7z6K208HQoaPA+9PDwOBwb3N0t723qKOsv8nS1L2rUnVubmFibGW21M/zt6LLzbW9z/vPorbTwdDW0KOssLTV1bbTwdC1xLv61sawtMuz0PLWtNDQsrvNrLXEUnVubmFibGW21M/z1tC1xHJ1bre9t6ihozwvcD4KPHA+we3N4qOsQW5kcm9pZLXEQ1BVt9bF5LXE1+7QobWl1KrKx8/fs8yjrEhhbmRsZXLSu7DjysfU2sSzuPbP37PMwO+0tL2otcSjrNLytvhIYW5kbGVyus1UaHJlYWS+zcrHz+C7pbDztqi1xKOs0rvSu7bU06aho7b4UnVubmFibGXKx9K7uPa907/ao6xUaHJlYWTKx1J1bm5hYmxltcTX08DgoaPL+dLUy7WjrMv7wam2vMvj0ru49r34s8yhozwvcD4KPHA+PGJyPgo8L3A+CjxwPjxicj4KPC9wPgo8cD5tYXJzX2FuZHJvaWRzytPGtdbQtcS0+sLrPC9wPgo8cD48cHJlIGNsYXNzPQ=="brush:java;">package mars.handler;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
public class HandlerActivity extends Activity {
/** Called when the activity is first created. */
//聲明兩個按鈕控件
private Button startButton = null;
private Button endButton = null;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
//根據控件的ID得到代表控件的對象,並未這兩個按鈕設置相應的監聽器
startButton = (Button)findViewById(R.id.startButton);
startButton.setOnClickListener(new StartButtonListener());
endButton = (Button)findViewById(R.id.endButton);
endButton.setOnClickListener(new EndButtonListener());
}
class StartButtonListener implements OnClickListener{
@Override
public void onClick(View v) {
//調用Handler的post方法,將要執行的線程對象添加到隊列當中
handler.post(updateThread);
}
}
class EndButtonListener implements OnClickListener{
@Override
public void onClick(View v) {
handler.removeCallbacks(updateThread);
}
}
//創建一個Handler對象
Handler handler = new Handler();
//將要執行的操作寫在線程對象的run方法當中
Runnable updateThread = new Runnable(){
@Override
public void run() {
System.out.println("UpdateThread");
//在run方法內部,執行postDelayed或者是post方法
handler.postDelayed(updateThread, 3000);
}
};
}
程序的運行結果就是每隔3秒鐘,就會在控制台打印一行UpdateTread。這是因為實現了Runnable接口的updateThread對象進入了空的消息隊列即被立即執行run方法,而在run方法的內部,又在3000ms之後將其再次發送進入消息隊列中。
3.Handler和多線程
post方法雖然發送的是一個實現了Runnable接口的類對象,但是它並非創建了一個新線程,而是執行了該對象中的run方法。也就是說,整個run中的操作和主線程處於同一個線程。
這樣對於那些簡單的操作,似乎並不會影響。但是對於耗時較長的操作,就會出現“假死”。為了解決這個問題,就需要使得handler綁定到一個新開啟線程的消息隊列上,在這個處於另外線程的上的消息隊列中處理傳過來的Runnable對象和消息
package mars.handler; import android.app.Activity; import android.os.Bundle; import android.os.Handler; import android.os.HandlerThread; import android.os.Looper; import android.os.Message; public class HandlerTest2 extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { // TODO Auto-generated method stub super.onCreate(savedInstanceState); setContentView(R.layout.main); //打印了當前線程的ID System.out.println("Activity-->" + Thread.currentThread().getId()); //生成一個HandlerThread對象,實現了使用Looper來處理消息隊列的功能,這個類由Android應用程序框架提供 HandlerThread handlerThread = new HandlerThread("handler_thread"); //在使用HandlerThread的getLooper()方法之前,必須先調用該類的start(); handlerThread.start(); //將由HandlerThread獲取的Looper傳遞給Handler對象,即由處於另外線程的Looper代替handler初始化時默認綁定的消息隊列來處理消息。 // HandlerThread顧名思義就是可以處理消息循環的線程,它是一個擁有Looper的線程可以處理消息循環; //其實與其說Handler和一個線程綁定,倒不如說Handler和Looper是一一對應的。 MyHandler myHandler = new MyHandler(handlerThread.getLooper()); Message msg = myHandler.obtainMessage(); //將msg發送到目標對象,所謂的目標對象,就是生成該msg對象的handler對象 Bundle b = new Bundle(); b.putInt("age", 20); b.putString("name", "Jhon"); msg.setData(b); msg.sendToTarget(); } class MyHandler extends Handler{ public MyHandler(){ } public MyHandler(Looper looper){ super(looper); } @Override public void handleMessage(Message msg) { Bundle b = msg.getData(); int age = b.getInt("age"); String name = b.getString("name"); System.out.println("age is " + age + ", name is" + name); System.out.println("Handler--->" + Thread.currentThread().getId()); System.out.println("handlerMessage"); } } }
這樣,當使用sendMessage方法傳遞消息或者使用post方法傳遞Runnable對象時,就會把它們傳遞到與handler對象綁定的處於另外一個線程的消息隊列中,它們將在另外的消息隊列中被處理。而主線程還會在發送操作完成時候繼續進行,不會影響當前的操作。
這裡需要注意,這裡用到的多線程並非由Runnable對象開啟的,而是ThreadHandler對象開啟的。Runnable對象只是作為一個封裝了操作的對象被傳遞,並未產生新線程。
在UI線程(主線程)中:
mHandler=newHandler();
mHandler.post(newRunnable(){
void run(){
//執行代碼..
}
});
這個線程其實是在UI線程之內運行的,並沒有新建線程。
常見的新建線程的方法是:
Thread thread = newThread();
thread.start();
HandlerThreadthread = new HandlerThread("string");
thread.start();
微信公眾平台發布消息,關注你的人都是可以看到的。用過微信的都知道的,每次開啟微信就有很多公眾用戶發布的信息。那麼這些消息是怎麼發布的呢?微信公眾平台怎麼用?
PopupMenu是Android中一個十分輕量級的組件。與PopupWindow相比,PopupMenu的可自定義的能力較小,但使用更加方便。 先上效果圖: 本
如果做一個如下圖的Dialog,首先要定義樣式: stateUnchanged|adjustResize @null @null
當我們寫商城類的項目的時候,一般都會有加入購物車的功能,加入購物車的時候會有一些拋物線動畫,具體代碼如下:實現效果如圖:思路: 確定動畫的起終點 在起終點之間使用二次