java - Singleton returning two instances -
i'm trying use singleton (photostorage) provide arraylist of photo objects, seems photostorage instance not behaving singleton (two instances).
i using dagger inject singleton class named photointeractor. objectgraph seems a-ok point. same photointeractor instance used in 3 fragments in viewpager. these fragments instantiated @ runtime:
recentfragment:
historyfragment:
notice how instance @4067 of photointeractor same both fragments.
also:
- mappcontext@4093: same
- photostorage@4094: same
when click photo object (grid image) recentfragment, photostorage.addphoto(url) method called. correctly adds photo object photostorage instance array (4094). ok.
problem:
when close applicaton, intended photostorage.savephotostofile method serialzes arraylist object json on filesystem.
the following method called same photointeractor instance:
@override public void savephotos(){ photostorage.get(mappcontext).savephotostofile(); }
when debug application, photostorage.get method has singleton instance, appears 2nd instance!
//singleton enforcement public static photostorage get(context c){ if(sphotostorage == null){ sphotostorage = new photostorage(c.getapplicationcontext()); } return sphotostorage; }
this means arraylist of photos empty since new instance of photostorage. i’m not sure instantiating from.
edit - added 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; } }
}
you not executing singletton pattern in correct way,
the singleton design pattern addresses of these concerns. singleton design pattern can:
ensure 1 instance of class created
provide global point of access object
in case, don't see photostorage
class call comes instance, not allowed singletton pattern:
photostorage.get(mappcontext).savephotostofile(); //↑ instance call wrong!!
this line works, get
method static
not practice karakuri pointed , breaks singletton pattern definition.
public static photostorage get(context c){
solution
make photostorage.get()
invalid , create correct singletton pattern must:
- declare
getinstance()
method static in class (herephotostorage
) - hide default constructor avoid instances of class
- create private constructors if necessary
- call
getinstance()
in static way:
class photostorage { // hidding default constructor private photostorage () {}; // creating own constructor 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 can make static call everywhere class scope allows:
@override public void savephotos(){ photostorage.get(mappcontext).savephotostofile(); //↑ static call correct!! }
update:
if app have several threads , singleton getinstance requests may overlapp, there double check syncronized singletton pattern 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()); } } } }
Comments
Post a Comment