2011-10-20 25 views
2

我正在閱讀這篇關於如何:correctly retain variable state in Android的文章,我想起我從來沒有得到一個很好的答案(在這裏找不到一個答案),爲什麼最好與Bundle爭鬥(這不是一個巨大的麻煩,但肯定有其侷限性),而不是總是有一個應用程序覆蓋在您的應用程序,並只存儲您的所有持久數據成員。是否存在泄漏風險?有沒有辦法可以意外釋放內存?我只是不清楚這一點......它似乎是對所有活動都完全可靠的「閣樓」,並且是存儲您擔心的任何事情的完美場所,可能會在用戶關閉設備或暫停時重置應用程序。爲什麼在使用應用程序時使用Bundle?

我錯了嗎?想要了解應用程序中真正的內存生命週期是什麼。


根據下面的答案,讓我擴展我的問題。

假設我有一個基於啓動時加載的XML文件行爲不同的應用程序。

具體來說,該應用程序是一個用戶信息收集應用程序,根據XML設置,它將遵循開放式的各種路徑(收集信息A,但不是J,並提供Survey P,然後是可選的PhotoTaking機會等)

理想情況下,我不必將這個行爲路徑的細節存儲在一個Bundle(god forbid)或一個數據庫(也是醜陋的,但不那麼)。我會加載XML,處理它,並讓應用程序保持該結構,以便我可以參考它以瞭解下一步該怎麼做。如果應用程序暫停並且應用程序被釋放,那麼它不是*檢查我的CustomFlow對象中的null(根據XML生成)並重新實例化它的麻煩。無論如何,這聽起來不會發生。這是一個很好的例子,其中應用程序是最好的工具嗎?

+0

鑑於你的描述我會完全支持你們的編輯同意。 –

+0

真棒,謝謝! –

+0

沒問題。就像這裏所有人強調的一樣,這取決於它如何被全部使用。您的示例非常棒,因爲它將運行時數據從運行時狀態移開,並允許組件根據該數據發起操作,而不是事件。 –

回答

4

一個問題,哪種方法更好很大程度上取決於你存儲什麼樣的信息,並需要獲得和誰(哪個部件,包等)需要訪問這些信息。此外,像launchModeconfigChanges這樣的設置會改變生命週期,可以幫助您確定哪種方法最適合您。首先,讓我注意到,我是擴展Application對象的一個​​巨大倡導者,並且經常擴展Application類,但是在上下文中將所有的東西都放在它的上下文中,因爲重要的是要明白在某些情況下它只是簡單的不利於。

在應用程序的生命週期中: Chubbard大多正確地聲明應用程序具有與Singleton組件相同的生命。儘管它們非常接近,但還是有一些細微的差別。應用程序本身作爲操作系統的單例處理,只要任何組件處於活動狀態,包括AppWidget(可能存在於另一個應用程序中)或ContentResolver中,它都處於活動狀態。

所有組件最終都會訪問同一個對象,即使它們位於多個任務或進程中。但是,這並不能保證永遠保持這種狀態(因爲應用程序並非實際上是一個Singleton),並且只能在Google Android中得到保證,而不是製造商被覆蓋的版本。這意味着某些事情應該在應用程序對象中小心處理。

Application對象不會死,除非所有的組件被殺害也是如此。但是,Android可以選擇殺死任何數量的組件。這意味着您永遠不能保證有一個Application對象,但是如果您的任何組件都處於活動狀態,則會有一個Application將其關聯到。

另一個好處約Application的是,它不extricably綁定到正在運行的組件。儘管如此,你的組件是綁定的,這使得它非常有用。

相近的應用程序對象避免:

  • 按ususal,避免靜電Context秒。實際上,通常情況下,您不應該在此存儲Context,因爲Application本身就是Context
  • 這裏的大多數方法都應該是靜態的,因爲不能保證得到相同的Application對象,即使它很可能。
  • 如果您覆蓋Application,則此處存儲的數據和方法類型將幫助您進一步確定是否需要製作Singleton組件。
  • Drawables及其衍生物是最有可能「泄漏」如果不是照顧,所以也建議它您避免引用Drawables這裏。
  • 運行狀態任何單個組件的狀態。這是因爲,您不能保證獲得相同的Application對象。此外,此處不存在Activity中發生的生命週期事件。

相近的(超過束)

Application是存儲必須的組件之間共享數據和方法的真棒的地方,特別是如果你有多個入口點的應用程序商店(多個組件可以啓動並從發射活動開始運行)。例如,在我的所有Application中,我放置了我的DEBUG標記和日誌代碼。

如果你有一個的ContentProvider或廣播接收器,這使得Application更加理想,因爲這些有小生命週期是不是「可再生能源」之類的ActivityAppWidgetProvider,現在可以訪問這些數據或方法。

首選項用於確定通常在多次運行中運行選項,因此這可以是一個很好的地方來處理您的SharedPreferences,例如,一個訪問而不是每個組件一個訪問。事實上,跨多次運行「堅持」的任何事情都很適合在這裏訪問。

最後,一個被忽視的優勢是你可以在這裏存儲和組織你的常量,而不必加載其他類或對象,因爲如果你的組件之一是Application,它總是運行。這對於意圖操作和異常消息以及其他類似常量類型特別有用。

需要在Bundle中存儲的東西而不是應用程序 運行時狀態取決於單個組件或單個組件運行的存在或狀態。另外,任何依賴於顯示狀態,方向或類似的Android服務的東西在這裏都是不可取的。這是因爲Application從未被通知過這些更改。最後,任何依賴Android系統通知的東西都不應該放在這裏,比如對生命週期事件的反應。

而且....別處

至於那需要保留的其他數據,你總是有數據庫,網絡服務器和文件系統。像你以往一樣使用它們。

作爲Application是有用的和被忽視的,一個很好的理解是重要的,因爲它是不理想的。希望這些說明能夠讓你對大師爲什麼鼓勵一種方式有所瞭解。瞭解許多開發人員都有類似的需求,大部分的指導都是基於大多數社區擁有的技術和知識。 Google所說的並不適用於所有程序員的需求,並且有理由認爲該應用程序未被宣佈爲Final

請記住,Android需要能夠殺死你的組件是有原因的。主要原因是內存,而不是處理。通過使用上述應用程序並開發適當的方法來保存適當的信息,您可以構建更強大的應用程序,以體貼系統,用戶,其兄弟組件和其他開發人員。利用這裏提供的每個人的信息應該給你一些關於如何以及何時擴展Application的很好的指導。

希望這有助於 FuzzicalLogic

+0

嗯,我必須對你最後一段提出投訴。我不會強迫記憶中的任何事情。我主張你爲應用程序所做的大部分工作,因爲它經常被忽視爲使工作更輕鬆的工具。與創建單身人士相比,這些單身人士會讓您的生活陷入可怕的依賴問題,並且無法直接參與生命週期。如果你的應用程序被收回,我沒有說可以阻止它發生。但是,我確實提供了一些不需要痛苦的對象 - >包映射來正確處理關閉的其他技巧。 – chubbsondubs

+0

是的,你做到了,我以各種方式主張你的帖子,除了你以後的評論之一是「這至少可以讓你的對象在你的應用程序中保持99%的時間。」我甚至提出了你的答案,因爲我只是一個闡述你的答案。尋找把對象保存在內存中的技巧是很多開發人員所做的事情,可能會對Android造成不利影響。如果我以錯誤的方式採納了評論,我會道歉並且會進行適當的編輯,但您可能會考慮詳細闡述這一部分,以便其他人不會像我一樣。 –

+0

好吧我想我可以看到如何可能採取錯誤的方式。我會盡力澄清我的觀點,更好地說明爲什麼要有一個穩定的地方來放置你的對象,以幫助你的應用程序變得更好。 – chubbsondubs

3

我更喜歡子類應用程序,並指出我的清單。我認爲這是編碼android的理智方式,儘管Google的Android架構師認爲您應該使用Singletons(eek)來做到這一點。單身人士與應用程序具有相同的生命週期,所以適用於他們的所有東西都適用於應用程序,除了少得多的依賴性混亂單身人士創建。基本上他們甚至不使用捆綁包。我認爲使用子類Application已經大大加快了Android的編程速度,而且更少麻煩。

現在的缺點。如果手機需要更多內存或應用程序進入後臺,應用程序可能會關閉。這可能意味着用戶接聽了電話或查看了他們的電子郵件。例如,假設您有一個強制用戶登錄的活動,以獲取其他活動將用於進行服務器調用的令牌。這是你可能存儲在你的服務對象中的東西(不是android服務只是一個發送網絡調用到你的服務器的類),你存儲在你的Application的子類中。那麼,如果您的應用程序關閉,您將丟失該令牌,並且當用戶單擊後退按鈕時,您的用戶可能會返回到假設您已經通過身份驗證並且繁榮時您的服務類無法工作的活動。

那麼你能做什麼?繼續使用Bundle可怕?那麼你是否可以輕鬆地將安全令牌存儲到捆綁包中(儘管可能存在一些安全問題,具體取決於應用程序的工作方式),或者您必須編寫活動代碼以使其不承擔應用程序所處的特定狀態。必須檢查令牌的丟失情況,並在發生此情況時將用戶重定向回登錄屏幕。但是,取決於您的應用程序對象擁有多少狀態,這可能會非常棘手。但請記住,您的應用程序可以知道什麼時候它正在關閉,並將它的內部狀態保存到一個包中。 ,至少可以讓你保持你的對象在內存中的99%的時間你的應用程序,並且只保存/恢復時,它會關閉,而不是不斷的序列化,並與鍋爐板代碼反序列化,只要你活動 之間移動。通過使用應用程序,您可以集中管理和關閉程序,因爲它通常比任何一項活動的壽命都長,因此可以減少程序在用戶在活動之間移動時重新構建應用程序的內容的需求。通過從每個Activity中排除應用程序的詳細信息,可以使代碼更加清晰,如果您的應用程序已經構建,共享常見實例/代碼並減少開銷,並且可以在不丟失所有程序的情況下回收活動。所有優秀的程序都需要一個以核心爲中心的集中式中心,並且應用程序的子類化可以讓您參與Android生命週期。

我個人最喜歡的是使用http://flexjson.sourceforge.net/連載我的Java對象成束爲JSON,如果我需要各地發送對象或保存。當你需要做的只是保存數據時,比寫入sqlite數據庫容易得多。在使用對象而不是拆分原語的兩個活動之間發送數據時很好。

記住,通過在應用程序中集中您的模型,您可以創建一個在多個活動之間共享代碼的位置,這樣您就可以始終通過掛鉤onPause()將活動持久性委託給應用程序中的對象,並允許持久性位於中心。

+0

將序列化複雜對象的問題是......該行爲必須發生在主線程(當saveInstanceState)被調用時。我想你可以有一個AsyncTask構建JSON字符串,然後在完成時觸發新的意圖(對於開始新活動的情況)。我只是擔心在主線程上做了太多的啓動/關閉處理。 – haseman

+0

您可以隨時在另一個線程上將其推下,但大多數發送的對象只需要1-10ms。當然,如果你有很多可以節省的東西,你必須減輕這些負擔,但是更大的列表和複雜的對象卻是瘋狂的。衡量,衡量,衡量所有任務。 – chubbsondubs

+0

雖然可以將它推送到另一個線程,但不能退出該方法,並期望異步線程不會死亡。因此,你必須在線程上做一個wait(),那麼如果你阻塞了主線程而不是做實際的工作,那麼有什麼區別呢?如果你只是在主線程上執行它,那麼它是一個或更少的線程。 – chubbsondubs

2

簡短的回答是:使用捆綁,因爲它使保存狀態了,當你轉到後臺更容易。而且,它很複雜。

長的答案:

我的理解是,只要你活動的在onPause方法被調用(和的onSaveInstanceState它給你包在其中可以儲存您的活動的數據)的過程可能不會進一步警告被終止。之後,當用戶返回到您的應用程序時,您的活動將與該原始包進行onCreate調用,從中恢復其狀態。這將發生在您的原始堆棧的所有活動中。

能夠從捆(其Android將會爲你保存爲您的過程消失)恢復狀態的Android如何保持是多任務的神話。如果每次調用onSaveInstanceState時不會將活動的狀態轉儲到一個包中,那麼當用戶剛剛切換一秒鐘時,您的應用程序將看起來像已重新啓動。這可能是特別麻煩的當系統資源的限制,因爲該系統將需要更頻繁地殺死進程,以保持設備迅速

運行應用程序爲什麼可不好

應用程序不如果流程關閉,實際上有機會保存它的任何數據。它確實有一個onDestroy方法,但文檔會告訴你,這實際上永遠不會被系統在實際設備上調用。這意味着,在上面提到的受限情況下,如果流程結束,任何有關活動內部發生的事件(如果您已將其保存在應用程序中)的信息都將丟失。

開發者往往錯過這種情況下(它可以是非常惱人的用戶),因爲他們無論是開發手機,它永遠不會在同一時間使用多個應用程序打在運行。我們也從未使用該應用程序一段時間,然後切換到另一個應用程序,並在一段時間後,再次切換回來。

+0

可以在不調用onPause()的情況下調用onDestroy()。例如,如果調用finish(),則可能不調用onPause(),這取決於調用的方式和時間。這會影響你的代碼的可能性是零,通常情況下,完成()是在用戶或應用程序完成其任務完成時的活動。這就是說,這些都是偉大的一點,以及。 –

+0

沒錯,有些情況下onPause沒有被調用,但此時您不必關心緩存數據(因爲活動正在被刪除,而不是隱藏) – haseman

+0

老實說,這取決於程序員的實現。雖然我個人同意你的看法,但有些開發人員可能有專門的需求,所以需要添加聲明。 –

相關問題