androidactivity回收
① Android開發時,Activity被銷毀後,之前在裡面創建的線程情況
是還在運行的,java線程一旦開起來,很難銷毀。JVM有很好的管理機制,系統最後會自動釋放回收。作為手動回收來說,你可以調用interrupt 但是不是每次都起作用,有時候回收不了
② 如何管理Android中Activity的生命周期
管理Android中Activity的生命周期
在一個activity的生命周期中,系統會像金字塔模型一樣去調用一系列的生命周期回調函數。Activity生命周期的每一個階段就像金字塔中的台階。當系統創建了一個新的activity實例,每一個回調函數會向上一階移動activity狀態。處在金字塔頂端意味著當前activity處在前台並處於用戶可與其進行交互的狀態。
當用戶退出這個activity時,為了回收該activity,系統會調用其它方法來向下一階移動activity狀態。在某些情況下,activity會隱藏在金字塔下等待(例如當用戶切換到其他app),此時activity可以重新回到頂端(如果用戶回到這個activity)並恢復用戶離開時的狀態。
根據activity的復雜度,也許不需要實現所有的生命周期方法。但了解每一個方法的回調時機並在其中填充相應功能,使得確保app能夠像用戶期望的那樣執行是很有必要的。如何實現一個符合用戶期待的app,我們需要注意下面幾點:
使用app的時候,不會因為有來電通話或者切換到其他app而導致程序crash。
用戶沒有激活某個組件時不會消耗寶貴的系統資源。
離開app並且一段時間後返回,不會丟失用戶的使用進度。
設備發生屏幕旋轉時不會crash或者丟失用戶的使用進度。
只有三個狀態是靜態的,這三個狀態下activity可以存在一段比較長的時間。(其它幾個狀態會很快就切換掉,停留的時間比較短暫)
Resumed:該狀態下,activity處在前台,用戶可以與它進行交互。(通常也被理解為"running" 狀態)
Paused:該狀態下,activity的部分被另外一個activity所遮蓋:另外的activity來到前台,但是半透明的,不會覆蓋整個屏幕。被暫停的activity不再接受用戶的輸入且不再執行任何代碼。
Stopped:該狀態下, activity完全被隱藏,對用戶不可見。可以認為是在後台。當stopped, activity實例與它的所有狀態信息(如成員變數等)都會被保留,但activity不能執行任何代碼。
③ Android技術分享|Android 中部分內存泄漏示例及解決方案
內存泄漏:
舉例:
請注意以下的例子是虛構的
內存抖動
源自Android文檔中的 Memory churn 一詞,中文翻譯為內存抖動。
指快速頻繁的創建對象從而產生的性能問題。
引用Android文檔原文:
Java內存泄漏的根本原因是 長生命周期 的對象持有 短生命周期 對象的引用就很可能發生內存泄漏。
盡管短生命周期對象已經不再需要,但因為長生命周期依舊持有它的引用,故不能被回收而導致內存泄漏。
靜態集合類引起的內存泄漏
如果僅僅釋放引用本身(tO = null), ArrayList 依然在引用該對象,GC無法回收。
監聽器
在Java應用中,通常會用到很多監聽器,一般通過 addXXXXListener() 實現。但釋放對象時通常會忘記刪除監聽器,從而增加內存泄漏的風險。
各種連接
如資料庫連接、網路連接(Socket)和I/O連接。忘記顯式調用 close() 方法引起的內存泄漏。
內部類和外部模塊的引用
內部類的引用是很容易被遺忘的一種,一旦沒有釋放可能會導致一系列後續對象無法釋放。此外還要小心外部模塊不經意的引用,內部類是否提供相應的操作去除外部引用。
單例模式
由於單例的靜態特性,使其生命周期與應用的生命周期一樣長,一旦使用不恰當極易造成內存泄漏。如果單利持有外部引用,需要注意提供釋放方式,否則當外部對象無法被正常回收時,會進而導致內存泄漏。
集合類泄漏
如集合的使用范圍超過邏輯代碼的范圍,需要格外注意刪除機制是否完善可靠。比如由靜態屬性 static 指向的集合。
單利泄漏
以下為簡單邏輯代碼,只為舉例說明內存泄漏問題,不保證單利模式的可靠性。
AppManager 創建時需要傳入一個 Context ,這個 Context 的生命周期長短至關重要。
1. 如果傳入的是 Application 的 Context ,因為 Application 的生命周期等同於應用的生命周期,所以沒有任何問題。
2. 如果傳入的是 Activity 的 Context ,則需要考慮這個 Activity 是否在整個生命周期都不會被回收了,如果不是,則會造成內存泄漏。
非靜態內部類創建靜態實例造成的內存泄漏
應該將該內部類單獨封裝為一個單例來使用。
匿名內部類/非同步線程
Runnable都使用了匿名內部類,將持有MyActivity的引用。如果任務在Activity銷毀前未完成,將導致Activity的內存無法被回收,從而造成內存泄漏。
解決方法:將Runnable獨立出來或使用靜態內部類,可以避免因持有外部對象導致的內存泄漏。
Handler造成的內存泄漏
Handler屬於TLS(Thread Local Storage)變數,生命周期與Activity是不一致的,容易導致持有的對象無法正確被釋放
當Android應用程序啟動時,該應用程序的主線程會自動創建一個Looper對象和與之關聯的MessageQueue。
當主線程中實例化一個Handler對象後,它就會自動與主線程Looper的MessageQueue關聯起來。所有發送到MessageQueue的Messag都會持有Handler的引用,所以Looper會據此回調Handle的handleMessage()方法來處理消息。只要MessageQueue中有未處理的Message,Looper就會不斷的從中取出並交給Handler處理。
另外,主線程的Looper對象會伴隨該應用程序的整個生命周期。
在Java中,非靜態內部類和匿名類內部類都會潛在持有它們所屬的外部類的引用,但是靜態內部類卻不會。
當該 Activity 被 finish() 掉時,延遲執行任務的 Message 還會繼續存在於主線程中,它持有該 Activity 的 Handler 引用,所以此時 finish() 掉的 Activity 就不會被回收了從而造成內存泄漏(因 Handler 為非靜態內部類,它會持有外部類的引用,在這里就是指 SampleActivity)。
避免不必要的靜態成員變數
對於BroadcastReceiver、ContentObserver、File、Cursor、Stream、Bitmap等資源的使用,應在Activity銷毀前及時關閉或注銷。
不使用WebView對象時,應調用`destroy()`方法銷毀。
④ android:當Activity和Service 都被銷毀後,如何控制其中生成的線程
線程沒有被銷毀的,當Activity或者Service中還有活動線程的時候,垃圾回收器是不會回收銷毀Activity和Service對象的。舉個例子,你可以在Activity中啟動一個線程,在onDestroy中用System.out.print或者log輸出一個信息,然後通過按鈕調用finish方法,會發現點擊以後Activity會「關閉」,但只是不可見了,但是沒有調用onDestroy方法。除非你在onDestroy中關閉了線程才會關閉。
線程管理一般是通過一個布爾類型值保存其狀態,通過判斷它是否為空,一起來處理。這樣最簡單。
就是在onDestroy中處理的,你說沒有調用,是因為還有子線程在運行。在onDestroy中判斷線程狀態,正常關閉線程以後就行了。
⑤ Android如何不讓Activity銷毀
activity自動回收是有activity生命周期決定的,當activity退出或失去焦點(按home除外)後,就被銷毀了,activity不可後台運行,你不能改變。能後台運行的是services,broadcastreceiver。