在android上保持应用程序状态

在android上保持应用程序状态,android,Android,我在保存应用程序的状态/单例时遇到问题 当应用程序启动时,将显示一个加载屏幕(活动),并使用来自webservice调用的值初始化一个单例(请注意,网络访问不能在主线程上运行) 创建单例后,我打开我的主活动。请注意,构建布局需要来自单例的值 现在假设应用程序在后台运行,并在后台被终止(例如,由于内存不足)。我的singleton实例在应用程序被终止时被删除。当我切换回我的应用程序时,它会尝试重新创建主活动。正如我前面提到的,构建布局需要来自singleton的值,因此这会导致NullPointe

我在保存应用程序的状态/单例时遇到问题

当应用程序启动时,将显示一个加载屏幕(活动),并使用来自webservice调用的值初始化一个单例(请注意,网络访问不能在主线程上运行)

创建单例后,我打开我的主活动。请注意,构建布局需要来自单例的值

现在假设应用程序在后台运行,并在后台被终止(例如,由于内存不足)。我的singleton实例在应用程序被终止时被删除。当我切换回我的应用程序时,它会尝试重新创建主活动。正如我前面提到的,构建布局需要来自singleton的值,因此这会导致NullPointerException(当我尝试访问singleton的成员时,因为它不再存在)

我能告诉android在应用程序被杀后启动第一次加载活动吗?如果我可以在重新创建布局之前刷新singleton,那就太好了,但这似乎是一个问题,因为网络调用不能在主线程上,因此在刷新完成之前不会阻塞。 我假设我可以在上面的所有活动中保存单例并在onCreate方法中重新创建它,但这似乎有点不可预测,可能会导致不一致的状态

另一种方法可能是总是在桌面上完成我的活动,但这会导致丢失用户最后一个标签等等,即使应用程序没有被杀死,所以这不是一个好的选择


有没有办法解决这个问题

对于类似的东西,我使用伪singelton对象作为类。此对象将在开始时创建,并将保存在内存中。但请注意,如果其他应用程序需要内存,系统将终止该应用程序。然而,即使所有活动暂时终止,该对象也是持久的

要使用它,您需要在android清单中声明如下:

<application android:label="@string/app_name"
             android:icon="@drawable/icon"
             android:description="@string/desc"
             android:name=".MySingeltonClass"
             ...
这两个函数的调用方式如下:

((MySingeltonClass)getApplicationContext()).informClientOnline();

当在活动中被调用时,您可以保存您的Singleton。您所需要做的就是实现它(这是Androids自己的序列化形式),然后您可以将它放入活动中的
outState
捆绑包中
onSaveInstanceState()
,这将允许您在活动中的
onCreate()
onRestoreInstanceState()
中检索它,无论您喜欢哪种方式

我为您提供了一个示例:

public class TestActivity extends Activity {

    private MySingleton singleton;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if(savedInstanceState.containsKey("singleton")) {
            singleton = savedInstanceState.getParcelable("singleton");
        } else {
            singleton = MySingleton.getInstance(5);
        }
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putParcelable("singleton", singleton);
    }

    public static class MySingleton implements Parcelable {

        private static MySingleton instance;
        private int myData;

        private MySingleton(int data) {
            myData = data;
        }

        public static MySingleton getInstance(int initdata) {
            if(instance == null) {
                instance = new MySingleton(initdata);
            }

            return instance;
        }

        public static final Parcelable.Creator<MySingleton> CREATOR = new Creator<TestActivity.MySingleton>() {

            @Override
            public MySingleton[] newArray(int size) {
                return new MySingleton[size];
            }

            @Override
            public MySingleton createFromParcel(Parcel source) {
                return new MySingleton(source.readInt());
            }
        };

        @Override
        public int describeContents() {
            return 0;
        }

        @Override
        public void writeToParcel(Parcel parcel, int flags) {
            parcel.writeInt(myData);
        }

    }

}
公共类测试活动扩展活动{
私家侦探迈辛格尔顿·辛格尔顿;
@凌驾
创建时受保护的void(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
if(savedInstanceState.containsKey(“单例”)){
singleton=savedInstanceState.getParcelable(“singleton”);
}否则{
singleton=MySingleton.getInstance(5);
}
}
@凌驾
SaveInstanceState上受保护的无效(束超出状态){
super.onSaveInstanceState(超出状态);
突出。可放置(“单体”,单体);
}
公共静态类MySingleton实现了Parcelable{
私有静态MySingleton实例;
私有数据;
私人迈辛格尔顿(int数据){
myData=数据;
}
公共静态MySingleton getInstance(int initdata){
if(实例==null){
instance=new MySingleton(initdata);
}
返回实例;
}
公共静态最终包裹。创建者=新创建者(){
@凌驾
public MySingleton[]新数组(整数大小){
返回新的MySingleton[size];
}
@凌驾
公共MySingleton createFromParcel(地块源){
返回新的MySingleton(source.readInt());
}
};
@凌驾
公共int描述内容(){
返回0;
}
@凌驾
公共无效writeToParcel(Parcel-Parcel,int标志){
包裹写入(myData);
}
}
}

为什么不使用SharedReferences而不是singleton

任何时候,只要您想保存一些全局状态,就将其提交到首选项。只要您想读取全局状态,就可以从首选项中将其读回


这样,您就不必担心应用程序的生命周期,因为无论手机在做什么,您的数据都将始终被保留。

显示代码或至少是代码片段。同时显示“崩溃”的日志——我们不能确定你说的是否是“…导致崩溃…”。问题不是崩溃,问题是当应用程序在后台被杀死时,singleton对象为空,当我切换回它时,它尝试加载最后一个活动,该活动必须访问singleton以创建其布局“系统将终止”部分正是我的问题,因为我需要一种方法在那之后重新创建对象。我的解决方案是在ondestroy中调用oncreate一个here-am-I方法和一个good-by方法…我将添加一个示例。谢谢,但是我不知道这如何帮助恢复我的singleton(好的,我想你的意思是我的singleton应该就是这个应用程序对象。现在请注意,数据必须用webservice调用填充。应用程序将被关闭,重新打开,应用程序对象将被创建,我可以安排我的webservice调用,但是我的活动被打开,调用没有完成,我的布局不好)。即使暂时关闭了所有活动,应用程序对象也将存在。这就是为什么我手动检查并保存
shutdown()中的所有自定义状态
method。如果没有通知您应用程序已被终止,您如何手动检查并保存任何内容?可能我没有得到某些信息或某些信息仍然丢失…那么多个活动会发生什么情况?我猜单例将独立保存/序列化(可能不同
public class TestActivity extends Activity {

    private MySingleton singleton;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if(savedInstanceState.containsKey("singleton")) {
            singleton = savedInstanceState.getParcelable("singleton");
        } else {
            singleton = MySingleton.getInstance(5);
        }
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putParcelable("singleton", singleton);
    }

    public static class MySingleton implements Parcelable {

        private static MySingleton instance;
        private int myData;

        private MySingleton(int data) {
            myData = data;
        }

        public static MySingleton getInstance(int initdata) {
            if(instance == null) {
                instance = new MySingleton(initdata);
            }

            return instance;
        }

        public static final Parcelable.Creator<MySingleton> CREATOR = new Creator<TestActivity.MySingleton>() {

            @Override
            public MySingleton[] newArray(int size) {
                return new MySingleton[size];
            }

            @Override
            public MySingleton createFromParcel(Parcel source) {
                return new MySingleton(source.readInt());
            }
        };

        @Override
        public int describeContents() {
            return 0;
        }

        @Override
        public void writeToParcel(Parcel parcel, int flags) {
            parcel.writeInt(myData);
        }

    }

}