2009-10-28 61 views
14

我經常遇到問題,我必須在活動的幾次調用之間保持狀態(即經歷幾次onCreate()/ onDelete()循環)。不幸的是,Android對此的支持非常糟糕。Activity類中的靜態字段是否保證超出創建/銷燬循環?

作爲一種保存狀態的簡單方法,我認爲由於該類只能由類加載器加載一次,因此在靜態Bundle字段中存儲一個活動的多個實例之間共享的臨時數據是安全的。

但是,有時,實例A創建靜態包並在其中存儲數據,然後被銷燬,而實例B嘗試從它讀取,靜態字段突然爲NULL。

這並不意味着這個類在活動正在經歷一個創建/銷燬循環時已被類加載器移除和重新加載?如果一個靜態字段在之前引用一個對象時突然變爲NULL,該怎麼辦?

+0

不肯定的回答你的問題,但我知道的是,Android開發建議不要將你的靜態引用不必要的,因爲它們容易記憶泄漏:http://android-developers.blogspot.com/2009/01/avoiding-memory-leaks.html – I82Much 2009-10-28 13:25:29

+2

好吧,那篇文章是關於泄漏上下文。如果通過該靜態引用可以強烈地訪問上下文,則這只是一個問題,例如,意見,但不是捆綁(據我所知?)。但通常我會假設靜態引用,一旦類被加載,只要應用程序一直存在,這在Android中似乎不是真的。 – Matthias 2009-10-28 13:46:09

回答

13

這個答案的第一部分是真的老了 - 請參閱下面的正確辦法做到這一點

您可以使用Application對象存儲應用持久對象。 This Android FAQ也討論了這個問題。

事情是這樣的:

public class MyApplication extends Application{ 
    private String thing = null; 

    public String getThing(){ 
     return thing; 
    } 

    public void setThing(String thing){ 
     this.thing = thing; 
    } 
} 

public class MyActivity extends Activity { 
    private MyApplication app; 

    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 

     app = ((MyApplication)getApplication()); 

     String thing = app.getThing(); 
    } 
} 

正確方式

當第一次寫這個答案,對於活動的生命週期的文檔的情況不是很好,因爲它是現在。閱讀Saving Activity State關於Activity文檔的章節有助於我們理解Android如何讓我們保存狀態。從本質上講,您的活動開始有兩種情況:(1)作爲新活動;(2)由於配置更改或由於內存壓力而被重新創建時。當您的活動因爲是新活動而啓動時,則saveInstanceState爲空。否則它不爲空。如果它爲空,那麼你的活動應該從頭開始初始化自己。碎片與活動非常相似,我詳細介紹了我的AnDevCon-14 slide deck這個概念。您還可以查看我的AnDevCon-14演示文稿的sample code以獲取更多詳細信息。

重做我以前的例子看起來像下面的代碼。我確實改變了語義 - 在第二個版本中,我假設字符串thing是特定於android task內的活動,在前面的示例中它是不明確的。如果你確實想要爲多個android任務保留相同的數據,那麼使用Application對象或其他單例仍然是你最好的選擇。

public class MyActivity extends Activity { 
    private static final String THING = "THING"; 

    private String thing; 

    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 

     if (savedInstanceState==null) { 
      // First time here (since we last backed out at least) 
      thing = initializeThing(); // somehow we init it 
     } else { 
      // Rehydrate this new instance of the Activity 
      thing = savedInstanceState.getString(THING); 
     } 

     String thing = app.getThing(); 
    } 

    protected void onSaveInstanceState(Bundle outState) { 
     outState.putString(THING, thing); 
    } 
} 
+4

這實際上是一個非常好的和簡單的想法...只要它不變成神對象反模式 – Matthias 2009-10-29 09:57:23

+0

呵呵,我以前沒有聽說過神對象模式[1]。很有趣的東西。我可能應該說這只是一個簡單的例子。對於任何不僅僅是簡單的應用程序而言,您的應用程序類應該只包含其他對象來保存真實數據,而不是數據本身的存儲庫。這是Android中存儲其他對象的方便之處。 [1] http://en.wikipedia.org/wiki/God_object – JohnnyLambada 2009-10-29 16:31:19

+1

我正在擺脫修改Application類並轉向使用單例。請參閱Dianne Hackbod的答案:http://stackoverflow.com/questions/3826905/singletons-vs-application-context-in-android – JohnnyLambada 2011-05-04 20:53:02

0

另外,亦正亦邪,方式保持靜態數據是有你活動旋轉了一個單例類。這個單例會保持靜態的引用。

class EvilSingleton{ 
    private static EvilSingleton instance; 

    //put your data as non static variables here 

    public static EvilSingleton getInstance() 
    { 
     if(instance == null) 
      instance = new EvilSingleton(); 
     return instance; 
    } 
} 

在您的活動的onCreate()方法中,您可以訪問/構建單例和您可能需要的任何數據。這樣,您的活動或應用程序可以被破壞或重新創建任何次數,只要您的進程的內存空間被保留,您應該應該好。

這是一個邪惡的黑客顛覆,所以沒有承諾;-)

+2

謝謝,但不,謝謝。我對單身人士有足夠的樂趣。這是他們所有人中最被濫用的設計模式,在大多數情況下,我已經看到它被使用,它實際上是一種反模式。 – Matthias 2009-10-29 09:58:53

+0

夠公平的。這不是什麼模式,我在時間壓力很大的情況下使用它們,但我同意,在一個大型的,維護良好的項目中,它們應該在最好的情況下使用。 – haseman 2009-10-29 16:36:07

+0

爲了防禦Singleton,在Android中有一個很好的用例:SqliteOpenHelper實例。除此之外,我同意你們的看法。 – 2015-09-23 11:04:15

相關問題