在活动类的静态字段保证活得比一个创建/销毁周期?字段、活得、静态、周期

2023-09-03 20:32:30 作者:一见倾心

我经常碰到,我要preserve状态的活动的几个调用(即经过若干的onCreate()/ onDelete()周期)之间的问题。不幸的是,Android的做这种支持是真穷。

I frequently run into the problem that I have to preserve state between several invocations of an activity (i.e. going through several onCreate()/onDelete() cycles). Unfortunately, Android's support for doing that is really poor.

作为一种简单的方法,以preserve状态,我想,既然类是由类装载器只能加载一次,这将是安全的存储是一个活动的多个实例之间共享的静态捆绑临时数据场。

As an easy way to preserve state, I thought that since the class is only loaded once by the class loader, that it would be safe to store temporary data that's shared between several instances of an activity in a static Bundle field.

不过,有时候,当实例A创建其中的静态包和存储数据,然后被破坏,比如B试图从中读出,静电场突然空。

However, occasionally, when instance A creates the static bundle and stores data in it, then gets destroyed, and instance B tries to read from it, the static field is suddenly NULL.

难道这不是意味着该类已被删除,并由类加载器而活动正在经历一个创建/销毁周期重载?否则怎么可能一个的静态的领域,当它被引用前一个对象突然变得空?

Doesn't that mean that the class had been removed and reloaded by the classloader while the activity was going through a create/destroy cycle? How else could a static field suddenly become NULL when it was referencing an object before?

推荐答案

这个答案的第一部分是真的老了 - 请参阅下面的的右键的方式做到这一点

The first part of this answer is really old -- see below for the right way to do it

您可以使用Application对象存储应用程序的持久对象。 关于这个问题,以及这个Android的常见问题解答会谈。

You can use the Application object to store application persistent objects. This Android FAQ talks about this problem as well.

事情是这样的:

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();
    }
}

的右键的方法

The right way:

在第一次写这个答案,对于活动的生命周期的文档是不如现在。阅读节能活动状态上的活动文档部分帮助我们理解的Andr​​oid怎么想我们保存状态。本质上,有两种情况下使用的活动开始:(1),为新的活动和(2),因为结构的变化时,或者由于存储器pressure被毁坏后真实重新创建。当你的活动开始,因为它是一个新的活动,然后saveInstanceState为空。这不是否则返回null。如果是空,那么你的活动应该从头开始初始化。片段非常相似的活动,和我讨论这个概念在细节我 AnDevCon-14幻灯片平台。您还可以看看在样品code 我AnDevCon-14 presentation了解更多详情。

When this answer was first written, the documentation for the Activity lifecycle was not as good as it is now. Reading Saving Activity State section on the Activity document helps us understand how Android wants us to save state. Essentially, there are two circumstances under which your activity starts: (1) as a new activity and (2) because of a configuration change or when it's recreated after being destroyed due to memory pressure. When your activity starts because it's a new activity, then saveInstanceState is null. It's not null otherwise. If it's null, then your activity should initialize itself from scratch. Fragments are very similar to Activities, and I covered this concept in detail for my AnDevCon-14 slide deck. You can also take a look at the sample code for my AnDevCon-14 presentation for more details.

我的返工previous例子看起来像下面的code。我改变语义位 - 在该第二版本我假定字符串特定于酶活性的特定的 Android的任务,在previous例如它的含糊不清。如果你想保持相同的数据各地的多个机器人的任务,然后使用无论是应用程序对象或其他单依然是你最好的选择。

Reworking my previous example would look something like the code below. I do change the semantics a bit -- in this second version I assume the string thing is specific to the activity within a specific android task, in the previous example it's ambiguous. If you do want to keep the same data around for multiple android tasks, then using either the Application object or another singleton is still your best bet.

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);
    }
}