2

我有一个我在所有活动中使用的对象,其中包含很多复杂的数据,使用 Android 框架保存对象状态并将其从活动传递到活动会很麻烦,所以我认为它会可以创建一个管理此对象并使其与应用程序一样长的单例。

尝试使用常规 Java Singleton 方案,具有普通类和普通静态实例,但一段时间后实例变为 null(这很令人困惑,为什么仍然引用的 Object 会变为 null 并被垃圾回收?)。所以我决定与 Android 设计师合作并创建一个服务来管理这个对象,服务看起来像这样:

public class DataService extends Service {
    private Data data;
    private static DataService instance;
    @Override
    public void onCreate() {
        instance = this;
        data= new Data(...);
        instance.data.addProgressListener(listener);
        (new Thread() {
            @Override
            public void run() {
                data.doInitProgress();
                listener = null;
            };
        }).start();

    }


    public static void listenToInitDataProcess(final ProgressBar progressBar,final Runnable onDone) {

        listener = new ProgressListener() {
            private int progress;
            private int max;
            @Override
            public void onUpdateProgress(final long i) {
                progressBar.setProgress(progress+=i);
            }

            @Override
            public void onProgressEndComputed(final long n) {
                progressBar.setMax(max=(int) n);
            }

            @Override
            public void onDone() {
                progressBar.setProgress(max);
                onDone.run();
            }
        };
            if (instance!=null) instance.data.addProgressListener(listener);
    }

    public static Data getData() {
        return instance.data;
    }
    @Override
    public IBinder onBind(Intent arg0) {
        return null;
    }
}

现在的问题是,在应用程序启动一段时间后,我得到由实例引起的 NPE 为空......请注意,我正在监听数据对象的创建,并且我只是在它被启动后才尝试获取它,所以这个实例不可能是空的......

那该怎么做呢?

4

2 回答 2

2

如果您想要一个与您的应用程序存在一样长的对象(即只要它的进程没有被操作系统杀死),您可以扩展android.app.Application,将您的“全局”数据放在那里并将该子类用作您的应用程序上下文(需要声明在清单中)

然而,许多人认为单例提供了与自定义上下文基本相同的结果,例如
Android 中的单例与应用程序上下文?

于 2013-11-08T09:56:39.393 回答
-1

但一段时间后实例变为空

首先,了解Effective Java的单例建议,以及某些内容如何不会变为空:

// Singleton with public final field
public class Elvis {
    public static final Elvis INSTANCE = new Elvis();
    private Elvis() { ... }

    public void leaveTheBuilding() { ... }
}

但是 Service 不同,因为那里没有公共构造函数。因此,首先检查服务是否正在运行(如本文所述:检查服务是否从广播接收器运行):

private boolean isMyServiceRunning(Context context) {
    ActivityManager manager = (ActivityManager)      context.getSystemService(Context.ACTIVITY_SERVICE);
    for (RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
        if (DataService.class.getName().equals(service.service.getClassName())) {
            return true;
        }
    }

    return false;
}

然后在你的服务中定义一些方法来返回你需要的状态变量。

于 2015-03-03T16:31:45.683 回答