androidhandler使用
A. android adapter 怎樣使用handler
主線程中創建 handler
handler的引用注入到adapter
adapter里通過handler的引用發送message
主線程中處理message
B. android中handler如何使用
Handler在Android中主要是負責發送和處理消息。它的主要用途大致是下面兩個:
1)按計劃發送消息或執行某個Runnanble;
2)從其他線程中發送來的消息放入消息隊列中,避免線程沖突(常見於更新UI線程)
學寫一下,在UI線程中,系統已經有一個Activity來處理了,你可以再起若干個Handler來處理。在實例化Handler的時候,只要有Handler的指針,任何線程也都可以sendMessage。
Handler對於Message的處理是非同步處理的。一個Looper 只有處理完一條Message才會讀取下一條,所以消息的處理是阻塞形式的(handleMessage()方法里不應該有耗時操作,可以將耗時操作放在其他線程執行,操作完後發送Message(通過sendMessges方法),然後由handleMessage()更新UI)。
根據對視頻的學習寫了一個通過Button控制項啟動進度條(類似於下載等操作)的程序,簡單介紹一下,有兩個Button控制項,一個是開始,點擊之後會顯示一個進度條以每次十分之一的進度進行(一開始是隱藏的),另一個是停止,可以中斷進度。
java代碼:
1 package zzl.handleactivity;
2
3 import android.app.Activity;
4 import android.os.Bundle;
5 import android.os.Handler;
6 import android.os.Message;
7 import android.view.Gravity;
8 import android.view.View;
9 import android.view.View.OnClickListener;
10 import android.widget.Button;
11 import android.widget.ProgressBar;
12 import android.widget.Toast;
13
14 public class Handler_01 extends Activity {
15
16 //聲明變數
17 private Button startButton=null;
18 private Button endButton=null;
19 private ProgressBar firstBar=null;
20 private Toast toast=null;
21 @Override
22 protected void onCreate(Bundle savedInstanceState) {
23 super.onCreate(savedInstanceState);
24 setContentView(R.layout.main);
25
26 //根據ID獲取對象
27 startButton =(Button)findViewById(R.id.startButton);
28 endButton=(Button)findViewById(R.id.endButton);
29 firstBar=(ProgressBar)findViewById(R.id.firstBar);
30 //給對象設置動作監聽器
31 startButton.setOnClickListener(new StartButtonListener());
32 endButton.setOnClickListener(new EndButtonListener());
33 }
34
35 class StartButtonListener implements OnClickListener{
36
37 @Override
38 public void onClick(View v) {
39 // TODO Auto-generated method stub
40 //一開始執行,加入到消息隊列,不延遲,
41 //然後馬上執行run方法
42 firstBar.setVisibility(View.VISIBLE);
43 firstBar.setMax(100);
44 handler.post(upRunnable);
45 toast=Toast.makeText(Handler_01.this, "運行開始", Toast.LENGTH_SHORT);
46 toast.setGravity(Gravity.CENTER, 0, 0);
47 toast.show();
48 }
49 }
50 class EndButtonListener implements OnClickListener{
51
52 @Override
53 public void onClick(View v) {
54 // TODO Auto-generated method stub
55 //停止
56 handler.removeCallbacks(upRunnable);
57 System.out.println("It's time to stop...");
58 }
59 }
60
61 //創建handler對象,在調用post方法
62 //非同步消息處理:將下載或者處理大數據等等單獨放到另一個線程
63 //更好的用戶體驗
64 Handler handler=new Handler(){
65
66 @Override
67 public void handleMessage(Message msg){
68 firstBar.setProgress(msg.arg1);
69 firstBar.setSecondaryProgress(msg.arg1+10);
70 //handler.post(upRunnable);
71 if(msg.arg1<=100) {
72 handler.post(upRunnable); //將要執行的線程放入到隊列當中
73 }else {
74 handler.removeCallbacks(upRunnable);
75 }
76 }
77 };
78
79 //聲明線程類:實現Runnable的介面
80 Runnable upRunnable=new Runnable() {
81
82 int i=0;
83 @Override
84 public void run() {//程序的運行狀態
85 // TODO Auto-generated method stub
86 //postDelayed方法:把線程對象加入到消息隊列中
87 // 隔2000ms(延遲)
88 System.out.println("It's time to start...");
89 i=i+10;
90 //獲取Message消息對象
91 Message msg=handler.obtainMessage();
92 //將msg對象的arg1(還有arg2)對象的值設置
93 //使用這兩個變數傳遞消息優點:系統消耗性能較少
94 msg.arg1=i;
95 try{
96 //設置當前顯示睡眠1秒
97 Thread.sleep(1000);
98 }catch(InterruptedException e){
99 e.printStackTrace();
100 }
101 //將msg對象加入到消息隊列當中
102 handler.sendMessage(msg);
103 if(i==100){//當值滿足時,將線程對象從handle中剔除
104 handler.removeCallbacks(upRunnable);
105 firstBar.setVisibility(View.GONE);
106 //臨時彈出
107
108 toast=Toast.makeText(Handler_01.this, "運行結束", Toast.LENGTH_SHORT);
109 toast.setGravity(Gravity.CENTER, 0, 0);
110 toast.show();
111 }
112 }
113 };
114 }
main.xml
1 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
2 xmlns:tools="http://schemas.android.com/tools"
3 android:orientation="vertical"
4 android:layout_width="match_parent"
5 android:layout_height="match_parent"
6 tools:context=".Handler_01" >
7
8 <ProgressBar
9 android:id="@+id/firstBar"
10 style="?android:attr/progressBarStyleHorizontal"
11 android:layout_width="200dp"
12 android:layout_height="wrap_content"
13 android:visibility="gone"/>
14
15 <Button
16 android:id="@+id/startButton"
17 android:layout_width="wrap_content"
18 android:layout_height="wrap_content"
19 android:text="@string/start" />
20
21 <Button
22 android:id="@+id/endButton"
23 android:layout_width="wrap_content"
24 android:layout_height="wrap_content"
25 android:text="@string/end" />
26
27 </LinearLayout>
總結:
1)當點擊開始或者運行結束的時候,都會通過調用Toas彈出臨時窗口,Toast.makeText(Handler_01.this, "運行結束", Toast.LENGTH_SHORT),這一句一開始總是執行出錯,原因在於必須調用它的show方法才可以顯示出來,還可以通過設置它的位置來顯示;
2)在xml中 android:text="@string/end",則需要在layout下的string文件中敲寫相應的代碼
3)原本代碼有一些瑕疵,就是沒有下面這一段代碼:
1 if(msg.arg1<=100) {
2 handler.post(upRunnable); //將要執行的線程放入到隊列當中
3 }else {
4 handler.removeCallbacks(upRunnable);
5 }
這樣就導致了upRunnable的run方法出現了死循環,這樣,雖然程序UI本身沒有問題,但是內部卻又很大的缺陷
這是因為
1 if(i==100){//當值滿足時,將線程對象從handle中剔除
2 handler.removeCallbacks(upRunnable);
3 firstBar.setVisibility(View.GONE);
4 toast=Toast.makeText(Handler_01.this, "運行結束", Toast.LENGTH_SHORT);
5 toast.setGravity(Gravity.CENTER, 0, 0);
6 toast.show();
7 }
這一段代碼看似是把upRunnable線程從線程對象隊列中移除,但是再次之前又前執行了handler.sendMessage(msg);這句代碼
從而導致下面的代碼又被執行到
1 public void handleMessage(Message msg){
2 firstBar.setProgress(msg.arg1);
3 firstBar.setSecondaryProgress(msg.arg1+10);
4
5 }
這樣肯定會使upRunnable線程重新加入到線程對象隊列中,updateThread的run方法重復執行,這就導致了死循環。所以必須加上之前的那段代碼,通過判斷來控制循環終止。並且run方法中的if(i==100)的那段代碼也是可以不用的,不過我是寫了一些其他代碼就懶得優化了,這是後話了。
4) 剛剛大家看到我們可以通過敲寫System.out.println在logcat中顯示,一開始eclipse編譯器中是沒有,這是如何顯示出來的?
大家可以再window的show view中找到logCat(deprecated)通過下圖中綠色的「+」添加出來
然後顯示內容的時候,選擇右上角「V D I W E 」的I就可以比較清晰的顯示出來了,當然你也可以選擇另外一個logCat來顯示,方法類似。
5)實際上,Handler在默認情況下,和調用它的Activity是處於同一個線程的。 上述Handler的使用示例中,雖然聲明了線程對象,但是在實際調用當中它並沒有調用線程的start()方法,而是直接調用當前線程的run()方法。
如果要實現調用另一個新的線程,只要注釋post方法,然後加上這樣兩段代碼即可: Thread t = new Thread(r); t.start();
C. Android用handler在線程間傳值
想要讓Activity收到消息,就要使用它自己的handler。
你可以在activity中聲明一個靜態的handler,在onCreat方法中初始化。
然後再其他線程直接調用。
還有就是,你應該把activity的handler賦值給Thread的
不知道為什麼網路抽了,沒有辦法追問,關於你的程序,我試調一下,消息傳遞沒有問題,吧前面的網頁訪問注釋掉直接向Activity發送消息,已經收到,請檢查你代碼的其他部分
D. Android中Handler的主要作用是什麼通俗點,初學。
Handler的使用主要是android中無法在主線程(即UI線程)中訪問網路、無法在子線程中訪問UI線程元素。
一般是在子線程中訪問網路,然後使用Handler發送message通知主線程處理UI更新操作
E. android 使用handler為什麼會造成內存泄漏
集合類泄漏
集合類如果僅僅有添加元素的方法,而沒有相應的刪除機制,導致內存被佔用。如果這個集合類是全局性的變數 (比如類中的靜態屬性,全局性的 map 等即有靜態引用或 final 一直指向它),那麼沒有相應的刪除機制,很可能導致集合所佔用的內存只增不減。比如上面的典型例子就是其中一種情況,當然實際上我們在項目中肯定不會寫這么 2B 的代碼,但稍不注意還是很容易出現這種情況,比如我們都喜歡通過 HashMap 做一些緩存之類的事,這種情況就要多留一些心眼。
單例造成的內存泄漏
由於單例的靜態特性使得其生命周期跟應用的生命周期一樣長,所以如果使用不恰當的話,很容易造成內存泄漏
匿名內部類/非靜態內部類和非同步線程
非靜態內部類創建靜態實例造成的內存泄漏
有的時候我們可能會在啟動頻繁的Activity中,為了避免重復創建相同的數據資源
Handler 造成的內存泄漏
Handler 的使用造成的內存泄漏問題應該說是最為常見了,很多時候我們為了避免 ANR 而不在主線程進行耗時操作,在處理網路任務或者封裝一些請求回調等api都藉助Handler來處理,但 Handler 不是萬能的,對於 Handler 的使用代碼編寫一不規范即有可能造成內存泄漏。另外,我們知道 Handler、Message 和 MessageQueue 都是相互關聯在一起的,萬一 Handler 發送的 Message 尚未被處理,則該 Message 及發送它的 Handler 對象將被線程 MessageQueue 一直持有。
由於 Handler 屬於 TLS(Thread Local Storage) 變數, 生命周期和 Activity 是不一致的。因此這種實現方式一般很難保證跟 View 或者 Activity 的生命周期保持一致,故很容易導致無法正確釋放。
F. android通過Handler使子線程更新UI
在Android項目中經常有碰到這樣的問題,在子線程中完成耗時操作之後要更新UI,下面就自己經歷的一些項目總結一下更新的方法。
一. 引言
首先來看一下android中消息機制:
專業術語:
Message:消息,其中包含了消息ID,消息處理對象以及處理的數據等,由MessageQueue統一列隊,終由Handler處理。
Handler:處理者,負責Message的發送及處理。使用Handler時,需要實現handleMessage(Message msg)方法來對特定的Message進行處理,例如更新UI等。
MessageQueue:消息隊列,用來存放Handler發送過來的消息,並按照FIFO規則執行。當然,存放Message並非實際意義的保存,而是將Message以鏈表的方式串聯起來的,等待Looper的抽取。
Looper:消息泵,不斷地從MessageQueue中抽取Message執行。因此,一個MessageQueue需要一個Looper。
Thread:線程,負責調度整個消息循環,即消息循環的執行場所。
二. 方法
1. 用Handler
(1)主線程中定義Handler:
Java代碼:
[java]view plain
HandlermHandler=newHandler(){
@Override
publicvoidhandleMessage(Messagemsg){
super.handleMessage(msg);
switch(msg.what){
case0:
<spanstyle="color:#009900;">//完成主界面更新,拿到數據</span>
Stringdata=(String)msg.obj;
updateWeather();
textView.setText(data);
break;
default:
break;
}
}
};
(2)子線程發消息,通知Handler完成UI更新:
java代碼:
privatevoipdateWeather(){
newThread(newRunnable(){
@Override
publicvoidrun(){
<spanstyle="color:#009900;">//耗時操作,完成之後發送消息給Handler,完成UI更新;</span>
mHandler.sendEmptyMessage(0);
<spanstyle="color:#33cc00;">//需要數據傳遞,用下面方法;</span>
Messagemsg=newMessage();
msg.obj="數據";<spanstyle="color:#33cc00;">//可以是基本類型,可以是對象,可以是List、map等;</span>
mHandler.sendMessage(msg);
}
}).start();
}
注意:Handler對象必須定義在主線程中,如果是多個類直接互相調用,就不是很方便,需要傳遞content對象或通過介面調用。
2.用Activity對象的runOnUiThread方法更新
在子線程中通過runOnUiThread()方法更新UI:
java代碼:
newThread(){
publicvoidrun(){
<spanstyle="color:#009900;">//這兒是耗時操作,完成之後更新UI;</span>
runOnUiThread(newRunnable(){
@Override
publicvoidrun(){
<spanstyle="color:#009900;">//更新UI</span>
imageView.setImageBitmap(bitmap);
}
});
}
}.start();
如果在非上下文類中,可以通過傳遞上下文實現調用:
java代碼:
Activityactivity=(Activity)imageView.getContext();
activity.runOnUiThread(newRunnable(){
@Override
publicvoidrun(){
imageView.setImageBitmap(bitmap);
}
});
注意:這種方法使用比較靈活,但如果Thread定義在其他地方,需要傳遞Activity對象。
3.
View.post(Runnable r)
java代碼:
imageView.post(newRunnable(){
@Override
publicvoidrun(){
imageView.setImageBitmap(bitmap);
}
});
這種方法更簡單,但需要傳遞要更新的View過去。
總結:UI的更新必須在主線程中完成,所以不管上述那種方法,都是將更新UI的消息發送到了主線程的消息對象,讓主線程做處理。
G. 安卓用另一個界面的handler 怎麼用
最重要的不是線程安全問題,而是android組件的監聽方法中只能訪問final的屬性,所以是無法修改的,只能把它交給handler處理。就是這個樣子
H. 能講講Android的Handler機制嗎
Android的Handler機制是通俗講為了互相發消息,一般是子線程給主線程發消息完成相應操作。
安卓中最常見的操作是子線程操作完事後得到數據想更新UI,安卓有規定不允許在子線程中刷新UI,所以Handler出現了。
使用和理解大致步驟。
創建全局Handler對象handler,然後在主線程中初始化它(一般在oncreate中),把它的handmessage裡面的方法重寫,這個方法是收到子線程發給它的消息後執行的邏輯。
在子線程中獲取數據,調用handler.sendmessage,把要發的消息放在message中。message會添加到Messagequue(消息隊列中,handler創建就帶的)。
3.對象handler被創建和初始化的時候,系統自動會啟動Handler.looper,也就是一個消息輪詢器,它不斷的去查看有沒有消息進入到Messagequue(消息隊列中),有就取出交給handler的handmessage去處理。//這段邏輯是系統自動執行,理解就行。*純手打,不騙人~~~
I. android 用handler怎麼把消息發送到指定的activity
1.在MyAPP中定義屬性handler
package jason.com;
import jason.com.MasterActivity.MyHandler;
import android.app.Application;
/**
* 自己實現Application,實現數據共享
* @author jason
*/
public class MyAPP extends Application {
// 共享變數
private MyHandler handler = null;
// set方法
public void setHandler(MyHandler handler) {
this.handler = handler;
}
// get方法
public MyHandler getHandler() {
return handler;
}
}
2、在主activity 中給MyAPP的屬性handler賦值
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mAPP = (MyAPP) getApplication();
handler = new MyHandler();
tv = (TextView) findViewById(R.id.tv);
btn_to = (Button) findViewById(R.id.btn_to);
// 設置監聽器
btn_to.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// 設置共享變數
mAPP.setHandler(handler);
// 啟動另一個Activity
Intent intent = new Intent(MasterActivity.this,
ToChangeViewActivity.class);
startActivity(intent);
}
});
}
3、在另一個activity中獲取MyAPP中handler進行傳值
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.show);
mAPP = (MyAPP) getApplication();
// 獲得該共享變數實例
mHandler = mAPP.getHandler();
findViewById(R.id.btn_chang).setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// 發送消息
mHandler.sendEmptyMessage(CHANGED);
ToChangeViewActivity.this.finish();
}
});
}
J. Android的handler機制的原理
Android的handler機制的原理分為非同步通信准備,消息發送,消息循環,消息處理。
1、非同步通信准備
在主線程中創建處理器對象(Looper)、消息隊列對象(Message Queue)和Handler對象。
2、消息入隊
工作線程通過Handler發送消息(Message) 到消息隊列(Message Queue)中。
3、消息循環
消息出隊: Looper循環取出消息隊列(Message Queue) 中的的消息(Message)。
消息分發: Looper將取出的消息 (Message) 發送給創建該消息的處理者(Handler)。
4、消息處理
處理者(Handler) 接收處理器(Looper) 發送過來的消息(Message),根據消息(Message) 進行U操作。
handler的作用
handler是android線程之間的消息機制,主要的作用是將一個任務切換到指定的線程中去執行,(准確的說是切換到構成handler的looper所在的線程中去出處理)android系統中的一個例子就是主線程中的所有操作都是通過主線程中的handler去處理的。
Handler的運行需要底層的 messagequeue和 looper做支撐。