辛格尔顿返回两个实例 [英] Singleton returning two instances
问题描述
我试图用一个单(PhotoStorage)提供照片对象的ArrayList,但它似乎PhotoStorage实例未表现为一个单独(两个实例)。
I'm trying to use a singleton (PhotoStorage) to provide an arrayList of Photo objects, but it seems that the PhotoStorage instance is not behaving as a singleton (two instances).
我使用匕首注入此singleton到一个名为PhotoInteractor类。该objectGraph似乎都OK了这一点。
相同PhotoInteractor实例在三个片段用于在viewpager。这些片段都被实例化在运行时:
I am using dagger to inject this singleton into a class named PhotoInteractor. The objectGraph seems A-OK up to this point. The same PhotoInteractor instance is used in three fragments in a viewpager. These fragments are all instantiated at runtime:
RecentFragment:
HistoryFragment:
注意实例@的PhotoInteractor 4067是如何成为两个片段是相同的。
Notice how the instance @4067 of the PhotoInteractor is the same for both fragments.
还有:
- mAppContext @ 4093:相同
- photoStorage @ 4094:相同
当我点击从RecentFragment照片对象(网格图),该PhotoStorage.addPhoto(URL)方法被调用。这正确添加照片对象的实例photoStorage阵列(4094)。这一点是确定。
When I click a photo object (grid image) from RecentFragment, the PhotoStorage.addPhoto(url) method is called. This correctly adds the photo object to the photoStorage instance array (4094). That much is OK.
问题:
当我关闭一个应用,其意图是在 PhotoStorage.savePhotosToFile 方式serialzes这个ArrayList对象成JSON上的文件系统。
When I close the applicaton, it is intended that the PhotoStorage.savePhotosToFile method serialzes this arrayList object into JSON on the filesystem.
下面的方法是从同一PhotoInteractor实例调用
The following method is called from the same PhotoInteractor instance:
@Override
public void savePhotos(){
photoStorage.get(mAppContext).savePhotosToFile();
}
当我调试应用程序,在 PhotoStorage.get 方式已经有一个单实例,但是这似乎是一个第二个实例!
When I debug the application, the PhotoStorage.get method already has a singleton instance, but what appears to be a 2nd instance!
//Singleton enforcement
public static PhotoStorage get(Context c){
if(sPhotoStorage == null){
sPhotoStorage = new PhotoStorage(c.getApplicationContext());
}
return sPhotoStorage;
}
这意味着,照片该ArrayList永远是空的,因为它是PhotoStorage的新实例。我不知道它是从哪里实例化本身。
This means that the ArrayList of photos will always be empty since it is a new instance of PhotoStorage. I’m not sure where it is instantiating itself from.
编辑 - 添加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模式一>以正确的方式,
You are not executing Singletton pattern in the correct way,
Singleton设计模式解决了所有这些问题。随着Singleton设计模式,您可以:结果
确保只有一个类的实例被创建结果
提供一个全局访问点的对象
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
类,但这一呼吁源于一个实例,什么是不的 Singletton模式:
In your case, we don't see PhotoStorage
class but this call comes from an instance, what is not allowed by Singletton pattern:
photoStorage.get(mAppContext).savePhotosToFile();
//↑ instance call WRONG!!
这行工作,但作为你的 GET
方法静态
不是一个好的做法,因为的Karakuri 尖,也打破了的 Singletton模式定义。
This line works, but as your get
method is static
is not a good practice as Karakuri pointed and also breaks the Singletton pattern definition.
public static PhotoStorage get(Context c){
SOLUTION 结果
为了让 photoStorage.get()
无效并创建一个正确的 Singletton模式你必须:
SOLUTION
To make photoStorage.get()
invalid and create a correct Singletton pattern you must:
- 声明
的getInstance()
方法在类的静态(这里PhotoStorage
) - 隐藏默认的构造函数,以避免类的实例
- 创建私有构造函数如果有必要
- 通话
的getInstance()
在一个静态的方式:
- declare the
getInstance()
method static in the class (herePhotoStorage
) - hide default constructor to avoid instances of the class
- create private constructors if necessary
- call
getInstance()
it in a static way:
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;
}
}
然后你就可以静态调用来自世界各地类范围内允许:
Then you can make static call from everywhere the class scope allows:
@Override
public void savePhotos(){
PhotoStorage.get(mAppContext).savePhotosToFile();
//↑ static call CORRECT!!
}
更新:结果,如果你的应用程序有多个线程和单身的getInstance请求可能overlapp,有一个的仔细检查syncronized singletton模式你可以申请?
UPDATE:
if your app have several threads and singleton getInstance requests may overlapp, there is a double check syncronized singletton pattern you can apply:
//Singleton enforcement
public synchronized static PhotoStorage get(Context c){
if(sPhotoStorage == null){
synchronized(PhotoStorage.class) {
if(sPhotoStorage == null) {
sPhotoStorage = new PhotoStorage(c.getApplicationContext());
}
}
}
}
这篇关于辛格尔顿返回两个实例的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!