導航:首頁 > 操作系統 > androidhandler下載

androidhandler下載

發布時間:2022-05-11 19:07:10

android handler是不是唯一的

前段時間在工作的時候碰見一個問題,就是要待機時在設定的時間內執行操作,開始並沒有意識到問題的嚴重,後來嘗試很多辦法沒有成功,最後也是在網上找到解決辦法,在此稍作總結,希望能對大家有所幫助,不足之處還望大家指正。
1Android中的handler、timer、thread、在待機時都會停止運行,所設定的時間會在待機結束後繼續計算。所以如果想在Android待機時運行某些操作,使用以上幾種方法是不可行的。
2Android中有一個Alarmmanager對象,可以使用該對象執行待機時的操作。具體設置的方法如下:
2.1設置鬧鈴的類型
AlarmManager.RTC,硬體鬧鍾,不喚醒手機(也可能是其它設備)休眠;當手機休眠時不發射鬧鍾。
AlarmManager.RTC_WAKEUP,硬體鬧鍾,當鬧鍾發躰時喚醒手機休眠;
AlarmManager.ELAPSED_REALTIME,真實時間流逝鬧鍾,不喚醒手機休眠;當手機休眠時不發射鬧鍾。
AlarmManager.ELAPSED_REALTIME_WAKEUP,真實時間流逝鬧鍾,當鬧鍾發躰時喚醒手機休眠;
AlarmManager.POWER_OFF_WAKEUP:能喚醒系統,他是一種關機鬧鈴,就是說設備在關機狀態下也可以喚醒系統,所以我們把它稱為關機鬧鈴。
RTC鬧鍾和ELAPSED_REALTIME最大的差別就是前者可以通過修改手機時間觸發鬧鍾事件,後者要通過真實時間的流逝,即使在休眠狀態,時間也會被計算。
2.2設置鬧鈴的開始時間
如果使用ELAPSED_REALTIME或者ELAPSED_REALTIME_WAKEUP類型應該調用SystemClock.elapsedRealtime()獲取相對時間在加上你設定的延遲時間
如果使用RTC或者RTC_WAKEUP類型應該調用System.currentTimeMillis()獲取從1970.1.1號以來的時間在加上你設定的延遲時間
2.3pendingintent
一個PendingIntent對象,表示到時間後要執行的操作。PendingIntent與Intent類似,可以封裝Activity、BroadcastReceiver和Service。
但與Intent不同的是,PendingIntent可以脫離應用程序而存在。

接觸Android沒幾天,不太了解。
本來寫好的一個應用在無意中發現,待機的時候,應用中的一個線程停止了運行。
這個線程是每隔一分鍾上傳一個數據到伺服器上。
我當時測試的時候,沒想過待機(接開關鍵)下的情況是怎樣的,現在發現,只要手機一進入待機狀態,這個線程就停止工作了。
不過有一個奇怪的現象,因為我的應用中同時啟動了三個線程。
一個負責每隔一分鍾上傳一個數據,當待機的時候,這個線程暫停運行,當手機不待機的時候,馬上復活。
一個負責接收伺服器發過來的UDP數據包,這個線程倒是不受待機的影響,當有數據來的時候,可以正常處理。
難道是因為datagramSocket.receive(datagramPacket);阻塞的原因?
public void run()
{
while(true)
{
datagramSocket.receive(datagramPacket); //阻塞
}
}

到網上搜索了一下,看到別人說的:
實驗1:使用java.util.Timer
當連接USB線進行調試時,會發現一切工作正常,每5秒更新一次界面,即使是按下電源鍵,仍然會5秒觸發一次。
當拔掉USB線,按下電源鍵關閉屏幕後,過一段時間再打開,發現定時器明顯沒有繼續計數,停留在了關閉電源鍵時的數字。

實驗2:使用AlarmService:
2.1通過AlarmService每個5秒發送一個廣播,setRepeating時的類型為AlarmManager.ELAPSED_REALTIME。
拔掉USB線,按下電源鍵,過一段時間再次打開屏幕,發現定時器沒有繼續計數。
2.2setRepeating是的類型設置為AlarmManager.ELAPSED_REALTIME_WAKEUP
拔掉USB線,按下電源鍵,過一點時間再次打開屏幕,發現定時器一直在計數。

如此看來,使用WAKEUP才能保證自己想要的定時器一直工作,但是肯定會引起耗電量的增加。

我最後自已寫了一個Service類,然後使用AlarmService每隔一分鍾執行一次,在待機的時候也能正常運行。

Ⅱ 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();

Ⅲ Android中Handler的主要作用是什麼通俗點,初學。

Handler的使用主要是android中無法在主線程(即UI線程)中訪問網路、無法在子線程中訪問UI線程元素。
一般是在子線程中訪問網路,然後使用Handler發送message通知主線程處理UI更新操作

Ⅳ 能講講Android的Handler機制嗎

Android的Handler機制是通俗講為了互相發消息,一般是子線程給主線程發消息完成相應操作。

安卓中最常見的操作是子線程操作完事後得到數據想更新UI,安卓有規定不允許在子線程中刷新UI,所以Handler出現了。

使用和理解大致步驟。

  1. 創建全局Handler對象handler,然後在主線程中初始化它(一般在oncreate中),把它的handmessage裡面的方法重寫,這個方法是收到子線程發給它的消息後執行的邏輯。

  2. 在子線程中獲取數據,調用handler.sendmessage,把要發的消息放在message中。message會添加到Messagequue(消息隊列中,handler創建就帶的)。

3.對象handler被創建和初始化的時候,系統自動會啟動Handler.looper,也就是一個消息輪詢器,它不斷的去查看有沒有消息進入到Messagequue(消息隊列中),有就取出交給handler的handmessage去處理。//這段邏輯是系統自動執行,理解就行。*純手打,不騙人~~~

Ⅳ 如何生動形象的理解Android Handler消息處理機制

在一個Android 程序開始運行的時候,會單獨啟動一個Process。默認的情況下,所有這個程序中的Activity,Service,Content Provider,Broadcast Receiver(Android 4大組件)都會跑在這個Process。一個Android 程序默認情況下也只有一個Process,但一個Process下卻可以有許多個Thread。在這么多Thread當中,有一個Thread,稱之為UI Thread。UI Thread在Android程序運行的時候就被創建,是一個Process當中的主線程Main Thread,主要是負責控制UI界面的顯示、更新和控制項交互。在Android程序創建之初,一個Process呈現的是單線程模型,所有的任務都在一個線程中運行。因此,UI Thread所執行的每一個函數,所花費的時間都應該是越短越好。而其他比較費時的工作(訪問網路,下載數據,查詢資料庫等),都應該交由子線程去執行,以免阻塞主線程,導致ANR。那麼問題來了,UI 主線程和子線程是怎麼通信的呢。這就要提到這里要講的Handler機制。
簡單來說,handler機制被引入的目的就是為了實現線程間通信的。handler一共幹了兩件事:在子線程中發出message,在主線程中獲取、處理message。聽起來好像so easy,如果面試中讓闡述下Handler機制,這么回答顯然不是面試官想要的答案。忽略了一個最重要的問題:子線程何時發送message,主線程何時獲取處理message。
為了能讓主線程「適時」得處理子線程所發送的message,顯然只能通過回調的方式來實現——開發者只要重寫Handler類中處理消息的方法,當子線程發送消時,Handler類中處理消息的方法就會被自動回調。
Handler類包含如下方法用於發送處理消息
void handleMessage(Message msg):處理消息的方法,該方法通常用於被重寫。
final boolean hasMessage(int what):檢查消息隊列中是否包含what屬性為指定值的消息。
final boolean hasMessage(int what,Object object):檢查消息隊列中是否包含what屬性為指定值且object屬性為指定對象的消息。
sendEmptyMessage(int what)發送空消息。
sendEmptyMessageDelayed(int what,longdelayMillis);指定多少毫秒之後發送空消息。
sendMessage(Message msg)立即發送消息。
sendMessageDelayed(int what,longdelayMillis);指定多少毫秒之後發送消息。
藉助以上方法,就可以自由穿梭於主線程和子線程之中了。
到這里就結束了么?當然沒有。要講的東西才剛剛開始,要知道消息處理這件事,不是handler一個人在戰斗,android的消息處理有三個核心類:Handler,Looper,和Message。其實還有一個MessageQueue(消息隊列),但是Message Queue被封裝到Looper裡面了,不會直接與Message Queue打交道。
Looper的字面意思是「循環裝置」,它被設計用來使一個普通線程變成Looper線程。所謂Looper線程就是循環工作的線程。在程序開發中,經常會需要一個線程不斷循環,一旦有新任務則執行,執行完繼續等待下一個任務,這就是Looper線程。Looper是用於給一個線程添加一個消息隊列(MessageQueue),並且循環等待,當有消息時會喚起線程來處理消息的一個工具,直到線程結束為止。通常情況下不會用到Looper,因為對於Activity,Service等系統組件,Frameworks已經為初始化好了線程(俗稱的UI線程或主線程),在其內含有一個Looper,和由Looper創建的消息隊列,所以主線程會一直運行,處理用戶事件,直到某些事件(BACK)退出。
如果,需要新建一個線程,並且這個線程要能夠循環處理其他線程發來的消息事件,或者需要長期與其他線程進行復雜的交互,這時就需要用到Looper來給線程建立消息隊列。
使用Looper也非常的簡單,它的方法比較少,最主要的有四個:
public static prepare();為線程初始化消息隊列。
public static myLooper();獲取此Looper對象的引用
public static loop();讓線程的消息隊列開始運行,可以接收消息了。
public void quit();退出具體哪個Looper
在整個消息處理機制中,message又叫task,封裝了任務攜帶的信息和處理該任務的handler,這個很好理解,就不做介紹了。
說了這么多,一定沒聽太明白。沒關系,再對Handler運行機製做個總結:
子線程(無looper)借用主線程(有looper)里的Hander發送一條message到主線程,這個message會被主線程放入message queue,主線程裡面有一個looper,在輪詢message queue的時候發現有一條message。調用handler消息處理者,執行handlemessage方法,去處理這個message,就可以在handlemessage的方法裡面更新ui。好像畫面感不是太強,舉個例子吧。試想有一個生產方便麵的車間,這個車間有兩條生產線,一條是生產面餅的,一條是生產調料包的,面餅的生產線比較先進一點,配備了一個工人叫handler,還配備了一個調料包分類循環器。這個車間能生產很多種方便麵,有老壇酸菜,有泡椒鳳爪,有香菇燉雞,有紅燒牛肉等等。其中方便麵的面餅都是一樣的,只有調料包和包裝袋不一樣,包裝袋是根據調料包來定的。那麼生產線運作起來了:工人Handler把子生產線(子線程)上的調料包(message)放到了主生產線(主線程)上的調料包分類循環器(Looper)上,通過輪詢分類篩選後工人Handler確定這是一包合格的老壇酸菜味調料包,於是工人把老壇酸菜調料包和面餅放在一塊(sendmessage),告訴主生產線,這是一包老壇酸菜方便麵,請給這包方便麵包一個老壇酸菜的包裝袋(更新UI).

Ⅵ 求ANDROID中handler的問題

Handler不等於使用線程。
傳統的UI架構,如swing。將繪制展示、事件派發都放在主線程(UI)線程中進行。
UI線程的實現模型通常是一個死循環,不斷接受Message。組織派發
android中Handler-MessageQueue-Looper,三者構成了這種死循環+消息通信的模型。此處的postDelayed實際上是將一個Runnable任務投入了MessageQueue中,並期望在3000毫秒後執行。
另外不要誤以為Runnable是線程。在java.util.concurrent中,Dogn大神已經明確將執行過程與任務分割出來。Runnable介面只是表示一項任務,既可以同步執行,也可以在新線程中執行。
為何需要Handler而不用Thread。除了消息模型是UI框架的經典模式外,還涉及到UI組件不允許跨線程訪問的限制。無論是.NET也好,swing也好,android也好,不允許在非UI線程中操作這一點都一樣。
Handler便是android框架中非同步線程代碼到達同步線程的官方通道。從另一個角度說,這種基於消息模型的通信模式有時也很有用。相關的例子有IntentService,HandlerThread等。

Ⅶ 我用Android studio開發老是遇到一些方法不能用,比如這個handler.sendMes

背景模糊,要麼自己模糊處理,要麼直接讓UI提供這張圖片,建議直接用圖片其他的功能都很簡單了,直接XML寫布局EditText跟Button就好了

Ⅷ android中handle和線程的關系是什麼

作者:李板溪
鏈接:http://www.hu.com/question/24766848/answer/53037579
來源:知乎
著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請註明出處。

問題背景,假設你要下載一張美女圖顯示出來。 使用這個問題就可以說明主要的問題了。
好了 上代碼,下載美女圖片,然後顯示在 ImageView 中。 代碼如下:
public class MainActivity extends AppCompatActivity {

public static final String beautyUrl = "http://ww3.sinaimg.cn/large/.jpg";
ImageView mBeautyImageView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mBeautyImageView = (ImageView)findViewById(R.id.beauty);
mBeautyImageView.setImageBitmap(downloadImage(beautyUrl));
}

@Nullable
public Bitmap downloadImage(String urlString){
try {
final URL url = new URL(urlString);
try(InputStream is = url.openStream()){
return BitmapFactory.decodeStream(is);
}
} catch (IOException e) {
e.printStackTrace();
return null;
}
}

}

然後這樣的一段看似沒有問題的代碼,在 Android 3 以上是會直接報錯的。 主要錯誤原因在
Caused by: android.os.NetworkOnMainThreadException at android.os.StrictMode$AndroidBlockGuardPolicy.onNetwork(StrictMode.java:1147)
為了保證用戶體驗, Android 在 3.0 之後,就不允許在 主線程(MainThread)即 UI線程 中執行網路請求了。 那怎麼辦呢?
好吧,我們暫不考試 Android 提供的一系統組件及工具類, 用純 Java 的方式來解決這個問題。
在新的線程中下載顯示圖片
在新創建的線程中下載顯示圖片如下:
new Thread(new Runnable() {
@Override
public void run() {
mBeautyImageView.setImageBitmap(downloadImage(beautyUrl));
}
}).start();

看起來來錯的樣子,跑起來看看。 啊,又報錯了。
android.view.ViewRootImpl$: Only the original thread that created a view hierarchy can touch its views.
說只能在創建View 層級結構的線程中修改它。 創建它的線程就是主線程。 在別的線程不能修改。 那怎麼辦?
那現在我們遇到的問題是: 下載不能在主線程下載。 更新ImageView 一定要在 主線程中進行。 在這樣的限制下,我們自然而然想去一個解決辦法: 就是在新創建的線程中下載。 下載完成在主線程中更新 ImageView。
但是,怎麼在下載完成之後,將圖片傳遞給主線程呢?這就是我們問題的關鍵了。
線程間通信
我們的通信要求,當下載線程中下載完成時,通知主線程下載已經完成,請在主線程中設置圖片。 純 Java 的實現上面的線程間通信的辦法我暫沒有找到,於是我想到使用 FutureTask 來實現在主線程中等待圖片下載完成,然後再設置。
FutureTask<Bitmap> bitmapFutureTask = new FutureTask<>(new Callable<Bitmap>() {
@Override
public Bitmap call() throws Exception {
return downloadImage(beautyUrl);
}
});
new Thread(bitmapFutureTask).start();
try {
Bitmap bitmap = bitmapFutureTask.get();
mBeautyImageView.setImageBitmap(bitmap);
} catch (InterruptedException |ExecutionException e) {
e.printStackTrace();
}

不過這雖然騙過了 Android 系統,但是雖然系統阻塞的現象沒有解決。 例如我在 get() 方法前後設置了輸出語句:
Log.i(TAG,"Waiting Bitmap");
Bitmap bitmap = bitmapFutureTask.get();
Log.i(TAG,"Finished download Bitmap");

設置了下載時間至少 5 秒鍾之後,輸出如下:
06-27 23:30:18.058 21298-21298/com.banxi1988.androiditc I/MainActivity﹕ Waiting Bitmap 06-27 23:30:23.393 21298-21298/com.banxi1988.androiditc I/MainActivity﹕ Finished download Bitmap
讓主線程什麼事做不做,就在那傻等了半天。然後由於 onCreate沒有返回。用戶也就還沒有看到界面。 導致說應用半天啟動不了。。卡死了。。
查閱了一些資料,沒有不用 Android 的框架層的東西而實現在其他進程執行指定代碼的。
而 Android 中線程間通信就得用到 android.os.Handler 類了。 每一個 Handler 都與一個線程相關聯。 而 Handler 的主要功能之一便是: 在另一個線程上安插一個需要執行的任務。
這樣我的問題就通過一個 Handler 來解決了。
於是 onCreate 中的相關代碼變成如下了:
final Handler mainThreadHandler = new Handler();

new Thread(new Runnable() {
@Override
public void run() {
final Bitmap bitmap = downloadImage(beautyUrl);
mainThreadHandler.post(new Runnable() {
@Override
public void run() {
mBeautyImageView.setImageBitmap(bitmap);
}
});
}
}).start();

看起來很酷的樣子嘛,一層套一層的 Runnable. mainThreadHandler 因為是在 主線程中創建的, 而 Handler創建時,綁定到當前線程。 所以 mainThreadHandler 綁定到主線程中了。
當然 Android 為了方便你在向主線程中安排進操作,在 Activity類中提供了 runOnUiThread 方法。 於是上面的代碼簡化為:
new Thread(new Runnable() {
@Override
public void run() {
final Bitmap bitmap = downloadImage(beautyUrl);
runOnUiThread(new Runnable() {
@Override
public void run() {
mBeautyImageView.setImageBitmap(bitmap);
}
});
}
}).start();

你不用自己創建一個 Handler了。
而 runOnUiThread 的具體實現,也跟我們做得差不多。UI線程即主線程。
public final void runOnUiThread(Runnable action) {
if (Thread.currentThread() != mUiThread) {
mHandler.post(action);
} else {
action.run();
}
}

Handler 與 Loop 簡介
上面說到 每一個 Handler 都與一個線程相綁定。 實際上是,通過 Handler 與 Loop 綁定,而每一個 Loop 都與一個線程想綁定的。 比如 Handler 中兩個主要構造函數大概如下:
public Handler(...){
mLooper = Looper.myLooper();
// ...
}

public Handler(Looper looper,...){
mLooper = looper;
// ...
}

public static Looper myLooper() {
return sThreadLocal.get();
}

然後 Looper 的構造函數如下:
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}

綁定了當前的線程和生成了一個消息隊列。
值得提起的一點是, Looper 類保持了對 應用的主線程的 Looper 對象的靜態應用。
private static Looper sMainLooper; // guarded by Looper.class
public static Looper getMainLooper() {
synchronized (Looper.class) {
return sMainLooper;
}
}

這樣就可以方便你在其他線程中,使用一個綁定到主線程的 Handler,從而方便向主線程安插任務。 例如一般的圖片處理庫即是如此。這樣你只要指定一個 圖片的 url,及要更新的ImageView 即可。 如 Picasso 庫可以用如下代碼的讀取並更新圖片。 Picasso.with(context).load(url).into(imageView);
然後 Handler 可以做的事情還有很多。 因為它後面有 Looper 有 MessageQueue。可以深入了解下。
談一下線程池與 AsyncTask 類
Android 早期便有這個便利的類來讓我們方便的處理 工作線程及主線程的交互及通信。 但是現在先思考一下,我們上面的代碼可能遇到的問題。 比如,我們現在要顯示一個圖片列表。 一百多張圖片。 如果每下載一張就開一個線程的話,那一百多個線程,那系統資源估計支持不住。特別是低端的手機。
正確的做法是使用一個線程池。
final ExecutorService executor = Executors.newCachedThreadPool();
executor.execute(new Runnable() {
@Override
public void run() {
final Bitmap bitmap = downloadImage(beautyUrl);
runOnUiThread(new Runnable() {
@Override
public void run() {
mBeautyImageView.setImageBitmap(bitmap);
}
});
executor.shutdown();
}
});

由於我們是在在一個局部方法中使用了一個線程池。所以處理完了之後應該將線程停止掉。 而我們上面只有一個線程,所以直接在下載完成之後,調用 executor停掉線程池。 那如果執行了多個圖片的下載請求。需要怎麼做呢? 那就要等他們都完成時,再停止掉線程池。 不過這樣用一次就停一次還是挺浪費資源的。不過我們可以自己保持一個應用級的線程池。 不過這就麻煩不少。
然後 Android 早已經幫我們想法了這一點了。 我們直接使用 AsyncTask 類即可。
於是我們下載圖片並顯示圖片的代碼如下:
new AsyncTask<String,Void,Bitmap>(){
@Override
protected Bitmap doInBackground(String... params) {
return downloadImage(params[0]);
}

@Override
protected void onPostExecute(Bitmap bitmap) {
mBeautyImageView.setImageBitmap(bitmap);
}
}.execute(beautyUrl);

相比之前的代碼簡潔不少。
看一下 AsyncTask 的源代碼,正是集合我們之前考慮的這些東西。
一個全局的線程池
public static final Executor THREAD_POOL_EXECUTOR
= new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);

一個綁定主線程的 Handler ,在線程中處理傳遞的消息
private static class InternalHandler extends Handler {
public InternalHandler() {
super(Looper.getMainLooper());
}

@SuppressWarnings({"unchecked", "RawUseOfParameterizedType"})
@Override
public void handleMessage(Message msg) {
AsyncTaskResult<?> result = (AsyncTaskResult<?>) msg.obj;
switch (msg.what) {
case MESSAGE_POST_RESULT:
// There is only one result
result.mTask.finish(result.mData[0]);
break;
case MESSAGE_POST_PROGRESS:
result.mTask.onProgressUpdate(result.mData);
break;
}
}
}

小結
Android 提供的 Looper 和 Handler 可以讓我們非常方便的在各線程中安排可執行的任務

Ⅸ 安卓 handle和callback的區別

android.os.Handler Handler在android里負責發送和處理消息。它的主要用途有: 1)按計劃發送消息或執行某個Runnanble(使用POST方法); 2)從其他線程中發送來的消息放入消息隊列中,避免線程沖突(常見於更新UI線程) 默認情況下,Handler接受的是當前線程下的消息循環實例(使用Handler(Looper looper)、Handler(Looper looper, Handler.Callback callback)可以指定線程),同時一個消息隊列可以被當前線程中的多個對象進行分發、處理(在UI線程中,系統已經有一個Activity來處理了,你可以再起若干個Handler來處理)。在實例化Handler的時候,Looper可以是任意線程的,只要有Handler的指針,任何線程也都可以sendMessage。Handler對於Message的處理不是並發的。一個Looper 只有處理完一條Message才會讀取下一條,所以消息的處理是阻塞形式的(handleMessage()方法里不應該有耗時操作,可以將耗時操作放在其他線程執行,操作完後發送Message(通過sendMessges方法),然後由handleMessage()更新UI)。 android中Handle類的用法 當我們在處理下載或是其他需要長時間執行的任務時,如果直接把處理函數放Activity的OnCreate或是OnStart中,會導致執行過程中整個Activity無響應,如果時間過長,程序還會掛掉。Handler就是把這些功能放到一個單獨的線程里執行,與Activity互不影響。 當用戶點擊一個按鈕時如果執行的是一個常耗時操作的話,處理不好會導致系統假死,用戶體驗很差,而Android則更進一步,如果任意一個Acitivity沒有響應5秒鍾以上就會被強制關閉,因此我們需要另外起動一個線程來處理長耗時操作,而主線程則不受其影響,在耗時操作完結發送消息給主線程,主線程再做相應處理。那麼線程之間的消息傳遞和非同步處理用的就是Handler。 加群討論研究 QQ群:56839077

Ⅹ Android中的Handler詳解以及和Thread的區別

一、Handler的定義:
主要接受子線程發送的數據, 並用此數據配合主線程更新UI.

解釋: 當應用程序啟動時,Android首先會開啟一個主線程 (也就是UI線程) , 主線程為管理界面中的UI控制項,進行事件分發, 比如說, 你要是點擊一個 Button ,Android會分發事件到Button上,來響應你的操作。 如果此時需要一個耗時的操作,例如: 聯網讀取數據, 或者讀取本地較大的一個文件的時候,你不能把這些操作放在主線程中,,如果你放在主線程中的話,界面會出現假死現象, 如果5秒鍾還沒有完成的話,,會收到Android系統的一個錯誤提示 "強制關閉". 這個時候我們需要把這些耗時的操作,放在一個子線程中,因為子線程涉及到UI更新,,Android主線程是線程不安全的,也就是說,更新UI只能在主線程中更新,子線程中操作是危險的. 這個時候,Handler就出現了.,來解決這個復雜的問題 , 由於Handler運行在主線程中(UI線程中), 它與子線程可以通過Message對象來傳遞數據, 這個時候,Handler就承擔著接受子線程傳過來的(子線程用sedMessage()方法傳弟)Message對象,(裡麵包含數據) , 把這些消息放入主線程隊列中,配合主線程進行更新UI。

二、Handler一些特點

handler可以分發Message對象和Runnable對象到主線程中, 每個Handler實例,都會綁定到創建他的線程中(一般是位於主線程),
它有兩個作用: (1): 安排消息或Runnable 在某個主線程中某個地方執行, (2)安排一個動作在不同的線程中執行

Handler中分發消息的一些方法

[html] view plain
post(Runnable)
postAtTime(Runnable,long)
postDelayed(Runnable long)
sendEmptyMessage(int)
sendMessage(Message)
sendMessageAtTime(Message,long)
sendMessageDelayed(Message,long)

以上post類方法允許你排列一個Runnable對象到主線程隊列中,
sendMessage類方法, 允許你安排一個帶數據的Message對象到隊列中,等待更新.

三、Handler實例

(1) 子類需要繼承Hendler類,並重寫handleMessage(Message msg) 方法, 用於接受線程數據

以下為一個實例,它實現的功能為 : 通過線程修改界面Button的內容

[html] view plain
public class MyHandlerActivity extends Activity {

Button button;

MyHandler myHandler;

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.handlertest);

button = (Button) findViewById(R.id.button);

myHandler = new MyHandler();

// 當創建一個新的Handler實例時, 它會綁定到當前線程和消息的隊列中,開始分發數據

// Handler有兩個作用, (1) : 定時執行Message和Runnalbe 對象

// (2): 讓一個動作,在不同的線程中執行.

// 它安排消息,用以下方法

// post(Runnable)

// postAtTime(Runnable,long)

// postDelayed(Runnable,long)

// sendEmptyMessage(int)

// sendMessage(Message);

// sendMessageAtTime(Message,long)

// sendMessageDelayed(Message,long)

// 以上方法以 post開頭的允許你處理Runnable對象

//sendMessage()允許你處理Message對象(Message里可以包含數據,)

MyThread m = new MyThread();

new Thread(m).start();

}

/**

* 接受消息,處理消息 ,此Handler會與當前主線程一塊運行

* */

class MyHandler extends Handler {

public MyHandler() {

}

public MyHandler(Looper L) {

super(L);

}

// 子類必須重寫此方法,接受數據

@Override

public void handleMessage(Message msg) {

// TODO Auto-generated method stub

Log.d("MyHandler", "handleMessage......");

super.handleMessage(msg);

// 此處可以更新UI

Bundle b = msg.getData();

String color = b.getString("color");

MyHandlerActivity.this.button.append(color);

}

}

class MyThread implements Runnable {

public void run() {

try {

Thread.sleep(10000);

} catch (InterruptedException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

Log.d("thread.......", "mThread........");

Message msg = new Message();

Bundle b = new Bundle();// 存放數據

b.putString("color", "我的");

msg.setData(b);

MyHandlerActivity.this.myHandler.sendMessage(msg); // 向Handler發送消息,更新UI

}

}

}

例外一個案例:

[html] view plain
package com.example.span.view;

import java.util.LinkedList;
import android.app.AlertDialog;
import android.content.ComponentName;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.RectF;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.view.KeyEvent;
import android.view.View;
import android.widget.Toast;

import com.example.span.view.domain.Block;

/**
* 2013-6-6 上午9:24:58
*
* @author 喬曉松
*/
public class GameView extends View {

public static boolean flag = true;
public static Block block;
public Handler handler;
public static int dir = 2;
public static final int DIRTOP = -1;
public static final int DIRLEFT = -2;
public static final int DIRDOWN = 1;
public static final int DIRRIGHT = 2;
public static int descount = 2;
public Canvas canvas;
public static Food food;
public LinkedList<Point> points = new LinkedList<Point>();

public LinkedList<Point> getPoints() {
return points;
}

public void setPoints(LinkedList<Point> points) {
this.points = points;
}

public GameView(Context context, AttributeSet attrs) {
super(context, attrs);
block = new Block(this);
for (int i = 0; i < 3; i++) {
Point point = new Point(block.getCx(), block.getCy());
block.setCx(block.getCx() - 20);
points.addLast(point);
}
food = new Food(this);
handler = new Handler() {

@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case DIRLEFT:
if (msg.what + descount != 0) {
descount = -2;
block.moveLeft();
} else {
block.moveRight();
}
break;
case DIRRIGHT:
if (msg.what + descount != 0) {
descount = 2;
block.moveRight();
} else {
block.moveLeft();
}
break;
case DIRTOP:
if (msg.what + descount != 0) {
descount = -1;
block.giveUp();
} else {
block.downLoad();
}
break;
case DIRDOWN:
if (msg.what + descount != 0) {
descount = 1;
block.downLoad();
} else {
block.giveUp();
}
break;
case -3:
Toast.makeText(getContext(), "Game Over", Toast.LENGTH_LONG)
.show();
new AlertDialog.Builder(getContext())
.setTitle("游戲提示")
.setMessage("Game Over")
.setPositiveButton("退出",
new DialogInterface.OnClickListener() {

@Override
public void onClick(
DialogInterface dialog,
int which) {
Thread.currentThread().stop();
}
})
.setNegativeButton("返回菜單",
new DialogInterface.OnClickListener() {

@Override
public void onClick(
DialogInterface dialog,
int which) {

Intent intent = new Intent();
intent.setAction("android.intent.action.MAI");
intent.addCategory("android.intent.category.LAUNCHER");
intent.setFlags(0x10200000);
intent.setComponent(new ComponentName(
"com.example.span",
"com.example.span.SpanActivity"));
getContext().startActivity(intent);

}
}).show();
break;
}
}
};
new Thread(new Runnable() {

@Override
public void run() {
while (flag) {
try {
Thread.sleep(500);
handler.sendEmptyMessage(dir);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
handler.sendEmptyMessage(-3);
}
}).start();
}

@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
System.out.println(keyCode);
return super.onKeyDown(keyCode, event);
}

@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
this.canvas = canvas;
food.chsw(canvas);
/*
* if (descount == 2) { chsw(); } else { if (points.contains(new
* Point(40, 40))) { System.out.println("吃掉食物了,,.."); } else { chsw(); }
* }

閱讀全文

與androidhandler下載相關的資料

熱點內容
命令號角 瀏覽:273
格力雙轉子壓縮機 瀏覽:612
hp伺服器上的ip地址 瀏覽:560
c語言編程計算100以內的所有素數 瀏覽:622
命令輸入框 瀏覽:892
冰箱壓縮機發燙噪音 瀏覽:85
單片機棧溢出符號 瀏覽:330
命令與征服修改器怎麼用 瀏覽:485
什麼app比較費錢 瀏覽:832
為什麼同一個app的功能不一樣 瀏覽:232
小型工作室用什麼伺服器好 瀏覽:995
程序員的興趣 瀏覽:413
華為伺服器有什麼好 瀏覽:701
程序員和測試之間的關系 瀏覽:945
加密蚊帳什麼意思 瀏覽:151
javalistclear 瀏覽:607
哪個app上民宿多靠譜 瀏覽:828
重慶伺服器租用哪裡有雲伺服器 瀏覽:453
土星模擬器文件夾 瀏覽:902
文件夾文件袋文件盒 瀏覽:695