单例返回两个实例
Singleton returning two instances
我正在尝试使用单例 (PhotoStorage) 来提供 Photo 对象的 arrayList,但 PhotoStorage 实例的行为似乎不像单例(两个实例)。
我正在使用 dagger 将这个单例注入一个名为 class 的 PhotoInteractor。到目前为止,objectGraph 似乎 A-OK。
同一个 PhotoInteractor 实例用于 viewpager 中的三个片段。这些片段都是在运行时实例化的:
最近片段:

历史片段:

注意两个片段的 PhotoInteractor 实例 @4067 是如何相同的。
还有:
- mAppContext@4093: 相同
- photoStorage@4094: 相同
当我从 RecentFragment 单击照片对象(网格图像)时,会调用 PhotoStorage.addPhoto(url) 方法。这会正确地将照片对象添加到 photoStorage 实例数组 (4094)。这么多就好了。
问题:
当我关闭应用程序时,PhotoStorage.savePhotosToFile 方法将此 arrayList 对象序列化为文件系统上的 JSON。
从同一个 PhotoInteractor 实例调用以下方法:
@Override
public void savePhotos(){
photoStorage.get(mAppContext).savePhotosToFile();
}
当我调试应用程序时,PhotoStorage.get 方法已经有一个单例实例,但似乎是第二个实例!
//Singleton enforcement
public static PhotoStorage get(Context c){
if(sPhotoStorage == null){
sPhotoStorage = new PhotoStorage(c.getApplicationContext());
}
return sPhotoStorage;
}
这意味着照片 ArrayList 将始终为空,因为它是 PhotoStorage 的新实例。我不确定它从哪里实例化自己。
编辑 - 添加 PhotoStorage.class:
public class PhotoStorage{
private ArrayList<Photo> mPhotos;
private PhotoJSONer mSerializer;
private static PhotoStorage sPhotoStorage;
private static Context mAppContext;
private static final String PHOTOS_DATABASE = "photos.json";
public static final String TAG = PhotoStorage.class.getSimpleName();
public PhotoStorage(Context appContext){
mSerializer = new PhotoJSONer(appContext, PHOTOS_DATABASE);
try{
mPhotos = mSerializer.loadPhotos();
}catch(Exception e){
mPhotos = new ArrayList<Photo>();
}
}
//Singleton enforcement
public static PhotoStorage get(Context c){
if(sPhotoStorage == null){
sPhotoStorage = new PhotoStorage(c.getApplicationContext());
}
return sPhotoStorage;
}
public ArrayList<Photo> getPhotos(){
return mPhotos;
}
public Photo getPhoto(String url){
for(Photo p: mPhotos){
if(p.getUrl() == url)
return p;
}
return null;
}
public void deletePhoto(String url){
Log.i(TAG, "deleted photo");
mPhotos.remove(url);
}
public void addPhoto(Photo photo){
Log.i(TAG, "added photo");
mPhotos.add(photo);
}
public boolean savePhotosToFile(){
try{
mSerializer.savePhotos(mPhotos);
return true;
}catch (Exception e){
return false;
}
}
}
您没有以正确的方式执行 Singletton pattern,
The Singleton design pattern addresses all of these concerns. With the Singleton design pattern you can:
Ensure that only one instance of a class is created
Provide a global point of access to the object
在你的情况下,我们没有看到 PhotoStorage
class 但这个调用来自一个实例,这是 Singletton pattern 不允许的:
photoStorage.get(mAppContext).savePhotosToFile();
//↑ instance call WRONG!!
这条线有效,但由于您的 get
方法是 static
,这不是一个好习惯,因为 Karakuri 指出并打破了 Singletton pattern定义。
public static PhotoStorage get(Context c){
解决方案
要使 photoStorage.get()
无效并创建正确的 Singletton pattern,您必须:
- 在 class(此处
PhotoStorage
)中声明 getInstance()
静态方法
- 隐藏默认构造函数以避免 class
的实例
- 必要时创建私有构造函数
- 以静态方式调用
getInstance()
它:
class PhotoStorage {
// hidding default constructor
private PhotoStorage () {};
// creating your own constructor but private!!!
private PhotoStorage(Context appContext){
mSerializer = new PhotoJSONer(appContext, PHOTOS_DATABASE);
try{
mPhotos = mSerializer.loadPhotos();
}catch(Exception e){
mPhotos = new ArrayList<Photo>();
}
}
//Singleton enforcement
public synchronized static PhotoStorage get(Context c){
if(sPhotoStorage == null){
sPhotoStorage = new PhotoStorage(c.getApplicationContext());
}
return sPhotoStorage;
}
}
然后你可以从class范围允许的任何地方进行静态调用:
@Override
public void savePhotos(){
PhotoStorage.get(mAppContext).savePhotosToFile();
//↑ static call CORRECT!!
}
更新:
如果您的应用有多个线程并且单例 getInstance 请求可能会重叠,则有一个 double check syncronized singletton pattern 您可以申请:
//Singleton enforcement
public synchronized static PhotoStorage get(Context c){
if(sPhotoStorage == null){
synchronized(PhotoStorage.class) {
if(sPhotoStorage == null) {
sPhotoStorage = new PhotoStorage(c.getApplicationContext());
}
}
}
}
我正在尝试使用单例 (PhotoStorage) 来提供 Photo 对象的 arrayList,但 PhotoStorage 实例的行为似乎不像单例(两个实例)。
我正在使用 dagger 将这个单例注入一个名为 class 的 PhotoInteractor。到目前为止,objectGraph 似乎 A-OK。 同一个 PhotoInteractor 实例用于 viewpager 中的三个片段。这些片段都是在运行时实例化的:
最近片段:
历史片段:
注意两个片段的 PhotoInteractor 实例 @4067 是如何相同的。
还有:
- mAppContext@4093: 相同
- photoStorage@4094: 相同
当我从 RecentFragment 单击照片对象(网格图像)时,会调用 PhotoStorage.addPhoto(url) 方法。这会正确地将照片对象添加到 photoStorage 实例数组 (4094)。这么多就好了。
问题:
当我关闭应用程序时,PhotoStorage.savePhotosToFile 方法将此 arrayList 对象序列化为文件系统上的 JSON。
从同一个 PhotoInteractor 实例调用以下方法:
@Override
public void savePhotos(){
photoStorage.get(mAppContext).savePhotosToFile();
}
当我调试应用程序时,PhotoStorage.get 方法已经有一个单例实例,但似乎是第二个实例!
//Singleton enforcement
public static PhotoStorage get(Context c){
if(sPhotoStorage == null){
sPhotoStorage = new PhotoStorage(c.getApplicationContext());
}
return sPhotoStorage;
}
这意味着照片 ArrayList 将始终为空,因为它是 PhotoStorage 的新实例。我不确定它从哪里实例化自己。
编辑 - 添加 PhotoStorage.class:
public class PhotoStorage{
private ArrayList<Photo> mPhotos;
private PhotoJSONer mSerializer;
private static PhotoStorage sPhotoStorage;
private static Context mAppContext;
private static final String PHOTOS_DATABASE = "photos.json";
public static final String TAG = PhotoStorage.class.getSimpleName();
public PhotoStorage(Context appContext){
mSerializer = new PhotoJSONer(appContext, PHOTOS_DATABASE);
try{
mPhotos = mSerializer.loadPhotos();
}catch(Exception e){
mPhotos = new ArrayList<Photo>();
}
}
//Singleton enforcement
public static PhotoStorage get(Context c){
if(sPhotoStorage == null){
sPhotoStorage = new PhotoStorage(c.getApplicationContext());
}
return sPhotoStorage;
}
public ArrayList<Photo> getPhotos(){
return mPhotos;
}
public Photo getPhoto(String url){
for(Photo p: mPhotos){
if(p.getUrl() == url)
return p;
}
return null;
}
public void deletePhoto(String url){
Log.i(TAG, "deleted photo");
mPhotos.remove(url);
}
public void addPhoto(Photo photo){
Log.i(TAG, "added photo");
mPhotos.add(photo);
}
public boolean savePhotosToFile(){
try{
mSerializer.savePhotos(mPhotos);
return true;
}catch (Exception e){
return false;
}
}
}
您没有以正确的方式执行 Singletton pattern,
The Singleton design pattern addresses all of these concerns. With the Singleton design pattern you can:
Ensure that only one instance of a class is created
Provide a global point of access to the object
在你的情况下,我们没有看到 PhotoStorage
class 但这个调用来自一个实例,这是 Singletton pattern 不允许的:
photoStorage.get(mAppContext).savePhotosToFile();
//↑ instance call WRONG!!
这条线有效,但由于您的 get
方法是 static
,这不是一个好习惯,因为 Karakuri 指出并打破了 Singletton pattern定义。
public static PhotoStorage get(Context c){
解决方案
要使 photoStorage.get()
无效并创建正确的 Singletton pattern,您必须:
- 在 class(此处
PhotoStorage
)中声明getInstance()
静态方法 - 隐藏默认构造函数以避免 class 的实例
- 必要时创建私有构造函数
- 以静态方式调用
getInstance()
它:
class PhotoStorage {
// hidding default constructor
private PhotoStorage () {};
// creating your own constructor but private!!!
private PhotoStorage(Context appContext){
mSerializer = new PhotoJSONer(appContext, PHOTOS_DATABASE);
try{
mPhotos = mSerializer.loadPhotos();
}catch(Exception e){
mPhotos = new ArrayList<Photo>();
}
}
//Singleton enforcement
public synchronized static PhotoStorage get(Context c){
if(sPhotoStorage == null){
sPhotoStorage = new PhotoStorage(c.getApplicationContext());
}
return sPhotoStorage;
}
}
然后你可以从class范围允许的任何地方进行静态调用:
@Override
public void savePhotos(){
PhotoStorage.get(mAppContext).savePhotosToFile();
//↑ static call CORRECT!!
}
更新:
如果您的应用有多个线程并且单例 getInstance 请求可能会重叠,则有一个 double check syncronized singletton pattern 您可以申请:
//Singleton enforcement
public synchronized static PhotoStorage get(Context c){
if(sPhotoStorage == null){
synchronized(PhotoStorage.class) {
if(sPhotoStorage == null) {
sPhotoStorage = new PhotoStorage(c.getApplicationContext());
}
}
}
}