Storing Application context in SharedPreferences when app crashes - java

Currently im storing all of my users information and there friends information inside a class i have created called userInfoCore that extends Application so i can store the values in the Context. When my app crashes it gets rid of al those values and my users are forced to relogin, so i would like to store them in SharedPreferences to be grabbed again in the onCreate of my MainActivity.
I know how to store them, thats not the issue. The issue is i dont want to overcrowd my code with repetitive code and put the storing methods in all the onDestroy's of all my Activities, and i cant #Override onDestroy in my userInfoCore class because its not an Activity i imagine?
Some insite would be great. Thank!
EDIT:
Ive found out that this line in the android manifest is causing my Application Context data to be destroyed even when the user presses the home screen. android:launchMode="singleInstance"
My thoughts are YES i could store them in the onPause or do what #CommonsWare suggested. However like i said, i dont want to have to do all of that. If i can find the root of the cause of the issue... which i have. (The singleInstance in manifest) then i would be much happier.

Some insite would be great.
Update your persistent store when the data changes. A custom Application subclass, like any singleton, should only be treated as a cache or other transient spot for data. If you care about the values, persist them, at the point when the data is changed.

This is a good argument for using the Model-View-Presenter (or Model-View-Controller) pattern. By separating your Model (domain data and procedures) from your View and Presenter (Layout and Activity respectively) you only have to write the Store logic once.
Then you have two choices: either do as #CommonsWare suggests, have the model write itself whenever it changes, or add a simple call in each Application's onPause (onDestroy is too late! It may never get called.) to the model to tell it to save itself.
Note: the model can accept a context as a construction parameter for use in finding a shared preferences, or it can create it's own named preferences using the PreferenceManager

Related

Android - Launch multiple methods in others Activities

I'm really new to Android.
I have a fitness app where the user can change it's gym. There are several activities where the content depends on the user's gym.
One activity will show the workouts of the gym, another the athletes of the gym, etc...
What I would like, is to update all of these activities when the user
change it's gym.
I know how to do that in iOS, I just need to add an observer NotificationCenter.default.addObserver(), but I really don't know how to do that for android.
Is it possible? If yes, how?
First of all, according to Google your app should contain only one entry point, in other words one Activity, and have Fragments to represent contents of application.
Second of all, for solution to your problem you could use SharedPreferences. It has onSharedPreferencesChangeListener(); which could be used to listen for updates of information (e.g. GYM name, your custom user permissions, user role, etc.). When something changes in SharedPreferences you notify all dependent objects of application to change their information accordingly by using Observer pattern (P.S. can use RxJava for that). You could also implement SharedPreferences change listener in all the Fragments and updated their data there.
If, for whatever reason, you want to stick with using multiple Activities in your application, you could still use SharedPreferences, but instead of listening to changes, you just read preference values in Activity onCreate(); method and create content accordingly (change item visibility, color, etc.).
That's one of the approaches. Hope this puts you in the right direction. Good luck :)
I think that Android Architecture Components might help you with this, specifically LiveData which is an Observable.
Unlike a regular observable, LiveData is lifecycle-aware, meaning it respects the lifecycle of other app components, such as activities, fragments, or services. This awareness ensures LiveData only updates app component observers that are in an active lifecycle state.
LiveData will notify any of your activities that are coming to foreground.

Storing shared values in SQLite database vs passing through intents

My app initially makes a request for a list of objects from a server. These objects are currently kept in memory as an ArrayList<MyObject>. However, I want these objects to be passed through multiple activities before the user terminates the flow by pressing a button. I could make the ArrayList serializable and pass it through Intent extras. But I could also store MyObject(s) in a SQLite database and access/modify them in any Activity without having to go though intents. I was wondering what the norm is to accomplish this.
EDIT: forgot to mention that all the values would be deleted once the user terminates the flow.
SQLite is not the best way to go in your case since you don't need the data to be persistent after you close the app. It will just slow your app having to store and retrieve all entries on every activity transition. You can do one of the following instead:
Pass Serializable the way you described. Might be slower than the other alternatives though
Make MyObject implement Parcelable and use [intent.putParcelableArrayListExtra()](https://developer.android.com/reference/android/content/Intent.html#putParcelableArrayListExtra(java.lang.String, java.util.ArrayList))
Extend Application and load the list from the network in your Application.onCreate() and call getList() from activities that need it. That way you load it once and you don't need to pass it between different activities.

Why does intent requires context?

While working with different activities and starting them for results I have no choice but to use intent. Now intent requires context and that makes no sense to me. I know that context allows access to the application resources but
why do you need to know about the application resources when an intent is just a simple messenger?
Also, I am not so sure why some people create intent with the getApplicationContext() while other use this for the activity context????
Lastly, I am not so sure how the activity that calls for startActivityResult() receive a call back on the method onActivityResult() when I don't pass the "this" for the context but instead the application context. I thought that you have to use the "this" or passing in the current activity context that called startActivityResult() in order to receive a callback. That is just straight up java right? If you pass in a class then the other activity class will have a reference to your class and hence allows it to call the method in your class which is onActivityForResult(). However, this is not the case so what am I missing?
Intent itself does not need the Context. The constructor Intent#Intent(Context, Class) is just a convenience constructor, that internally uses the provided arguments to derive a ComponentName. ComponentName is in turn just a package name of your app and a class name to target. So ComponentName might be something like:
com.foo.bar/com.foo.bar.ui.activity.MyActivity
However, you can as well just use an empty constructor Intent#Intent() and provide ComponentName yourself (Intent#setComponentName(ComponentName)).
Therefore it doesn't matter if you provide your Application's or your Activity's context (the latter is just simpler to type). Also keep in mind that classes that require application context can call Context#getApplicationContext themselves, so this is not something you need to worry about.
About startActivityForResult() - Android manages internally a stack of your Activity records. Therefore it delivers the result to the previous Activity on the stack. It is the same way it knows where to return, when you click "back".
Please note it doesn't mean it maintains a stack of your Activity instances. These instances might be long gone - destroyed and garbage collected to free the memory. However the stack contains the information that allows to recreate them and to restore their state.
Intent does not need Context for itself but as you yourself pointed out that Intent is just a messenger. It also passes the current state of application/object to the newly created object so that it can understand that what exactly is going on in the application. And that is why we need to pass the context.
And, I believe that you want to ask about startActivityForResult(). Android itself takes care of the callback in the same way other callbacks are handled. You can take the example of Activity Life-cycle. Whenever it is started onCreate(), onStart(), onResume() are called itself by Android.
Not been much deep into Android development but still let me try with an explanation. So basically, context is a reference to linking your resources to your program. Each object is given its own context, which contains the resources required to set that object up. It is required for many objects to be created, and to get program identifying information, among other purposes. This makes it invaluable to set up new views and activities, but it can also be used for other purposes. See this Android Context for more information.
According to this page Activity inherits context. Thus, if you are in an activity, you only need to pass itself to use the context. It also contains a pointer to getBaseContext(). You might occasionally need to reference that, if you need the entire application context, but most likely you won't for a while.
There are ways of creating an Intent which do not require a Context. But if you want to target a specific class of a specific package, then providing a context for the target package is a ready way to do that. Refer this Context Lesson.
As explained by snctin in his answer getApplicationContext() offers application context. Basically the Application context is associated with the Application and will always be the same throughout the life cycle of your app. Also refer this post.
See Android - How to start (display) a new Activity. According to it
startActivity(new Intent(this, ProjectsActivity.class));
assumes your current class extends one of the Android Activity classes, which gives you access to the startActivity method.
According to Getting result from a activity, Starting another activity doesn't have to be one-way. You can also start another activity and receive a result back. To receive a result, call startActivityForResult() (instead of startActivity()).
For example, your app can start a camera app and receive the captured photo as a result. Or, you might start the People app in order for the user to select a contact and you'll receive the contact details as a result. This post will help you understand the same more better way.
Hope that helps. And also thanks becuase of your question I had a refresh with Android.:)

Android - Is using static fields a good practice for surviving activity restart?

Recently I have found a way to survive configuration changes. What I do is I declare the objects I want to protect as static fields. Is this a good practice?
It's never been a good practice. In my own experience I made a music player app with full of static variables and it's ram usage rocketed to more than 75 mb which is far more than any other of it's kind. The reason is, it stores the value of variable while activity is destroyed. if you have static variable on bitmaps or any other heavy file, it makes memory leaks which is not pleasant to see by user as not all devices got enough resources (ram) to keep up with heavy usage app.
Also static variables often make NullPointerExceptions as these are used by many other activities too and having a variable null may result in total failure of app...
I advise you to store the data in a SharedPreferences and just make one static field like integer and always use that to retrieve values from SharedPrefrences, its very clean and reduces the NullPointers. Moreover just one static makes u have more control over your app... For me it saves time to change 100's of static field rather than changing 1 as it's a lot easy and memory efficient...
I hope, I may help u a little !
Not really. You can cause a memory leak, because one of your static fields can hold a reference to the current Context, which could be destroyed without the reference.
The best way to survive configuration changes is to use the recomended method - Bundles. If you have to store something bigger and/or more persistant - use files, SharedPreferences or a database.
Use static may lead to nullpointer exception. Because when configuration change the current context is destroyed and if you access those context then it throws nullPointer exception.
So sharedPreferences or database is the best option for store the data.
Hope this help :)
One of the approach to retain Activity State, especially during configuration change is to make use of Fragments.
Instead of reinitializing your activity, you can alleviate the burden by retaining a Fragment when your activity is restarted due to a configuration change.
The fragments of your activity that you have marked to retain are not destroyed by Android system, when it destroyed your activity during configuration change.
You can add such fragments to your activity to preserve stateful objects.
Compare to using "static", this Approach is what being advocated at below link:
http://developer.android.com/guide/topics/resources/runtime-changes.html
I assume you can't just put in the bundle in onSaveInstanceState for some (very good) reason. So I think you have to compare with retain fragment.
If you have a static field in your class, like:
static Object myStaticReference;
you will no more worry about all the lifecycle jungle mess with onDestroy, onCreate, onSaveInstanceState of the Activity or Fragment. This will reduce considerably the code rows and make everything just easier to debug and understand. In any case you shall not have any reference in your object to a View, Activity, Fragment, Context and the like.
If for example you have something like this:
public class MyObject {
ArrayList metaData;
Context cntx;
public MyObject(Context cntx) {
this.cntx=cntx;
}
}
Then you still are in the lifecycle jungle, and you will have to pass (and repass) the reference of the context (and any other View relations you have) any time your Activity gets recreated in onCreate and still manage with onSaveInstanceState if there is any need. So in this case it is just useless.
With retain Fragment (which I suppose should be the other way) things are different too. The retain Fragment will last even when the Activity gets recreated, but you have to manage this additional fragment (the good part is that you do not need an UI for this).

Keeping data view/layout in Android after screen rotate/activity destroyed

I'm a little confused about the Activity being destroyed and recreated when the user's device is rotated.
I've been reading around, and I understand the rationale for doing so (it basically 'forces' the developer to make sure they haven't 'missed' anything upon rotation/language/other changes)
I'm happy to respect best practice if it is seen as such, however it begs the question:
How do I 'remember' the state of the game/app, so that when the screen is rotated I have something from which to re-generate what the user was looking at?
From what I can see, absolutely everything is destroyed, the base class constructor runs and all variables in the Activity are 'null'.
I suspect the 'savedInstanceState' (Bundle class) is where I would collect that data, but reading around it only seems to be used for when the app is closed from lack of resources (and a few other extremely fringe cases)
Am I misinformed or misunderstanding the purpose of savedInstanceState? Is it wise to abandon best practice (letting the Activity be destroyed) if I'm mindful enough to not miss anything upon rotation? Thanks in advance for any advice.
I should note this question applies to game programming (I'm not using a layout XML)
Do you need your activity to be recreated? Is there work you want to do on rotation? savedInstanceState is where you would store data to be passed to the recreation of the Activity, but since you aren't using XML layouts you may consider just adding android:configChanges="orientation" to your activity in the manifest. This will give you manual control over what happens during rotation change.
In additional to my original comment, I would override config changes for keyboard being show as well:
android:configChanges="orientation|keyboardHidden"
If there is work you want to do on rotation change you can override onConfigChange and do anything you need there.
It's hard to say that there is a time when you should always override config changes, but I often do it when I have no dependency on resource folders that are size or orientation specific and I'm doing a lot of work that would take too much time to recreate.
There are other best practices to store data while activitiy config changes.1. Developer Doc Handling Runtime Changes2. Alex Lockwood : Handling Configuration Changes with Fragments, This will answer all your questions reagarding config change and storing data.
Impt:
Fragment file to store data. You must set setRetainInstace(true) in order to store data and retrieve while your activity config changes.
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// retain this fragment
setRetainInstance(true);
}

Categories

Resources