Retain singleton instance after thrown exception - android

I have created an Android application that uses a singleton to hold its state. The class is instantiated when the application starts.
The application does make extensive use of fragments but is not a single Activity application.
The problem occurs when an activity crashes for some (any) reason.
Normally, Android closes the activity bringing to the foreground the previous one that was active. Since the previous activity also used the singleton somehow, it needs data from it to resume (for example). The thing is that the singleton is no longer available while the previous activity is running in a new Application Context forcing the Singleton to re-instantiate itself with no data of course.
One way to surpass this problem seems to be storing the state (serialized or not) in a file or the database but that means too many read writes on pretty much every other user activity which should be avoided. Apart from UX, this solution might lead to inconsistent or erroneous data from faulty or untimely synchronisations.
I would like to hear your input on the matter.
Cheers!
Here is the Singleton instantiation method.
final public class Data {
private static Data INSTANCE = new Data();
private Data() {}
public static Data getInstance() {
return INSTANCE;
}
}

If you declare your singleton as static on a root activity it should be saved. We used static varaibles linked to a baseline activty from which every activity dereives.
Antoher solution might be to use sharedpreferences.
It is nice to worry about performance but if you have many fragments and few activities, it would be the fragment that will cause the lion share of teh workload

1) You can use an Application class. It's gonna be destroyed at the very last stage.
2) If your data is not structured - you can keep it in SharedPreferences (as a String mapped with JSON for example)
3) If your data is structured - you should store it in DB (or better ContentProvider)

Related

Save multiple instances states of the same Activity in Android

I am developing an Android app and I would like to avoid reloading similar data when it comes from the same Activity using the same extra.
Specifically, when I launch my Activity 'A' with extra, I use this extra to load remote data from server.
From this Activity, I can relaunch 'A' with different extra and so on.
Example :
A:id1 --> A:id2 --> A:id3
But, it can also be an extra that I already loaded :
A:id1 --> A:id2 --> A:id3 --> A:id1
In this case, I wouldn't request the server again or lose the activities stack.
As I understand, "onSaveInstanceState" allows to save one instance of one Activity, but in my case, it's multiple instances of same Activity (with differents extras).
So, is it the solution to manage a list of saved instance states (bundle) for the same Activity ? Or something else ?
Thanks in advance
The onSaveInstanceState method isn't used in the way you describe. Check this out, it's the documentation for the Activity Class, specifically the Activity Lifecycle section. onSaveInstanceState is a method that gets called when the OS has to kill an Activity for some reason. It allows you to populate a Bundle which will help recreate that specific instance of the Activity where the user left off. Usually this happens because the user switched to a different app and the OS is killing the Activity to reclaim memory, but also happens on screen rotation, so it's a nuance of the platform that is important to at least be aware of.
As for your question, what I would do is use a database to store the information that is retrieved from the server. When you start an Activity, you can first check to see if the data that needs to populate that Activity exists in the database. If it does, load and display it from there, else make the server call.
This is nice, because the data will be persistent over multiple uses of the App. Going further, if the data from the server has the potential to be stale, you can easily extend this to display the data from the database initially, and fire off an asynchronous request for the data that will update both the UI and database when it returns. Your user will almost never be in a state where they're waiting for things to load, which is always a good thing!
Here's a good tutorial on the basics of implementing an sqlite database. This will also give you the added benefit of keeping the data stored over separate runs of your application.
As an alternative, if you don't really need the persistence or other features of the database and don't think that the overhead is worth it, you could create a Singleton class which keeps track of the data as its returned, perhaps implementing it using the Application class. It's important to note (and bringing us full circle) that any in-memory method of storing this data should be managed with onSaveInstanceState to ensure you don't lose any data if the Activity is killed at an unexpected time.
+1 for MattDavis' answer, but I'd also suggest you use what's known as the "singleton pattern".
Essentially, this is a way to cache things in memory. You create a class whose purpose is to hold all the database data you don't want to keep reloading. There's a single global instance of this object, which is initially null. You call a static method that returns that instance. If the static method finds that the instance is null, it creates the instance, populates it from the database, caches it, and returns it to the caller. From that point on, all requests for the instance just return the cached copy. If your app gets killed by the system for lack of resources, and started again later, it transparently re-creates the instance as needed.
This is a very common implementation, and works in a multi-threaded environment:
public class Singleton {
private static volatile Singleton instance = null;
private Singleton() {
// This is the place where you initialize the instance
// from the database.
}
public static Singleton getInstance() {
if (instance == null) {
synchronized(Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
I use this pattern in a lot of places; it's very handy.
To really do it right, you should also implement onLowMemory() or onTrimMemory() in your activities to release the singleton instance when resources are tight.

Main data model on android

I have an android application with a number of activities.
I have a singleton class holding my main data model which all activities access to get data.
The problem is that sometimes the android GC decides to destroy my singleton when the app in the background (when you press the home button).
Is there anyway that I can bypass this?
I've had this exact problem in a current application of mine, which needs to retain a large amount of data in various 'singleton' classes. The problem I encountered was as in your case; i.e. sometimes when bringing the application back to the foreground, some of the static 'singleton' classes have been destroyed.
The problem, I believe, is that the 'lifetime' of such classes can never be well defined or predicted. After all, it's a class sat there holding a reference to itself, so it's susceptible to being garbage collected when the system wants to grab some resources.
You're probably already aware that extending android.app.Application is a well-known alternative to using conventional Singletons. The solution that worked for me is to hold the actual instances of data singleton classes within an extension class of android.app.Application, whose lifecycle is well defined. Any other class that wants to access those singletons can obtain them using a getter in the Application class.
So for example I have a class called AppState that extends Application, that holds the instances within:
import android.app.Application;
public class AppState extends Application {
...
// "Singleton" instances that this Application extension looks after
private MSData singletonInstanceMSData;
public AppState() {
...
singletonInstanceMSData = new MSData();
...
// ---------------- Singleton instance control ----------------
public MSData getMSData(){
return singletonInstanceMSData;
}
// I also provide the means to 'reset' the instances on startup (this is
// something I need to do for my application - you may or may not need to)
public void resetControllerSpecificData(){
singletonInstanceMSData.reset();
...
Don't forget you'll need to modify your manifest if you extend Application.
AFAIR, lifespan os singleton is lifespan of his classloader - also complete VM . When user hit home button, your application goes in backgorund and is probably destroyed - you can not do anything against it. Your best bet is to save whatever is necessary in your onPause() callback ( or just use write through in every change of datza if you really paranoid )

Lifecycle of enum based singleton on Android

A few days ago I've discovered that singleton can become anti-pattern in Android. My singleton (class with private constructor and instance stored in static field) was deleted (instance was deleted despite the fact other activities were still using this singleton (via getInstance() method) so another instance had to be created ) because Activity from which it was first invoked was deleted (after invoking finish for only this one activity).
I've read already how this problem can be resolved however I've also just read "Effective Java". There is said that "Single-element enum type is the bast way to implement a singleton".
So now I'm wondering what would be the lifecycle of singleton created this way in Android application? Would it be the same like in case of "standard singleton implementation" so after destroying activity from which it was invoked the first time it will be destroyed (even if it used also in other activities)?
I'm not asking about proper android singleton implemenation or the singleton pattern itself (is it pattern or anti-pattern etc) but I'd like to know what be the lifecycle of such enum singleton object and when it will be destroyed.
In all cases, the classes you use are tied to the ClassLoader that loaded them. This is true in Java in general, not just Android. Android will isolate activities by using new ClassLoaders each time -- at the least, it doesn't promise it won't, and it does as far as I can tell.
Any singleton, or other class-level state, is tied to the Class which is tied to the ClassLoader. This is why your state "disappears"; it's actually that your calling code is seeing a new Class in a new ClassLoader.
So, your enum-based trick, or anything else along these lines, would have exactly the same behavior. You just can't "persist" activity information this way. You can and should write to a SQLite DB. You could probably stash it in the SharedPreferences too.
The application object is a good location to store information which needs to be accessible to various activity or service instances. You can retrieve it like this (where this is an Activity or Service):
private MyApplication app;
in onCreate(...){
...
this.app = (MyApplication) this.getApplication();
...
}
Remember to set the name also in the manifest:
Set the attribute "name" of the "application" tag:
The value is the path to the class relative to the package of your app.
The application object is created when the app is started, you can initialize like in an activity or service in it's onCreate() method.
One thing to remember: The application object can survive closing your "last" activity. In this case you may get the same application object with the state from the previous interaction with your app. If this is a problem you must somehow detect the initial start of your app (e.g. using a special launcher activity without UI, which initializes the application object and then starts a new intent.
BTW, the same may happen with singletons if they have not yet been lost to garbage collection.
My secure singleton implementation is like that:
I create a singleton class which has an attribute of boolean 'didReceiveMemoryWarning';
public class SingleTon(){
public boolean didReceiveMemoryWarning = true;
...
...
}
In application first screen(It is exactly first launch screen)(I have a splash screen that is visible 3 sec)
SingleTon.getInstance().didReceiveMemoryWarning = false;
And in every Activity's onCreate() method, check this boolean data,
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if(SingleTon.getInstance().didReceiveMemoryWarning){
{ Load your data from local to your SingleTon class,
because your app was released by OS};
}
}
it is my implementation.

Android: is it possible to refer to an Activity from a 2nd Activity?

This is a pretty simple question, but I have been unable to find anyway to accomplish what I am trying to do...
I want to launch a new Activity to display some complex information. Because of the complexity, it is undesirable to serialize the information into the intent's parameters. Is it possible for the the new Activity to get a reference to the launching activity, so it can call its methods?
If you use a custom application class, you can store information that will be kept between the activities.
See a tutorial here for instance.
The lifetime of an Activity cannot be depended upon. In this case, one way of sharing data is to have a singleton which holds the data to be shared between the two activities.
You can add a public static field to the first activity containing this (the first activity).
But beware that the first activity could be destroyed by Android while you are using the second activity, so you will have to implement a fallback method if the first activity is destroyed.
And don’t forget to unset the public static variable in the onDestroy() callback of the first activity or you will leak memory.
Is it possible for the the new Activity to get a reference to the launching activity, so it can call its methods?
Please do not do that. Android can and will destroy activities to free up memory.
Complex information like you describe should not be owned by an activity. It should be held in a central data model, like you would in any other application. Whether that central data model is mediated by a Service or a singleton or a custom Application object depends a bit on the type of data, caching models, risks of memory leaks, and so on.
You can make your complex objects public and static in ActivityA, and access them in ActivityB like this:
MyCustomObjectType complexFromA = ActivityA.complexObject;
this will work, however while in ActivityB, you can't always be sure that static objects from ActivityA will exist(they may be null) since Android may terminate your application.
so then maybe add some null checking:
if(null == ActivityA.complexObject) {
//go back to ActivityA, or do something else since the object isn't there
}
else {
//business as usual, access the object
MyCustomObjectType complexFromA = ActivityA.complexObject;
}
You could also use a Singleton object which extends Application. You would have the same problem when Android terminates your application. always need to check if the object actually exists. Using the Singleton extending Application approach seems to be the more organized way - but adds more complexity to implementation. just depends what you need to do and whatever works for your implementation.
You should create a separate class that both the activities can use.
public class HelperClass{
public void sharedFunction(){
//implement function here
}
}
I would recommend staying away from static variable in android. It can cause some unexpected behavior.
Use getParent() from new activity and call parent's method
Android Activity call another Activity method

Using the Android Application class to persist data

I'm working on a fairly complex Android application that requires a somewhat large amount of data about the application (I'd say a total of about 500KB -- is this large for a mobile device?). From what I can tell, any orientation change in the application (in the activity, to be more precise) causes a complete destruction and recreation of the activity. Based on my findings, the Application class does not have the same life-cycle (i.e. it is, for all intents and purposes, always instantiated). Does it make sense to store the state information inside of the application class and then reference it from the Activity, or is that generally not the "acceptable" method due to memory constraints on mobile devices? I really appreciate any advice on this topic. Thanks!
I don't think 500kb will be that big of a deal.
What you described is exactly how I tackled my problem of losing data in an activity. I created a global singleton in the Application class and was able to access it from the activities I used.
You can pass data around in a Global Singleton if it is going to be used a lot.
public class YourApplication extends Application
{
public SomeDataClass data = new SomeDataClass();
}
Then call it in any activity by:
YourApplication appState = ((YourApplication)this.getApplication());
appState.data.UseAGetterOrSetterHere(); // Do whatever you need to with the data here.
I discuss it here in my blog post, under the section "Global Singleton."
Those who count on Application instance are wrong. At first, it may seem as though the Application exists for as long as the whole app process exists but this is an incorrect assumption.
The OS may kill processes as necessary. All processes are divided into 5 levels of "killability" specified in the doc.
So, for instance, if your app goes in the background due to the user answering to an incoming call, then depending on the state of the RAM, the OS may (or may not) kill your process (destroying the Application instance in the process).
I think a better approach would be to persist your data to internal storage file and then read it when your activity resumes.
UPDATE:
I got many negative feedbacks, so it is time to add a clarification. :) Well, initially I realy used a wrong assumption that the state is really important for the app. However if your app is OK that sometimes the state is lost (it could be some images that will be just reread/redownloaded), then it is fully OK to keep it as a member of Application.
If you want to access the "Global Singleton" outside of an activity and you don't want to pass the Context through all the involved objects to obtain the singleton, you can just define a static attribute in your application class, which holds the reference to itself. Just initialize the attribute in the onCreate() method.
For example:
public class ApplicationController extends Application {
private static ApplicationController _appCtrl;
public static ApplicationController getAppCtrl()
{
return _appCtrl;
}
}
Because subclasses of Application also can obtain the Resources, you could access them simply when you define a static method, which returns them, like:
public static Resources getAppResources()
{
return _appCtrl.getResources();
}
But be very careful when passing around Context references to avoid memory leaks.
Dave, what kind of data is it? If it's general data that pertains to the application as a whole (example: user data), then extend the Application class and store it there. If the data pertains to the Activity, you should use the onSaveInstanceState and onRestoreInstanceState handlers to persist the data on screen rotation.
You can actually override the orientation functionality to make sure that your activity isn't destroyed and recreated. Look here.
You can create Application class and save your all data on that calss for use that anywhere in your application.
I know this is the very old question but using the ViewModel from the jetpack components is the best way to preserve the data between Activity rotation.
The ViewModel class is designed to store and manage UI-related data in a lifecycle conscious way. The ViewModel class allows data to survive configuration changes such as screen rotations.

Categories

Resources