android線程通知
① 安卓多線程間通信和多進程之間通信有什麼不同
1.安卓線程間通信的方式有以下幾種1)共享變數(內存)
2)管道
3)handle機制
runOnUiThread(Runnable)
view.post(Runnable)
android 進程內的消息驅動機制---Handler,MessageQueue,Runnable,Looper
Looper和Message的處理機制:首先在主線程中創建了一個handler對象,目的是為了處理從子線程發送過來的消息,然後當子線程有發送消息的需求時會使用Message對象,消息首先會被存儲在Message queue消息隊列中,主線程還有一個Looper消息輪詢器,會循環遍歷消息隊列中的消息,當發現消息的時候會發送消息給handler處理(更新ui等操作),handler調用handleMessage處理完後將Message置為null以便回收.
2進程間的通信
進程間的通信:
bind機制(IPC->AIDL)
linux級共享內存
boradcast
Activity之間可以通過intent來傳遞數據
3.安卓結束進程幾種方式
1)使用ActivityManager中的restartPackage(String packname)方法,這里清單文件裡面要配置許可權
2)android.os.process.killProcess(int pid)只能終止本程序的進程
3)System.exit()
4)在android2.2版本之後則不能再使用restartPackage()方法,而應該使用killBackgroundProcesses()方法,同時應該配置許可權
5)利用反射調用forceStopPackage來結束- Method forceStopPackage = am.getClass().getDeclaredMethod("forceStopPackage", String.class);
- forceStopPackage.setAccessible(true);
- forceStopPackage.invoke(am, yourpkgname);
6)使用Linux指令kill -9
② android 主線程和子線程有什麼區別
本文較為深入的分析了android中UI主線程與子線程。分享給大家供大家參考。具體如下:
在一個Android 程序開始運行的時候,會單獨啟動一個Process。默認的情況下,所有這個程序中的Activity或者Service(Service和 Activity只是Android提供的Components中的兩種,除此之外還有Content Provider和Broadcast Receiver)都會跑在這個Process。
一個Android 程序默認情況下也只有一個Process,但一個Process下卻可以有許多個Thread。在這么多Thread當中,有一個Thread,我們稱之為UI Thread。UI Thread在Android程序運行的時候就被創建,是一個Process當中的主線程Main Thread,主要是負責控制UI界面的顯示、更新和控制項交互。在Android程序創建之初,一個Process呈現的是單線程模型,所有的任務都在一個線程中運行。因此,我們認為,UI Thread所執行的每一個函數,所花費的時間都應該是越短越好。而其他比較費時的工作(訪問網路,下載數據,查詢資料庫等),都應該交由子線程去執行,以免阻塞主線程。
那麼,UI Thread如何和其他Thread一起工作呢?常用方法是:誕生一個主線程的Handler物件,當做Listener去讓子線程能將訊息Push到主線程的Message Quene里,以便觸發主線程的handlerMessage()函數,讓主線程知道子線程的狀態,並在主線程更新UI。
例如,在子線程的狀態發生變化時,我們需要更新UI。如果在子線程中直接更新UI,通常會拋出下面的異常:
11-07 13:33:04.393: ERROR/javaBinder(1029):android.view.ViewRoot$:Only the original thread that created a view hierarchy can touch its views.
意思是,無法在子線程中更新UI。為此,我們需要通過Handler物件,通知主線程Ui Thread來更新界面。
如下,首先創建一個Handler,來監聽Message的事件:
private final int UPDATE_UI = 1;
private Handler mHandler = new MainHandler();
private class MainHandler extends Handler {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case UPDATE_UI: {
Log.i("TTSDeamon", "UPDATE_UI");
showTextView.setText(editText.getText().toString());
ShowAnimation();
break;
}
default:
break;
}
}
}
或者:
private Handler mHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case UPDATE_UI: {
Log.i("TTSDeamon", "UPDATE_UI");
showTextView.setText(editText.getText().toString());
ShowAnimation();
break;
}
default:
break;
}
}
}
當子線程的狀態發生變化,則在子線程中發出Message,通知更新UI。
mHandler.sendEmptyMessageDelayed(UPDATE_UI, 0);
在我們的程序中,很多Callback方法有時候並不是運行在主線程當中的,所以如果在Callback方法中更新UI失敗,也可以採用上面的方法。
③ Android——消息分發機制
什麼是 Handler 機制 ?
Handler 機制是 Android 中用於 線程間通信 的一套通信機制。
為什麼是 Handler ?Handler 機制為什麼被那麼多次的提及 ?
從Android4.0開始,Android 中網路請求強制不允許在主線程中操作,而更新UI的操作則不允許在子線程中執行。當在子線程中執行網路請求,拿到伺服器返回的數據之後,要更新UI。由於系統的要求,勢必會產生一種矛盾:數據在子線程,更新UI要在主線程。此時我們必須要把數據返回到主線程中才行,Handler機制應運而生。
Android 中針對耗時的操作,放在主線程操作,輕者會造成 UI 卡頓,重則會直接無響應,造成 Force Close。同時在 Android 3.0 以後,禁止在主線程進行網路請求。
針對耗時或者網路操作,那就不能在主線程進行直接操作了,需要放在子線程或者是工作線程中進行操作,操作完成以後,再更新主線程即 UI 線程。這里就涉及到一個問題了,在子線程執行完成以後,怎麼能更新到主線程即 UI 線程呢,針對以上問題,就需要用到 Android 的消息機制了,即: Handler, Message, MessageQueue, Looper 全家桶
Handler機制中最重要的四個對象
Handler的構造方法:
Looper :
Handler的使用:
MessageQueue:
Looper.loop()
Handler.dispatchMessage()
handler導致activity內存泄露的原因:
handler發送的消息在當前handler的消息隊列中,如果此時activity finish掉了,那麼消息隊列的消息依舊會由handler進行處理,若此時handler聲明為內部類(非靜態內部類),我們知道內部類天然持有外部類的實例引用,這樣在GC垃圾回收機制進行回收時發現這個Activity居然還有其他引用存在,因而就不會去回收這個Activity,進而導致activity泄露。
假如在子線程執行了耗時操作,這時用戶操作進入了其他的 acitvity, 那麼 MainActivity 就會被內存回收的,但是這個時候發現 Handler 還在引用著 MainActivity,內存無法及時回收,造成內存泄漏。
Handler 防止內存泄漏常見方法:
為什麼通過 Handler 可以把子線程的結果通知或者攜帶給 UI 線程 ?
這里的 Handler 指的是主線程的 Handler ,同時與 Handler 配套的 Looper , MessageQueue 是在 UI 線程初始化的,所以在子線程中調用 Handler 發送消息可以更新 UI 線程。
Looper 在 UI 線程源碼, 在 ActivityThread 類:
④ Android 怎麼啟動一個工作線程及線程如何與UI線程交互
啟動線程就調用start方法,跟UI交互的話可以藉助Handler
⑤ Android怎麼正確使用wait和notify方法
經常有人有以下的說法:
notify只會通知一個在等待的對象,而notifyAll會通知所有在等待的對象,並且所有對象都會繼續運行
並且,好像都有例子可以證明。上面的說法,可以說對,也可以說不對。究其原因,在於其中有一點很關鍵,官方的說法如下所示:
wait,notify,notifyAll:
此方法只應由作為此對象監視器的所有者的線程來調用。通過以下三種方法之一,線程可以成為此對象監視器的所有者:
通過執行此對象的同步實例方法。
通過執行在此對象上進行同步的 synchronized 語句的正文。
對於 Class 類型的對象,可以通過執行該類的同步靜態方法。
一次只能有一個線程擁有對象的監視器。
以上說法,摘自javadoc。意思即,在調用中,必須持有對象監視器(即鎖),我們可以理解為需要在synchronized方法內運行。那麼由此話的隱含意思,即如果要繼續由同步塊包含的代碼塊,需要重新獲取鎖才可以。這句話,在javadoc中這樣描述:
wait
此方法導致當前線程(稱之為 T)將其自身放置在對象的等待集中,然後放棄此對象上的所有同步要求。出於線程調度
目的,在發生以下四種情況之一前,線程 T 被禁用,且處於休眠狀態:
其他某個線程調用此對象的 notify 方法,並且線程 T 碰巧被任選為被喚醒的線程。
其他某個線程調用此對象的 notifyAll 方法。
其他某個線程中斷線程 T。
大約已經到達指定的實際時間。但是,如果 timeout 為零,則不考慮實際時間,在獲得通知前該線程將一直等待。
然後,從對象的等待集中刪除線程 T,並重新進行線程調度。然後,該線程以常規方式與其他線程競爭,以獲得在該對
象上同步的權利;一旦獲得對該對象的控制權,該對象上的所有其同步聲明都將被恢復到以前的狀態,這就是調用 wait
方法時的情況。然後,線程 T 從 wait 方法的調用中返回。所以,從 wait 方法返回時,該對象和線程 T 的同步狀態與調
用 wait 方法時的情況完全相同。
即必須重新進行獲取鎖,這樣對於notifyAll來說,雖然所有的線程都被通知了。但是這些線程都會進行競爭,且只會有一個線程成功獲取到鎖,在這個線程沒有執行完畢之前,其他的線程就必須等待了(只是這里不需要再notifyAll通知了,因為已經notifyAll了,只差獲取鎖了)有如下一個代碼,可以重現這個現象。