androidfor循環執行
『壹』 Android面試必問handler機制淺析
Handler是Android中的非同步消息處理機制。當發送一個消息之後,這個消息是進入一個消息隊列(MessageQueue),在消息隊列中通過Looper去循環的獲取隊列中的消息,然後將消息分派給對應的處理者進行處理。
Message:存儲需要處理操作的信息
MessageQueue:先進先出,存儲handler發送過來的消息
Looper:循環器,它是消息隊列和handler的通信媒介,1:循環的取出消息隊列中的消息;2:將取出的消息發送給對應的處理者
Handler:主線程和子線程的通信媒介,1:添加消息到消息隊列; 2:處理循環器分派過來的消息
在handler機制中,Looper.loop方法會不斷循環獲取Message, 其中的消息的獲取是通過調用MessageQueue的next()方法獲取的,而該方法會調用nativePollOnce()方法 ,這是一個native方法。底層的實現涉及到Linux pipe/epoll機制,nativePollOnce()被阻塞時,主線程會釋放CPU資源,進入休眠狀態. 直到下個消息到達或者有事務發生,會通過pipe管道寫端寫入數據來喚醒looper工作。
Android6.0及以前的版本使用管道與epoll來完成Looper的休眠與喚醒的
Android6.0及以後的版本使用eventfd與epoll來完成Looper的休眠與喚醒的
如果不處理的話,會阻塞線程,處理方案是調用Looper的quit()(清空所有的延遲和非延遲的消息)和quitSafely()(只清空延遲消息); 這個方法會調用MessageQueue的quit()方法,清空所有的Message,並調用nativeWake()方法喚醒之前被阻塞的nativePollOnce(),使得方法next()方法中的for循環繼續執行,接下來發現Message為null後就會結束循環,Looper結束。如此便可以釋放內存和線程
同進程線程間內存共享,通過handler通信,消息的內容是不需要從一個線程拷貝到另一個線程,因為兩個線程間可使用的內存是同一個區域。(注意:線程私有區域ThreadLocal)
管道的作用就是當一個線程准備好Message,並放入消息池,這時需要通知了一個線程B去處理這個消息。線程A向管道的寫端寫入數據,管道有數據便會喚醒線程B去處理消息。管道的作用是用於通知另一個線程的,這便是最核心的作用。
從內存角度,通信過程中binder涉及到一次內存拷貝,handler機制中的Message根本不需要拷貝,本身就是在同一片內存。
從CPU角度,為了Binder通信底層驅動還需要創建一個binder線程池,每次通信涉及binder線程的創建和內存的分配等比較浪費CPU資源
原因:handler發送的消息在當前handler的消息隊列中,如果此時activity被finish掉了,那麼消息隊列的消息依舊由handler進行處理,若此時handler申明為內存類(非靜態內部類),內部類持有外部類的實例引用,這樣在GC垃圾回收時發現Activity還有其他引用存在,因而就不會去回首這個Activity,進而導致Activity泄漏。
方法:使用靜態內部類,並且使用WeakReference包裹外部類的對象。首先靜態內部類不持有外部類的引用,使用靜態的handler不會導致activity的泄漏,handler定義static的同時,還要用WeakReference包裹外部類的對象。
『貳』 android 的shell中如何使用while和for,我需要實現100次循環dd命令。
android中的sh不支持「((",expr,這些,要用
i=$(($1-1))
#!/system/bin/sh
i=100
while [ i -gt 0 ]
do
echo $i
i=$((i-1))
done
下面是我自己實驗的一個只循環十次的結果
root@android:/ # i=10;while [ i -gt 0 ];do echo $i;i=$(($i-1));done
10
9
8
7
6
5
4
3
2
1