android前台進程
❶ android進程管理機制
Android系統與其他操作系統有個很不一樣的地方,就是其他操作系統盡可能移除不再活動的進程,從而盡可能保證多的內存空間,而Android系統卻是反其道而行之,盡可能保留進程。Android這樣設計有什麼優勢呢?又是通過怎樣的方法來管理這些被保留的進程的呢?Android用戶又該如何正確使用手機從而更好發揮Android系統所特有的優勢呢?本文將一一為您解開這些謎團。
本文的主要內容如下:
一、Android進程管理的特殊設計
Linux系統對進程的管理方式是一旦進程活動停止,系統就會結束該進程。盡管Android基於Linux Kernel,但在進程管理上,卻採取了另外一種獨特的設計:當進程活動停止時,系統並不會立刻結束它,而是會盡可能地將該進程保存在內存中,在以後的某個時間,一旦需要該進程,系統就會立即打開它,而不用再做一些初始化操作。只有當剩餘內存不夠用了,為了維持新開啟的進程或者比較重要的進程的正常運行,系統才會選擇性地殺掉一些不重要的內存,騰出內存空間來,所以Android系統永遠不會有內存不足的提示。
二、Android獨特進程管理設計的好處
Android這種獨特的設計,也正是Android標榜的優勢之一,這有兩個好處:
1、最大限度地提高內存的使用率。
比如,你的內存是8G,如果每次使用完某個進程就殺掉,那麼被使用的內存基本上會始終保持在某個值,比如4G以內,那麼內存的使用率就總是保存在50%以內,剩餘的4G內存形同虛設,發揮用處的機會非常少。而Android的這種設計,就可以做到有多少內存就用多少內存,盡可能大地提高內存使用率。同樣比如有8G內存,使用完的進程仍保留在內存中,累積下來,被使用的內存就盡可能地會接近8G。
2、提高再次啟動時的啟動速度
被駐留在內存中不再活動的進程(後台進程或空進程,後面會再講到),很多是經常需要使用的,當再次使用該進程的時候,系統立即打開它,而不需要再重新初始化。例如,我們常用的瀏覽器,當暫時不再使用時,按下Home鍵或Back鍵,瀏覽器進程就變成了不再活動的進程。如果下次又要使用了,點擊多任務鍵,在最近使用應用列表中點擊瀏覽器即可,瀏覽器界面仍然保持著退出前的界面。但如果退出時把該進程移除了,那麼再次使用時,就需要重新初始化,然後進入該應用,這往往會花費不少的時間。
三、Android進程的五個等級
Android系統將盡量長時間地保持應用進程,但為了新建進程或運行更重要的進程,最終需要移除舊進程來回收內存。為了確定保留或終止哪些進程,系統會根據進程中正在運行的組件以及這些組件的狀態,將每個進程放入「重要性層次結構」中。必要時,系統會首先消除重要性最低的進程,然後是重要性略遜的進程,以此類推,以回收系統資源。該「重要性層級結構」將進程分為了五個等級:
1、前台進程(foreground)
前台進程是指那些有組件正和用戶進行交互的應用程序的進程,也稱為Active進程。這些都是Android嘗試通過回收其他應用程序來使其保持相應的進程。這些進程的數量非常少,只有等到最後關頭才會終止這些進程,是用戶最不希望終止的進程。例如:而當你運行瀏覽器這類應用時,它們的界面就會顯示在前台,它們就屬於前台進程,當你按home鍵回到主界面,他們就變成了後台程序。
如果一個進程滿足以下任一條件,即視為前台進程:
(1)託管處於活動狀態的Activity,也就是說,它們位於前台並對用戶事件進行響應,此時的情形為響應了Activity中的onResume()生命周期方法,但沒有響應onPause()。
(2)託管正在執行onReceive()方法處理事件程序的BroadcastReceiver。
(3)託管正在執行onStart()、onCreate()或onDestroy()事件處理程序的Service。
(4)託管正在運行且被標記為在前台運行的Service,即調用了該Service的startForeground()方法。
(5)託管某個Service,且該Service正綁定在用戶正在交互的Activity的Service,即該Activity正處於活動狀態。
2、可見進程(visible)
沒有任何前台組件、但仍然會影響用戶在屏幕上所見內容的進程。如果一個進程滿足以下任一條件,即視為可見進程:
(1)託管不在前台、但仍對用戶可見的Activity(已調用其onPause()方法)。例如:如果前台Acitivty啟動了一個對話框,或者啟動了一個非全屏,亦或是一個透明的Activity,允許在其後顯示上一個Activity,則可能會發生這種情況,這類Activity不在前台運行,也不能對用戶事件作出反應。
(2)託管綁定到可見Activity的Service。(官網上說是綁定到可見或前台Activity,但筆者有一點疑問,這個和「前台進程」中第(5)點相矛盾嗎,綁定到前台Activity,那就是前台進程了)
可見進程被視為是極其重要的進程,這類進程的數量也很少,只有在資源極度匱乏的環境下,為保證前台進程繼續執行時才會終止。
3、服務進程(Service)
正在運行已使用startService()方法啟動的Serice且不屬於上述兩個更高類別進程的進程。盡管服務進程與用戶所見內容沒有直接關聯,但是它們通常在執行一些用戶關心的操作。因此,除非內存不足以維持所有前台進程和可見進程同時運行,否則系統會讓服務進程保持運行狀態。
有些資料上面也稱這種進程為次要服務(Secondary Service),而屬於上述兩個更高類別的進程則被稱為主要服務,主要服務往往屬於系統進程,如撥號進程等,不可能被進程管理輕易終止。這里我們以Android開發者官網的稱呼為標准,稱為服務進程。
4、後台進程(hidden)
包含目前對用戶不可見的Activity,即該Activity調用了onStop()方法。這些進程對用戶體驗沒有直接影響,系統可能隨時終止它們,以回收內存供上述三個更高級別的進程使用。通常會有很多後台進程在運行,它們會保存在LRU(Least Recently Used,最近最少使用)列表中,以確保包含用戶最近查看的Activity的進程最後一個被終止。如果某個Activity正確實現了生命周期方法,並保存了其當前狀態,則終止其進程不會對用戶體驗產生明顯影響,因為當用戶導航回該Activity時,Activity會恢復其所有可見狀態。
這里讀者可以做個試驗,先開啟微信,進入到朋友圈界面, 然後點擊手機屏幕下方的導航欄中的Home按鍵進入到後台,再點擊最近使用應用列表顯示按鈕(不同的手機位置不一樣,有的在Home鍵左邊,有的則在Home鍵右邊),在顯示的最近使用應用的列表中清理掉微信應用,最後再點擊桌面的微信圖標啟動微信,會發現顯示的界面仍然是朋友圈界面。
後台進程,我們可以簡單理解為,應用(只考慮只有Activity組件的情況)啟動後按Home鍵後被切換到後台的進程。如瀏覽器、閱讀器等,當程序顯示在屏幕上時,它們所運行的進程即為前台進程(foreground),一旦按home鍵(注意不是back鍵)返回到桌面,程序就停留在後台,成為後台進程。
5、空進程(empty)
不含任何活動應用組件的進程。保留這種進程的唯一目的是用作緩存,以縮短下次再其中運行組件所需要的啟動時間。一般來說,當應用按back按鍵退出後應用後,就變成了一個空進程。比如BTE,在程序退出後,依然會在進程中駐留一個空進程,這個進程里沒有任何數據在運行,作用往往是提高該程序下次的啟動速度或者記錄程序的一些歷史信息。當系統內存不夠用時,無疑,該進程是應該最先終止的。在最近使用應用列表中,可以看到按back鍵退出的應用。
根據進程中當前活動組件的重要程度,Android會將進程評定為它可能達到的最高級別。通俗地說,就是如果一個進程同時擁有多個對應上述不同等級進程的組件時,會以最高的那個等級作為該進程的等級。例如,如果某進程託管著服務和可見Activity,則會將此進程評定為可見進程,而不是服務進程。
此外,一個進程的級別可能會因為其他進程對它的依賴而有所提高,即服務於另一進程的進程其級別永遠不會低於其所服務的進程。例如,如果進程A中的內容提供程序為進程B中的客戶端提供服務,或者如果進程A中的服務綁定到進程B中的組件,則進程A始終被視為至少與進程B同樣重要。
由於運行服務的進程其級別高於託管後台Activity的進程,因此啟動長時間運行操作的Activity最好為該操作啟動Service,而不是簡單地創建工作線程,當操作有可能比Activity更加持久時更應該如此。例如,正在將圖片上傳到網站的Activity應該啟動服務來執行上傳,這樣一來,即使用戶退出Activity,仍可在後台繼續執行上傳操作。使用服務可以保證,無論Activity發生什麼情況,該操作至少具備「服務進程」優先順序。如果某個Activity開啟了線程執行耗時操作,當Activity退出時,該Activity的實例將不會釋放內存資源,直到線程執行完,這樣容易導致內存泄漏。同理,廣播接收器也應該使用服務,而不是簡單地將耗時冗長的操作放入線程中。
四、進程移除順序的依據——閾(yu,第四聲)值
前面講到,內存不夠用時,會根據進程的等級來決定優先回收哪類進程。那麼系統是根據什麼來判斷需要移除這些進程的時機的呢?答案是閾值。
1、查看閾值
我們可以採用如下方法查看手機中各個等級進程的閾值(需要root許可權),如第二排數據所示(其單位為頁):
以第一個數據44032為例,計算方法為:
1page=4KB=4*1024B=4096B
44032page* 4048B/page = 180355072B
180355072B/1024/1024 = 172M
即第一個等級的進程的閾值為172M。依次類推,閾值依次為:172M,190M,208M,226M,316M,415M。
有必要說明一下,在Android開發者官方文檔中,是將Android應用進程分為了5個等級,但很多資料卻是分的6個等級,在後台進程和空進程之間還有一個「內容提供節點(content provider)進程」。內容提供節點,沒有實體程序,僅提供內容供別的程序去用 ,比如日歷供應節點,郵件供應節點等,在終止進程時,這類進程有比較高的優先權。手機中應該是採用的6個等級的方式,如上六個數據,正好對應著六個等級的進程,等級越高,閾值越低,即前台進程閾值為172M,空進程為415M。當系統的剩餘內存只剩餘不到415M的時候,系統首先會回收空進程,依次類推,只有剩餘內存不到172M了,才會去回收前台進程,這樣就起到了優化保護重要進程的作用。
五、Home鍵、Back鍵和多任務鍵
Home鍵、Back鍵和多任務鍵,在手機屏幕的下方,這三個按鍵一般稱為導航欄,中間的按鈕為Home鍵,多任務鍵和Back鍵分別在其左右,一般根據手機品牌不同,左右位置也有所差異。
在運行App的時候,如果按一下Home鍵或者Back鍵,都可以退到桌面,那麼這兩者有什麼區別呢?
Home鍵。按Home鍵的時候,App如果沒有Service開啟,會從一個前台進程轉變為一個後台進程;如果有前台service運行,就仍然是前台進程,比如QQ音樂播放器等;如果是只有普通service運行,那麼就轉變為服務進程(參照前文中講的Android進程的5個級別)。
Back鍵。按Back鍵的時候,App如果沒有Service開啟,會從一個前台進程轉變為一個空進程;對於有Service運行的情況,和按Home鍵一樣。
後台進程和空進程,都是駐留在後台,處於暫停狀態,也都是除了佔用一部分內存外,不佔用其他如cpu等資源的,那麼問題來了,為什麼要設計後台進程和空進程這兩種空進程呢?它們的區別到底在哪裡呢?我們在前文講Android進程的5個等級的時候講到過,當剩餘內存不足的時候,系統會按照等級順序,優先移除不太重要進程,以收回內存供更重要的進程運行。那麼,它們的區別就是,在剩餘內存不足時,會優先移除空進程,再不足,才會移除空進程。所以,如果確實要退出某個應用一段時間內不大使用了,如果這款應用有退出按鈕,就用應用自帶的退出功能;如果沒有,則最好按系統的Back鍵,這樣可以變成空進程,當系統要回收內存時,就會優先被回收,從而釋放的所佔的資源。如果只是暫時退出去做點別的,過一會還要切換回來,或者對這款應用使用比較頻繁,那就使用Home鍵,因為相比於按Back鍵,這樣可以盡可能保住後台進程,方便下次使用的時候快速啟動。
當然,按Home鍵或Back鍵,對用戶來說,其實感覺不到差異,使用起來沒什麼兩樣,但是,對於Android開發者來說,卻有必要作為常識來了解其中的道理和差異。無論是按Home鍵還是按Back鍵,在按多任務鍵的時候,都可以看到這些進程,如下圖所示。最下面的按鍵為清理按鍵,點擊後可以清除掉這些進程,回收內存了,當然,前面也講了很多遍了,不建議這樣做。
2、修改閾值。
可以採用命令:echo "44032,48640,53248,57856,80896,106241" > /sys/mole/lowmemorykiller/parameters/minfree來修改閾值,如下所示:
重啟後,會恢復為原來的值。至於如何永久性修改該閾值,這里不深入探討,有興趣的童鞋可以自行研究,一般來說,就按照系統給定的默認值使用就可以了,沒特殊用途的話,沒必要修改。
對於這一節閾值的內容,暫時先講到這里,如果要更深入,可以自行多研究研究。筆者也沒有看到比較好的更深入的文章,所以也不好推薦,如果讀者看到比較好的,可以推薦給筆者,感激不盡。
六、開發者選項中的進程管理功能
Android手機都帶有開發者選項,隱藏了很多功能,顧名思義,這些功能主要用於輔助開發者調試程序用的。其中有一些就是關於進程管理功能的,筆者這里簡單介紹一下其中兩款,如下圖紅框部分所示:
不保留活動。用戶離開以後即銷毀每個活動(Activity),這樣做使得後台進程都被銷毀了。筆者試驗過幾款app,比如微信,瀏覽器,開啟/關閉「不保留活動」前後,按Home鍵後,再打開應用,有明顯的差別。當然,也試用了簡訊,DD打車,就沒看出起了什麼作用。讀者若是感興趣可以深入研究研究,到時候在指導指導筆者!
後台進程限制。如下圖所示,給出了後台進程個數限制的選項。
七、進程管理軟體的使用
Windows操作系統用戶往往總想著保留更多的內存,在使用Android手機的時候,喜歡經常清理後台進程或空進程,而且清理完後,心裡有一種特別爽的感覺,就像給家裡做了一次大掃除一樣,筆者最初使用Android手機的時候也是這樣的心態-_-!基於這樣的心態,一些進程清理軟體,很受普通用戶的青睞。其實這樣做卻正好抹殺了Android系統所標榜的優勢,如前文所講到的。
那麼進程管理軟體有無必要呢?當然有的,只是需要注意使用場合。當需要運行大型程序的時候,可以手動關閉掉一些進程,騰出足夠的空間供大型程序使用,這樣就可以有效避免系統調用進程調度策略而引起的卡頓,這一點,第八大點第3小節中會有說明。而且由於開發者的原因,可能是程序寫得太爛,或程序容易出錯,或做不該做的動作,或是惡意程序,對於這類程序進程,手動移除也是有好處的。
但如果是運行一些小程序,就完全沒有必要去預先殺進程了,完全可以交給系統自己管理。讀者可能會疑惑,因為小程序啟動的時候,也有可能會因為內存不足而導致需要移除部分進程的情況。筆者認為,即便是內存不足,小程序運行引起的調用進程調度策略測的次數非常少,要移除的進程也非常少,產生的影響不大。同時,我們也要意識到另外一點就是,無論是手動殺死進程還是自動殺進程,都需要cpu去執行這些任務,所以也會拖慢手機和消耗電量。所以從這一點看,頻繁殺進程,也是一個不好的習慣。
八、答疑解惑
在以前沒有專門去了解Android進程管理機制的時候,甚至是在研究的過程中,筆者心裡都經常存在很多疑惑,以下整理了其中5個,不知道讀者您是否有也類似的困惑呢?
1、這么多駐留在內存的進程,不會耗電嗎?
大多數用慣了Windows操作系統的童鞋,看到Android系統盡可能保留不在活動的進程的設計,可能第一反應就是質疑,難道這樣不會增加耗電量嗎?其實,但一個程序按home鍵變成後台進程或者按back鍵退出變成空進程後,其實已經被暫停了,只保留了運行狀態,不會消耗cpu,一個程序會耗電,是因為它需要調用cpu來運算,現在不消耗cpu了,當然就不會耗電了。當然,開了service的應用就另當別論了,比如QQ音樂播放器,當按home鍵或back鍵後,音樂仍然播放,是因為它開啟了服務,而且是一個前台服務,在後面我們會繼續講到,此時它是一個前台進程,而不是後台進程或空進程。
2、為什麼一個不太app,運行時會佔用很大的內存呢?
我們經常會碰到這樣一種現象,一個只有20M的App,運行起來的時候,卻會耗掉100M以上的內存。一方面是,程序運行時為對象分配內存,另一方面,是Android虛擬機的原因。Android中的應用啟動的時候,系統都會給它開啟一個獨立的虛擬機,這樣做的好處是可以避免虛擬機崩潰導致整個系統崩潰,代價就是耗用更多的內存。
3、為什麼內存少的時候,運行大型程序會卡頓呢?
當剩餘內存不多時,打開大型程序,系統會觸發自身的進程調度策略,去移除一些等級比較低的進程來回收內存,以供大型程序運行。而這個進程調度策略在決定哪些進程需要被移除的過程,是一個十分消耗資源的操作,特別是一個程序頻繁像系統申內存的時候,這樣就導致了系統的卡頓。
4、應用開得太多了,手機變慢,是因為內存被佔用太多嗎?
其實手機變慢的根本原因是cpu被耗用太多,而不是內存佔用太多,因為真正執行程序所要完成的任務的最終執行者是CPU,而不是內存(RAM)。在內存足夠的情況下,如果系統中佔用cpu的進程太多,那無疑cpu總有忙不過來的時候,那肯定就會變慢了。這就好比,在一條道路上駕車,道路就像內存,車的引擎就像cpu,如果車的引擎的動力不夠,或者承載的貨物太多,車都跑不快,即便是道路上一路暢通無阻,也無濟於事。所以,內存佔用多少並不重要,只要道路提供給車輛前行的空間是足夠的,手機變慢的責任,就和內存無關了。這個比喻用來解釋第三點也很恰當,道路提供的車輛前進的空間無法滿足車輛所必需的空間時,就需要交通機制花時間來調節交通,給這輛車提供足夠的空間,而在此期間,這輛車只能乖乖候著。
5、Android手機越用越慢,是什麼原因呢?
Android手機常常是越用越慢,即使是恢復出廠設置,也無法改變這個現象。手機越用越慢,主要由如下幾個原因:(1)虛擬機機制問題。這一點在上一個問題中也提到了,在Android4.4以前的系統,使用的是Dalvik虛擬機,它的設計機制有缺陷,就是越用越慢;在Android4.4系統中有切換按鈕,可以在Art虛擬機和Dalvik虛擬機之間切換;在Android4.4以後的系統就徹底拋棄了Dalvik而全面使用Art。(2)開啟了太多的服務,導致耗用太多的CPU。隨著手機開機使用時間的增長,應用使用越來越多,很多應用看似退出了,而其實後台可能開了不少的服務,而他們可能還沒有關閉。這些服務正在執行一些操作,會消耗CPU,而CPU才是手機變慢的根本原因。 而且Android app比較開放的,有很多不良應用充斥其中,可能對服務處理不當,濫用服務等,增加系統中的服務。(3)系統頻繁調用自身的進程調度演算法。這一點在前面已經說明了,這里不再贅述。(4)手機硬體的自然老化
❷ Android進程和線程的區別
Android進程和線程的區別
下面我先介紹下Android進程和線程各是什麼,然後再一一比較區別下
Android進程基本知識:
當一個程序第一次啟動的時候,Android會啟動一個LINUX進程和一個主線程。默認的情況下,所有該程序的組件都將在該進程和線程中運行。 同時,Android會為每個應用程序分配一個單獨的LINUX用戶。Android會盡量保留一個正在運行進程,只在內存資源出現不足時,Android會嘗試停止一些進程從而釋放足夠的資源給其他新的進程使用, 也能保證用戶正在訪問的當前進程有足夠的資源去及時地響應用戶的事件。
我們可以將一些組件運行在其他進程中,並且可以為任意的進程添加線程。組件運行在哪個進程中是在manifest文件里設置的,其中<Activity>,<Service>,<receiver>和<provider>都有一個process屬性來指定該組件運行在哪個進程之中。我們可以設置這個屬性,使得每個組件運行在它們自己的進程中,或是幾個組件共同享用一個進程,或是不共同享用。<application>元素也有一個process屬性,用來指定所有的組件的默認屬性。
Android中的所有組件都在指定的進程中的主線程中實例化的,對組件的系統調用也是由主線程發出的。每個實例不會建立新的線程。對系統調用進行響應的方法——例如負責執行用戶動作的View.onKeyDown()和組件的生命周期函數——都是運行在這個主線程中的。這意味著當系統調用這個組件時,這個組件不能長時間的阻塞主線程。例如進行網路操作時或是更新UI時,如果運行時間較長,就不能直接在主線程中運行,因為這樣會阻塞這個進程中其他的組件,我們可以將這樣的組件分配到新建的線程中或是其他的線程中運行。
Android會根據進程中運行的組件類別以及組件的狀態來判斷該進程的重要性,Android會首先停止那些不重要的進程。按照重要性從高到低一共有五個級別:
1.1前台進程
前台進程是用戶當前正在使用的進程。只有一些前台進程可以在任何時候都存在。他們是最後一個被結束的,當內存低到根本連他們都不能運行的時候。一般來說, 在這種情況下,設備會進行內存調度,中止一些前台進程來保持對用戶交互的響應。
1.2可見進程
可見進程不包含前台的組件但是會在屏幕上顯示一個可見的進程是的重要程度很高,除非前台進程需要獲取它的資源,不然不會被中止。
1.3服務進程
運行著一個通過startService() 方法啟動的service,這個service不屬於上面提到的2種更高重要性的。service所在的進程雖然對用戶不是直接可見的,但是他們執行了用戶非常關注的任務(比如播放mp3,從網路下載數據)。只要前台進程和可見進程有足夠的內存,系統不會回收他們。
1.4後台進程
運行著一個對用戶不可見的activity(調用過 onStop() 方法).這些進程對用戶體驗沒有直接的影響,可以在服務進程、可見進程、前台進 程需要內存的時候回收。通常,系統中會有很多不可見進程在運行,他們被保存在LRU (least recently used) 列表中,以便內存不足的時候被第一時間回收。如果一個activity正 確的執行了它的生命周期,關閉這個進程對於用戶體驗沒有太大的影響。
1.5空進程
未運行任何程序組件。運行這些進程的唯一原因是作為一個緩存,縮短下次程序需要重新使用的啟動時間。系統經常中止這些進程,這樣可以調節程序緩存和系統緩存的平衡。
單線程模型
線程在代碼是使用標準的java Thread對象來建立,那麼在Android系統中提供了一系列方便的類來管理線程——Looper用來在一個線程中執行消息循環,Handler用來處理消息,HandlerThread創建帶有消息循環的線程。具體可以看下面的詳細介紹。
當一個程序第一次啟動時,Android會同時啟動一個對應的主線程(Main Thread),主線程主要負責處理與UI相關的事件,如用戶的按鍵事件,用戶接觸屏幕的事件以及屏幕繪圖事件,並把相關的事件分發到對應的組件進行處理。所以主線程通常又被叫做UI線程。
在開發Android應用時必須遵守單線程模型的原則: Android UI操作並不是線程安全的並且這些操作必須在UI線程中執行。
2.1 子線程更新UI Android的UI是單線程(Single-threaded)的。
為了避免拖住GUI,一些較費時的對象應該交給獨立的線程去執行。如果幕後的線程來執行UI對象,Android就會發出錯誤訊息 。以後遇到這樣的異常拋出時就要知道怎麼回事了!
2.2 Message Queue
在單線程模型下,為了解決類似的問題,Android設計了一個Message Queue(消息隊列), 線程間可以通過該Message Queue並結合Handler和Looper組件進行信息交換。下面將對它們進行分別介紹:
2..3 Message 消息
理解為線程間交流的信息,處理數據後台線程需要更新UI,則發送Message內含一些數據給UI線程。
2.4. Handler 處理者
是Message的主要處理者,負責Message的發送,Message內容的執行處理。後台線程就是通過傳進來的Handler對象引用來sendMessage(Message)。而使用Handler,需要implement 該類的 handleMessage(Message) 方法,它是處理這些Message的操作內容,例如Update UI。通常需要子類化Handler來實現handleMessage方法。
2.5. Message Queue 消息隊列
用來存放通過Handler發布的消息,按照先進先出執行。 每個message queue都會有一個對應的Handler。Handler會向message queue通過兩種方法發送消息:sendMessage或post。這兩種消息都會插在message queue隊尾並按先進先出執行。但通過這兩種方法發送的消息執行的方式略有不同:通過sendMessage發送的是一個message對象,會被Handler的handleMessage()函數處理;而通過post方法發送的是一個runnable對象,則會自己執行。
2.6 Looper Looper是每條線程里的Message Queue的管家。
Android沒有Global的Message Queue,而Android會自動替主線程(UI線程)建立Message Queue,但在子線程里並沒有建立Message Queue。所以調用Looper.getMainLooper()得到的主線程的Looper不為NULL,但調用Looper.myLooper()得到當前線程的Looper就有可能為NULL。
從以上幾點,不難看出Android進程和線程的二者的區別所在。
❸ android啟動後怎麼查看其裡面的進程和線程
1)一個 Android 程序開始運行時,會單獨啟動一個Process。
默認情況下,所有這個程序中的Activity或者Service都會跑在這個Process。
默認情況下,一個Android程序也只有一個Process,但一個Process下卻可以有許多個Thread。
2)一個 Android 程序開始運行時,就有一個主線程Main Thread被創建。該線程主要負責UI界面的顯示、更新和控制項交互,所以又叫UI Thread。
3)一個Android程序創建之初,一個Process呈現的是單線程模型--即MainThread,所有的任務都在一個線程中運行,所以,MainThread所調用的每一個函數,其耗時應該越短越好,而對於比較耗時的工作,應該交給子線程去做,以避免主線程(UI線程)被阻塞,導致程序出現ANR(Application not response)
一個Activity就運行在一個線程中嗎?或者編碼時,如果不是明確安排在不同線程中的兩個Activity,其就都是在同一個線程中?那從一個Activity跳轉到另一個Activity時,是不是跳出的那個Activity就處在睡眠狀態了?
【答】 每個Activity都有一個Process屬性,可以指定該Activity是屬於哪個進程的。當然如果不明確指明,應該就是從屬於默認進程(Application指定的,如其未指定,應該就是默認主進程)。
Android中有Task的概念,而同一個Task的各個Activity會形成一個棧,只有站定的Activity才有機會與用戶交互。
原文地址:Android中的進程與線程 原文作者:江鵬
當應用程序的組件第一次運行時,Android將啟動一個只有一個執行線程的Linux進程。默認,應用程序所有的組件運行在這個進程和線程中。然而,你可以安排組件運行在其他進程中,且你可以為進程衍生出其它線程。本文從下面幾點來介紹Android的進程與線程:
1、進程
組件運行於哪個進程中由清單文件控制。組件元素——<activity>、<service>、<receiver>、<provider>,都有一個process屬性可以指定組件運行在哪個進程中。這個屬性可以設置為每個組件運行在自己的進程中,或者某些組件共享一個進程而其他的不共享。他們還可以設置為不同應用程序的組件運行在同一個進程中——假設這些應用程序共享同一個Linux用戶ID且被分配了同樣的許可權。<application>元素也有process屬性,為所有的組件設置一個默認值。
所有的組件都在特定進程的主線程中實例化,且系統調用組件是由主線程派遣。不會為每個實例創建單獨的線程,因此,對應這些調用的方法——諸如View.onKeyDown()報告用用戶的行為和生命周期通知,總是運行在進程的主線程中。這意味著,沒有組件當被系統調用時應該執行很長時間或阻塞操作(如網路操作或循環計算),因為這將阻塞進程中的其它組件。你可以為長操作衍生獨立的線程。
public boolean onKeyDown(int keyCode,KeyEvent event):默認實現KeyEvent.Callback.onKeyMultiple(),當按下視圖的KEYCODE_DPAD_CENTER或KEYCODE_ENTER然後釋放時執行,如果視圖可用且可點擊。
參數
keyCode-表示按鈕被按下的鍵碼,來自KeyEvent
event-定義了按鈕動作的KeyEvent對象
返回值
如果你處理事件,返回true;如果你想下一個接收者處理事件,返回false。
當內存剩餘較小且其它進程請求較大內存並需要立即分配,Android要回收某些進程,進程中的應用程序組件會被銷毀。當他們再次運行時,會重新開始一個進程。
當決定終結哪個進程時,Android會權衡他們對用戶重要性的相對權值。例如,與運行在屏幕可見的活動進程相比(前台進程),它更容易關閉一個進程,它的活動在屏幕是不可見(後台進程)。決定是否終結進程,取決於運行在進程中的組件狀態。關於組件的狀態,將在後面一篇——組件生命周期中介紹。
2、線程
雖然你可能會將你的應用程序限制在一個進程中,但有時候你會需要衍生一個線程做一些後台工作。因為用戶界面必須很快地響應用戶的操作,所以活動寄宿的線程不應該做一些耗時的操作如網路下載。任何不可能在短時間完成的操作應該分配到別的線程。
線程在代碼中是用標準的Java線程對象創建的,Android提供了一些方便的類來管理線程——Looper用於在線程中運行消息循環、Handler用戶處理消息、HandlerThread用戶設置一個消息循環的線程。
Looper類
該類用戶在線程中運行消息循環。線程默認沒有消息循環,可以在線程中調用prepare()創建一個運行循環;然後調用loop()處理消息直到循環結束。大部分消息循環交互是通過Handler類。下面是一個典型的執行一個Looper線程的例子,分別使用prepare()和loop()創建一個初始的Handler與Looper交互:
1. Android中進程與進程、線程與線程之間如何通信?
1)一個 Android 程序開始運行時,會單獨啟動一個Process。
默認情況下,所有這個程序中的Activity或者Service都會跑在這個Process。
默認情況下,一個Android程序也只有一個Process,但一個Process下卻可以有許多個Thread。
2)一個 Android 程序開始運行時,就有一個主線程Main Thread被創建。該線程主要負責UI界面的顯示、更新和控制項交互,所以又叫UI Thread。
3)一個Android程序創建之初,一個Process呈現的是單線程模型--即MainThread,所有的任務都在一個線程中運行,所以,MainThread所調用的每一個函數,其耗時應該越短越好,而對於比較耗時的工作,應該交給子線程去做,以避免主線程(UI線程)被阻塞,導致程序出現ANR(Application not response)
一個Activity就運行在一個線程中嗎?或者編碼時,如果不是明確安排在不同線程中的兩個Activity,其就都是在同一個線程中?那從一個Activity跳轉到另一個Activity時,是不是跳出的那個Activity就處在睡眠狀態了?
【答】 每個Activity都有一個Process屬性,可以指定該Activity是屬於哪個進程的。當然如果不明確指明,應該就是從屬於默認進程(Application指定的,如其未指定,應該就是默認主進程)。
Android中有Task的概念,而同一個Task的各個Activity會形成一個棧,只有站定的Activity才有機會與用戶交互。
原文地址:Android中的進程與線程 原文作者:江鵬
當應用程序的組件第一次運行時,Android將啟動一個只有一個執行線程的Linux進程。默認,應用程序所有的組件運行在這個進程和線程中。然而,你可以安排組件運行在其他進程中,且你可以為進程衍生出其它線程。本文從下面幾點來介紹Android的進程與線程:
1、進程
組件運行於哪個進程中由清單文件控制。組件元素——<activity>、<service>、<receiver>、<provider>,都有一個process屬性可以指定組件運行在哪個進程中。這個屬性可以設置為每個組件運行在自己的進程中,或者某些組件共享一個進程而其他的不共享。他們還可以設置為不同應用程序的組件運行在同一個進程中——假設這些應用程序共享同一個Linux用戶ID且被分配了同樣的許可權。<application>元素也有process屬性,為所有的組件設置一個默認值。
所有的組件都在特定進程的主線程中實例化,且系統調用組件是由主線程派遣。不會為每個實例創建單獨的線程,因此,對應這些調用的方法——諸如View.onKeyDown()報告用用戶的行為和生命周期通知,總是運行在進程的主線程中。這意味著,沒有組件當被系統調用時應該執行很長時間或阻塞操作(如網路操作或循環計算),因為這將阻塞進程中的其它組件。你可以為長操作衍生獨立的線程。
public boolean onKeyDown(int keyCode,KeyEvent event):默認實現KeyEvent.Callback.onKeyMultiple(),當按下視圖的KEYCODE_DPAD_CENTER或KEYCODE_ENTER然後釋放時執行,如果視圖可用且可點擊。
參數
keyCode-表示按鈕被按下的鍵碼,來自KeyEvent
event-定義了按鈕動作的KeyEvent對象
返回值
如果你處理事件,返回true;如果你想下一個接收者處理事件,返回false。
當內存剩餘較小且其它進程請求較大內存並需要立即分配,Android要回收某些進程,進程中的應用程序組件會被銷毀。當他們再次運行時,會重新開始一個進程。
當決定終結哪個進程時,Android會權衡他們對用戶重要性的相對權值。例如,與運行在屏幕可見的活動進程相比(前台進程),它更容易關閉一個進程,它的活動在屏幕是不可見(後台進程)。決定是否終結進程,取決於運行在進程中的組件狀態。關於組件的狀態,將在後面一篇——組件生命周期中介紹。
2、線程
雖然你可能會將你的應用程序限制在一個進程中,但有時候你會需要衍生一個線程做一些後台工作。因為用戶界面必須很快地響應用戶的操作,所以活動寄宿的線程不應該做一些耗時的操作如網路下載。任何不可能在短時間完成的操作應該分配到別的線程。
線程在代碼中是用標準的Java線程對象創建的,Android提供了一些方便的類來管理線程——Looper用於在線程中運行消息循環、Handler用戶處理消息、HandlerThread用戶設置一個消息循環的線程。
Looper類
該類用戶在線程中運行消息循環。線程默認沒有消息循環,可以在線程中調用prepare()創建一個運行循環;然後調用loop()處理消息直到循環結束。大部分消息循環交互是通過Handler類。下面是一個典型的執行一個Looper線程的例子,分別使用prepare()和loop()創建一個初始的Handler與Looper交互:
2.1、遠程過程調用(Remote procere calls,RPCs)
Android有一個輕量級的遠程過程調用機制——方法在本地調用卻在遠程(另外一個進程中)執行,結果返回給調用者。這需要將方法調用和它伴隨的數據分解為操作系統能夠理解的層次,從本地進程和地址空間傳輸到遠程進程和地址空間,並重新組裝調用。返回值以相反方向傳輸。Android提供了做這些工作的所有代碼,這樣我們可以專注於定義和執行RPC介面本身。
一個RPC介面僅包含方法。所有的方法同步地執行(本地方法阻塞直到遠程方法執行完成),即使是沒有返回值。簡言之,該機制工作原理如下:首先,你用簡單的IDL(interface definition language,介面定義語言)聲明一個你想實現的RPC介面。從這個聲明中,aidl工具生成一個Java介面定義,提供給本地和遠程進程。它包含兩個內部類,如下圖所示:
內部類有管理你用IDL定義的介面的遠程過程調用所需要的所有代碼。這兩個內部類都實現了IBinder介面。其中之一就是在本地由系統內部使用,你寫代碼可以忽略它。另外一個是Stub,擴展自Binder類。除了用於有效地IPC(interprocess communication)調用的內部代碼,內部類在RPC介面聲明中還包含方法聲明。你可以定義Stub的子類實現這些方法,如圖中所示。
通常情況下,遠程過程有一個服務管理(因為服務能通知系統關於進程和它連接的其它進程的信息)。它有由aidl工具生成的介面文件和Stub子類實現的RPC方法。服務的客戶端僅有由aidl工具生成的介面文件。
下面介紹服務如何與它的客戶端建立連接:
· 服務的客戶端(在本地端的)應該實現onServiceConnected() 和onServiceDisconnected() 方法,因此當與遠程服務建立連接成功和斷開連接是會通知它。然後調用bindService() 建立連接。
· 服務的onBind()方法將實現為接受或拒絕連接,者取決於它接受到的意圖(該意圖傳送到binServive())。如果連接被接受,它返回一個Stub子類的實例。
· 如果服務接受連接,Android調用客戶端的onServiceConnected()方法且傳遞給它一個IBinder對象,返回由服務管理的Stub子類的一個代理。通過代理,客戶端可以調用遠程服務。
這里只是簡單地描述,省略了一些RPC機制的細節。你可以查閱相關資料或繼續關注Android開發之旅,後面將為你奉上。
2.2、線程安全方法
在一些情況下,你實現的方法可能會被不止一個線程調用,因此必須寫成線程安全的。這對遠程調用方法是正確的——如上一節討論的RPC機制。當從IBinder進程中調用一個IBinder對象中實現的一個方法,這個方法在調用者的線程中執行。然而,當從別的進程中調用,方法將在Android維護的IBinder進程中的線程池中選擇一個執行,它不在進程的主線程中執行。例如,一個服務的onBind()方法在服務進程的主線程中被調用,在onBind()返回的對象中執行的方法(例如,實現RPC方法的Stub子類)將在線程池中被調用。由於服務可以有一個以上的客戶端,所以同時可以有一個以上的線程在執行同一個IBinder方法。因此,IBinder的方法必須是線程安全的。
同樣,一個內容提供者可以接受其它進程產生的數據請求。雖然ContentResolver 和 ContentProvider 類隱藏進程通信如何管理的,對應哪些請求的ContentResolver 方法——query()、insert()、delete()、update()、getType(),在內容提供者的進程的線程池中被調用,而不是在這一進程的主線程中。因為這些方法可以同時從任意數量的線程中調用,他們也必須實現為線程安全的。
❹ 如何讓Android service進程變成前台進程
這里只是修改了Service中onCreate()方法的代碼。可以看到,我們首先創建了一個Notification對象,然後調用了它的setLatestEventInfo()方法來為通知初始化布局和數據,並在這里設置了點擊通知後就打開MainActivity。然後調用startForeground()方法就可以讓MyService變成一個前台Service,並會將通知的圖片顯示出來。
現在重新運行一下程序, Service就會以前台Service的模式啟動了,並且在系統狀態欄會彈出一個通欄圖標,下拉狀態欄後可以看到通知的詳細內容
❺ android後台服務保持,不被殺死
作者:閉關寫代碼
鏈接:https://www.hu.com/question/29826231/answer/71207109
來源:知乎
著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請註明出處。
強烈建議不要這么做,不僅僅從用戶角度考慮,作為Android開發者也有責任去維護Android的生態環境。現在很多Android開發工程師,主力機居然是iPhone而不是Android設備,感到相當悲哀。
從技術角度概括一下現在普遍的防殺方法
Service設置成START_STICKY,kill 後會被重啟(等待5秒左右),重傳Intent,保持與重啟前一樣
通過 startForeground將進程設置為前台進程,做前台服務,優先順序和前台應用一個級別,除非在系統內存非常缺,否則此進程不會被 kill
雙進程Service:讓2個進程互相保護,其中一個Service被清理後,另外沒被清理的進程可以立即重啟進程
QQ黑科技:在應用退到後台後,另起一個只有 1 像素的頁面停留在桌面上,讓自己保持前台狀態,保護自己不被後台清理工具殺死
在已經root的設備下,修改相應的許可權文件,將App偽裝成系統級的應用(Android4.0系列的一個漏洞,已經確認可行)
Android系統中當前進程(Process)fork出來的子進程,被系統認為是兩個不同的進程。當父進程被殺死的時候,子進程仍然可以存活,並不受影響。鑒於目前提到的在Android-Service層做雙守護都會失敗,我們可以fork出c進程,多進程守護。死循環在那檢查是否還存在,具體的思路如下(Android5.0以下可行)
用C編寫守護進程(即子進程),守護進程做的事情就是循環檢查目標進程是否存在,不存在則啟動它。
在NDK環境中將1中編寫的C代碼編譯打包成可執行文件(BUILD_EXECUTABLE)。
主進程啟動時將守護進程放入私有目錄下,賦予可執行許可權,啟動它即可。
聯系廠商,加入白名單
------------------------------------------------------
TIP: 面對各種流氓軟體後台常駐問題,建議使用「綠色守護」來解決,可是殺掉那些第三方清理工具難以清除的後台程序