I read a lot but couldn't understand how to restore state when some data kept on singletone class. for example
public class UserDataKeeper {
private static UserDataKeeper instance;
private User mUser;
private UserDataKeeper(){
}
public static UserDataKeeper getInstance() {
if (instance == null) {
instance = new UserDataKeeper();
}
return instance;
}
public User getUser() {
return mUser;
}
public void setUser(User mUser) {
this.mUser = mUser;
}
}
When my android application come from background user data becoming null. what should I do here for not getting null result.
Is the only solution is save data using SQLite,Preference or something else ?
Even if you're implementing a Singleton (which is almost always a bad solution), you're still storing the data in memory. After your application is closed the data will be lost. If you want persistent storage then yes, you'll need to have either a SQLite database, or write your information to disk.
Related
I stumbled upon a pseudo-singleton class that is responsible for housing a few collections. It looks something like this:
public class PseudoSingleton {
private List<Object> collection1;
private List<Object> collection2;
private static PseudoSingleton instance = null;
public static synchronized PseudoSingleton getInstance() {
if (instance == null) {
instance = new PseudoSingleton();
}
return instance;
}
public static synchronized void reload() {
instance = new PseudoSingleton();
}
private PseudoSingleton() {
load();
}
private void load() {
//parse some files from disk and fill collections
}
}
The reason it is coded like this is that in a few places in code a comparison of collection1 before and after reload needs to be done.
However this way seems like a major code smell to me.
I tried to refactor the code slightly by making the reload() method not static:
public synchronized void reload() {
//clear collections
//load collections
}
In order to be able to compare collection before reload I added a method that needs to be called before reloading the collection:
public List<Object> getCollection1Copy() {
return new LinkedList<>(collection1);
}
However, in review I got a comment that the previous way was better and I should leave it as is. I am not convinced. Should I insist to go my way or leave it? Or is there a better way to code it?
I follow one example with small modifications: https://dzone.com/articles/spring-webflux-first-steps
My ServiceImpl looks like:
private final HotelRepository hotelRepository;
private final HotelByLetterRepository hotelByLetterRepository;
public HotelServiceImpl(HotelRepository hotelRepository, HotelByLetterRepository hotelByLetterRepository) {
this.hotelRepository = hotelRepository;
this.hotelByLetterRepository = hotelByLetterRepository;
}
#Override
public Mono<Hotel> save(Hotel hotel) {
if (hotel.getId() == null) {
hotel.setId(UUID.randomUUID());
}
Mono<Hotel> saved = hotelRepository.save(hotel);
saved.then(hotelByLetterRepository.save(new HotelByLetter(hotel)));
return saved;
}
After Hotel entity is saved logic try to save HottelByLetter.
In repository I inject ReactiveCassandraOperations and for a save method I just call insert method.
#Repository
public class CassandraHotelRepository implements HotelRepository {
private final ReactiveCassandraOperations cassandraTemplate;
public CassandraHotelRepository(ReactiveCassandraOperations cassandraTemplate) {
this.cassandraTemplate = cassandraTemplate;
}
#Override
public Mono<Hotel> save(Hotel hotel) {
return cassandraTemplate.insert(hotel);
}
}
After service call only Hotel is saved, HotelByLetter is not saved.
After debug I found that:
In ReactiveCqlTemplate method createFlux is called properly two times with correct ReactiveSessionCallback.
protected <T> Flux<T> createFlux(ReactiveSessionCallback<T> callback) {
Assert.notNull(callback, "ReactiveStatementCallback must not be null");
ReactiveSession session = getSession();
return Flux.defer(() -> callback.doInSession(session));
}
But, callback.doInSession(session) is executed only once for insert new hotel.
I try also to extend ReactiveCrudRepository, but same issue.
I'm using: org.springframework.data/spring-data-cassandra/2.0.0.RELEASE
TL;DR;
You need to work with the results of each publisher operator to apply the actual operation which created the Publisher.
Explanation
Project Reactor's fundamental concept is to never mutate a Publisher through operators but rather returning a new instance. That's different in contrast to say a Future like CompletableFuture where you're able to register callbacks, and you're not obliged to reuse the result of the callback registration method to make it work.
The code of your HotelServiceImpl should look like the following:
class HotelServiceImpl implements HotelService {
// …
#Override
public Mono<Hotel> save(Hotel hotel) {
if (hotel.getId() == null) {
hotel.setId(UUID.randomUUID());
}
Mono<Hotel> saved = hotelRepository.save(hotel);
return saved.then(hotelByLetterRepository.save(new HotelByLetter(hotel)));
}
}
Calling saved.then(…) creates a new Mono. Dropping (not using) that Mono will result in not executing the .then(…) operator. Instead, returning the result of saved.then(…) will do also save HotelByLetter.
I have one-to-many relationship in Realm
public class BayEntity extends RealmObject implements RealmModel {
#PrimaryKey
private int id;
private String title;
}
public class TermEntity extends RealmObject implements RealmModel {
#PrimaryKey
private String termId;
private String name;
private RealmList<BayEntity> bayList;
public void updateBayList(ArrayList<BayEntity> bayList) {
if(CollectionUtility.isEmptyOrNull(this.bayList))
this.bayList = new RealmList();
this.bayList.addAll(bayList);
realm.beginTransaction();
realm.copyToRealm(this.bayList);
realm.insertOrUpdate(this); //update current instance
realm.commitTransaction();
}
public ArrayList<BayEntity> getSimpleList() {
if(CollectionUtility.isEmptyOrNull(bayList))
return new ArrayList<>();
return (ArrayList<BayEntity>) realm.copyFromRealm(bayList);
}
}
I am getting all TermEntity objects containing baylist as:
public RealmResults<TermEntity> getTerms() {
return realm.where(TermEntity.class).findAll();
}
I am able to save and retrieve bayList successfully. When I try to convert it into Arraylist in method getSimpleList(), I am getting exception:
java.lang.IllegalArgumentException: Only valid managed objects can be
copied from Realm.
I can't understand how objects can be unmanaged when they are saved and retrieved from realm. Please correct me. Thanks.
It looks to me as though you have several problems:
Where are you getting the Realm instance that you use in the updateBayList method? Since it is instance local state, it might easily refer to a Realm that is not valid in the current context (time or thread)
The first three lines if ... addAll(bayList); modify Terms RealmList. You can't do that outside of a transaction, if the object is managed. When the object is not managed, you get the error you describe, because you are trying to add managed objects to an unmanaged RealmList
While not a problem, RealmObject already implements RealmModel. Say something once, why say it again?
Edited to add:
In order to add BayEntitys to a TermEntity, first make sure that the TermEntity is a managed object (use copyToRealm, or query for it). Once you do that, the code in updateBayList is very nearly correct. You want something like:
realm.beginTransaction();
if (CollectionUtility.isEmptyOrNull(this.bayList)) {
this.bayList = new RealmList();
}
this.bayList.addAll(bayList);
realm.commitTransaction();
There are several activities and fragments that need access to a specific data, so i created a singleton object to store data in that. The problem is after a long time that the app is in background, that singleton object will disapear and become null, so when i open my app again the app crashes and throws null pointer exception to that object. What should I do? How should i share that data between activities and fragments?
Is it a good practice to store that data in database? Or bundle? or whatever?
This is my singleton:
public class Book {
private static Book ourInstance;
private int FLNB;
private Book() {
}
public static Book getInstance() {
if (ourInstance == null) {
ourInstance = new Book();
}
return ourInstance;
}
public void setFLNB(int FLNB) {
this.FLNB = FLNB;
}
public int getFLNB() {
return this.FLNB;
}
}
I set FLNB, and when singleton is gone, the value of FLNB is cleared and I need to access this value after re-initial singleton.
I'm quite new to OOP concepts, and right now I am developing a small system, it has a login system. I have saved the user info in a database, and when I log in, I have made it so it retrieves and assigns the user info(name, privileges, etc) to a set of static variables in my staff class to use later. I was wondering is there a way around this, to save the variables while the program is running after log in to be used later in other forms. The reason I assigned them to static variables while the user has logged in, is so that I don't have to retrieve his user info everytime I need to use them(for example to check which form to fall back to if the user presses back and has certain privileges)
If you want this the OOP way, you would typically define a UserInfo class, which will hold the relevant information (passed in via constructor). If you need to change between different users, the most common solution would be to store the UserInfos in a container such as a HashMap, and have one of the attributes (possibly a dedicated one) act as key to the users. Later you can just get the information object for a given user.
In most cases using static variables is a mistake, not just for the clutter it causes but for the on-going pain of remembering it.
There are some generally accepted exceptions though. Loggers are acceptable when made static.
You are in need of a session static Context. I.e. a context that is static for one session (i.e. login).
class Context {
private static final Context context = new Context();
String userName;
String userPriveliges;
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getUserPriveliges() {
return userPriveliges;
}
public void setUserPriveliges(String userPriveliges) {
this.userPriveliges = userPriveliges;
}
public static Context getContext() {
return context;
}
}
One approach is to use the Singleton Pattern. This allows you to avoid static fields at the cost of a static method.
public class LoginInfo {
private String username;
private List<String> privileges;
private static INSTANCE = new LoginInfo();
private LoginInfo() {
}
public void initFromDB() {
}
// Everything else is non-static but this
public static getInstance() {
return INSTANCE;
}
}
public class Form1 {
public void doSomething() {
LoginInfo info = LoginInfo.getInstance();
}
}
public class Form2 {
public void doSomething() {
LoginInfo info = LoginInfo.getInstance();
}
}
The other approach is Dependency Inversion. In this case, the users of LoginInfo get the information from outside, somehow.
public class Form1 {
private LoginInfo loginInfo;
public Form1(LoginInfo loginInfo) {
this.loginInfo = loginInfo;
}
public void doSomething() {
}
}
public class Form2 {
private LoginInfo loginInfo;
public Form2(LoginInfo loginInfo) {
this.loginInfo = loginInfo;
}
public void doSomething() {
}
}
Somewhere else:
// The Hollywood Principle - don't call me, I'll call you
public void login() {
LoginInfo loginInfo = new LoginInfo();
form1 = new Form1(loginInfo);
form2 = new Form2(loginInfo);
}
The Dependency Inversion approach has the benefit of the nasty side effects of static variables and methods, at the cost of some wiring. There are frameworks such as Spring, CDI and Guice that help you with that part.
Also, Singletons are Pathalogical Liars.
Instead of using static use final. I mean un-initialised final. But it will work only if after logged offing you exit from application. If you are not existing after logged off then use registry to save users. Java has inbuilt registry, you can use it to save anything. It also has password protection, and you can use that registry as cookies of web applications. Here are few linksconstant-vs-staticbad design practice statichow to avoid static
You can pass variables through constructors. Otherwise you can use a singleton class. There's no other way.