When my application goes to background , my (static and singleton) objects are cleared.
So I tried to store these objects in Applicaton Context . I am using the following code.
Accounts.create(getApplicationContext()) will be called once to store the accounts instance.
Is that possible(reliable) to store objects in Application Context ? I am not sure the following way is correct or not . please guide ..
public class Init extends Application {
private Hashtable<Object, Object> globalStore = new Hashtable<Object, Object>();
public void putToGlobalStore(Object key, Object value) {
globalStore.put(key, value);
}
public Object takeFromGlobalStore(Object key) {
return this.globalStore.get(key);
}
public void removeFromGlobalStore(Object key) {
this.globalStore.remove(key);
}
public boolean containsInGlobalStore(Object key) {
return this.globalStore.containsKey(key);
}
}
public class Accounts {
protected Accounts(String name, Context context) {
Init init = (Init) applicationContext;
init.putToGlobalStore(name, this);
}
private static Init applicationContext;
public static void create(Context context) {
if (context instanceof Application)
applicationContext = (Init) context;
else
applicationContext = (Init) context.getApplicationContext();
if (applicationContext.containsInGlobalStore(GLOBAL_NAME))
Logger.log("Warning " + GLOBAL_NAME
+ " is already created. This will remove all old datas");
new Accounts(GLOBAL_NAME, applicationContext);
}
private static final String GLOBAL_NAME = "accounts";
public static Accounts getInstance() {
try {
return (Accounts) applicationContext
.takeFromGlobalStore(GLOBAL_NAME);
} catch (Exception e) {
Logger.log("GLOBAL_NAME Lost");
return null;
}
}
Please help.
You should know that the application context itself gets destroyed if left unused for a long time in the background. So there is no guarantee that your static and singleton objects will not be cleared when the app is in background. Instead what you can do is persist your objects from time to time (either in a flat-file or shared preference or database) and restore them in the onCreate method of the Application class
I have been using this method in my application and i didn't see any problem unless my process gets killed by the OS or if there is a crash in my application and my app gets restarted.
If you think whatever data you are storing is valid for only life time of a program why don't you override OnCreate of Application object and create all your singletons there. This way you can always make sure your application has all singletons before your app starts functioning.
Application class is not permanent.
If App process killed, Application class private member variable data loss.
Using Shared Preferences.
I know this question was asked a long time ago, but here's a good article that suggests using the Application object to store data is generally not a sound design methodology.
Related
I am using SharedPreferences to store my data. When my application is running data is been saved to SharedPreferences successfully but when i close my application and try to save data in it via Intent Service nothing happened . no data saved to it :
public class TinyDB {
private SharedPreferences preferences;
private String DEFAULT_APP_IMAGEDATA_DIRECTORY;
private String lastImagePath = "";
public TinyDB(Context appContext) {
preferences = PreferenceManager.getDefaultSharedPreferences(appContext);
}
public void putString(String key, String value) {
checkForNullKey(key); checkForNullValue(value);
preferences.edit().putString(key, value).apply();
}
}
I am using its object in onMessageReceive()
public void onMessageReceived(RemoteMessage remoteMessage) {
tinyDb.putString("key","value");
}
The main point that i want to make sure that i want to save value when app is not running. When app is running everything is fine.
I also want to know what class or Activity is best for initializing the object of TinyDB , and i should make it static or not ?
You can instantiate a new instance of TinyDB in your IntentService class with the Context of your Service (assuming that the IntentService is running on the same process as the original Activity). Please note that after performing all its logic, an IntentService is destroyed with all its resource, so the new TinyDB will be destroyed as well.
try
public void onMessageReceived(RemoteMessage remoteMessage) {
// shortcut and valid local variable
Context ctx = getApplicationContext()
// get instance of shared preferences using service/receiver context!
// keep in mind device protected context / boot aware stuff
// https://source.android.com/security/encryption/file-based
SharedPreferences sp = ctx.getSharedPreferences(preferencesFileName,Context.MODE_PRIVATE);
// save pref value
sp.edit().put(...).commit();
}
*preferenceFileName - if default is your_packageName + _preferences
ps some things to consider:
see man: apply() vs commit()
check how you register your receiver
read in dosc / specs / www if you are allowed to save preferences outside main thread (ActivityThread)
read Are Android's BroadcastReceivers started in a new thread?
more hints:
do not store Context class objects - as they are and should stay short lived - instead use WeakReference
// create if you want to hold context reference
WeakReference<Context> wctx = new WeakReference<Context>(context)
// then get when you want to use context
Context ctx = wctx.get();
if(ctx!=null) // context still alive we can use it
I am building a menu from which the user can select items. They can edit their selections whenever necessary. The singleton would be a class containing the list of all selectable items. Whenever new activities are opened, the singleton would have the correct state of all items.
The reason I am asking this is because implementing Serializable creates a new instance (albeit almost identical) of the item.
Yes you could use a singleton for this. It would be something like:
public class MenuData {
private static MenuData instance;
private boolean isItemASelected;
public static MenuData getInstance() {
if (instance == null) {
instance = new MenuData();
}
return instance;
}
public boolean isItemASelected() {
return isItemASelected;
}
public void setItemASelected(boolean itemASelected) {
isItemASelected = itemASelected;
}
}
However I wouldn't recommend this. This data will only be around for as long as your Application is in memory. As soon as your app gets killed by Android all the variables will be cleared and the state will have been lost.
If your menu items are constant then I'd recommend using SharedPreferences to store the state. If they are dynamic then use the SQL database. This way the options are persisted even if your app gets killed.
I am trying to use a Singleton to share a large data object between Activities. But when I open the new Activity, the singleton comes up as empty. It seems to me that the Singleton should be the same no matter where in the Application I call if from.
It seems like the Scope of the Singleton is being limited to the individual Activity. Working around this is making my App very complicated. I must be doing something wrong. I even tried instantiating them in an extended Application class... Google says I should not have to use that though...
Can someone please point out where I am going wrong? i.e. Why does this singletom not contain the same data in each Activity?
I call it from an Activity with...
DataLog dataLog = DataLog.getInstance(this);
I have...
public class DataLog extends ArrayList<String> implements Serializable {
private static final long serialVersionUID = 0L;
private static DataLog sInstance;
private static Context mContext;
public static DataLog getInstance(Context context) {
mContext = context.getApplicationContext();
prefs = PreferenceManager.getDefaultSharedPreferences(mContext);
if (sInstance == null) {
sInstance = new DataLog();
}
return sInstance;
}
private DataLog() {
}
public boolean add(String entry) {
super.add(entry);
return true;
}
public void add(int index, String entry) {
if (index > 0)
super.add(index, entry);
else
super.add(entry);
}
public void clear() {
super.clear();
}
...
}
Its highly advisable to avoid singleton for sharing large data sets in android.
Singletons are used for short life-cycle objects.
Switch to SharedPrefferences, SQLite DB's or file storing. You are not the only to have experienced this behavior, and the reason lies in the nature of android Activities and the system itself(managing activities and its data).
Here is an example why singleton is bad for your case:
You stored important data in it. The user knows that he can close the app on home button to call someone or whatever)maybe someone called him when he was in your app), and that when he opens your app he will come back at the same place with everything in order. (this is expected behavior from users and android apps). The system can easily kill your process and all static variables in it for memory maintenance, app inactivity etc...result=data lost. Thus its not safe to use it.
This article shows the different database approaches nicely:
database approaches
I use approach 2: An Application object which holds the single LocalDatabaseAdapter I made. This holds a DatabaseOpenHelper etc.
public class MyApplication extends Application {
private static LocalDbAdapter lDb;
public void onCreate() {
super.onCreate();
MyApplication.context = getApplicationContext();
lbm = LocalBroadcastManager.getInstance(context);
[..]
}
public static LocalDbAdapter getLDb(){
if(lDb==null){
lDb = new LocalDbAdapter(context);
}
if(lDb.isOpen()){
return lDb;
}else{
return lDb.open();
}
}
#Override
public void onTerminate() {
super.onTerminate();
lDb.close();
}
Now when I start the camera app and then return to my main activity, I get the database never closed error. As it points out, this db was created in the Application context, so why is it a problem that I dont close it in my Activity, I thought that was the idea. An important adavantage of having only one database object is that all methods of LocalDbAdapter that do any writing use the protected(this) statement around the insert or update.
In OnActivityResult, after the camera has taken a picture, I acquire the database like
LocalDbAdapter ldb = MyApplication.getLDb();
This has me seriously bummed out. If I close it in onPause of my MainActivity, I'm afraid that a background service using the same object gets in trouble, and Im even keeping the object local to the onActivityResult...
I'm considering creating a singleton wrapper for a Context so my model objects, if necessary, can open and read from a database connection. My model objects do not have access to a Context, and I'd like to avoid needing to pass a reference to a Context from object to object.
I was planning to place into this singleton a reference to the Context returned by Application.getApplicationContext(). This singleton object would be initialized in my custom Application instance before anything else would need to or have a chance to use it.
Can anyone think of a reason to not do this?
I would urge you to think about what reasons you have for not passing a reference of the application context into your model objects.
There are various well-documented disadvantages of using singletons. I won't go into detail here but you might want to consider:
How singletons limit your ability to properly unit-test your application.
Singletons hide dependencies between different entities in the code- you cannot determine dependecies from inspecting the interfaces.
You have no real control over the lifetime of a singleton, it could exist for the lifetime of your application. Do you really want to potentially hold a DB connection for the lifetime of your app?
The thread safety of your singleton.
If you valid reasons for not passing a reference to a context to other parts of your application then perhaps you should consider some other pattern- a factory might be one possible solution, a service another.
I'm not sure I get your idea, but here's what's been working for me:
public class MyApp extends Application {
private static MyApp instance;
#Override
public void onCreate() {
super.onCreate();
instance = this;
// ...
}
public static MyApp getInstance(){
return instance;
}
// misc helper methods
}
Pasted here to preserve formatting.
public class ContextContainer
{
private static boolean initialized;
private static Context context;
private ContextContainer()
{
//
}
public static synchronized void setApplicationContext(Context context)
{
if (!initialized) {
ContextContainer.context = context;
initialized = true;
} else {
throw new RuntimeException("ApplicationContext has already been set!");
}
}
public static synchronized Context getApplicationContext()
{
return context;
}
}