2009-10-28 57 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

相关问题