I'm working on an application that consist of a couple of activities:
Activity 1: main screen of an application with a "Start" button
Activity 2: user selects its identity from the list (more than one user is going to use the application)
Activity 3: user inputs password
Activity 4: user chooses an event from a timetable (every user has its own timetable with associated events)
Activity 5: user can choose an action connected with an activity.
Activities 6-10: user performs appropriate action.
Below some more information:
every activity from 6-10 have to know what user is logged in and what event has been selected
every activity from 6-10 has a menu that allows the user to go back to activities: 1 (to log out), 4 (to select different event), 5 (to select different action)
Since now, I've been using bundles to exchange data between activities but it seems to complicate the code as the number of actions grow (some actions use a 3-4 activities to collect data from the user). Passing all the data to every created activity doesn't seems to be nice.
I'm thinking about storing the "user name" and selected "event" as a static fields of a class. I will simplify the code very much, but I'm not sure whether this data will persist if the user let say at some point press "home button" and run another application that needs a lot of memory.
Will the data stored in static fields be safe?
It's better to have a custom Application object and store them there. The application object will live aslong as your app does.
http://developer.android.com/reference/android/app/Application.html
You can get access to the Application object by casting getApplicationContext() to whatever your custom Application type is:
public class CustomApplication extends Application {
private String userId;
public void onCreate() {
super.onCreate();
...
}
public String getUserId() {
return userId;
}
...
}
From Activity call: ((CustomApplication) getApplicationContext()).getUserId();
No. You are not guaranteed that these will all exist in the same classloader, in which case you would be dealing with different copies of these classes in different places, and not accessing the same shared state.
It may happen to work now; but no it is not something I would call "safe".
you can use the SharedPreference for this instead of using static variable/object into the class. check out this blog http://android-er.blogspot.com/2011/01/example-of-using-sharedpreferencesedito.html
You should just use the intent system as designed. Statics and Activities can get killed seemingly willy-nilly by Android. Even the Application class can get killed.
Say your have an app consisting of two activities, the first one lets the user store some data in the Application object. The user then clicks a button to start the second activity which displays the data. The user puts their phone down and comes back to it several hours later.
Android might decide to kill the app for various reasons during this time. When the user comes back, picks up the phone and relaunches your app a new Application object will be created and the second activity will be restored but the data the user entered will no longer be available in the Application object because it is a new Application object.
One way to help with this is to use SharedPreferences even for complex objects. Gson is perfectly capable of serializing and deserializing them to SharedPreferences.
To simulate this you can do the following:
$adb shell ps | grep your.app.package
to get the pid of your running app, then
$ adb shell kill -9
then open the app with the task switcher and you will have a new Application object but will be on the second activity.
Static fields work but not graceful. You just need a session object following singleton pattern.
Static data will persist on pressing home button and on opening your application again you will go to the same state where you left but when you run another application which needs lot of memory there are possibilities that you may lost your all static data.
But if you have very less static data then it may persist.
You can also look for SharedPreference.
You can Use the static unless and untill you are sure that this static variable will not conflict the users.
also static variable are class's property so it consumes more memory because lifetime is application level.
other i can suggest is to use shared prefereces which very handy. this shared preferences can be access by any of the activity of your application. so no need to pass bundle and worry about static fields.
last option is which is i dont find importance in your application is "Use Database to store and retreive".
Hope this helps.
Related
There are 3 activities: A->B->C. Each contains a Button (to open next activity) and a EditText.
For example: if I type some text in C and go back to A(by pressing Back Button), how can I see the same text there?
I know 3 solution:
LocalBroadcastManager
SharedPreferences
Create Singleton class with static field and then get this field in onStart method of A - which cons of this solution?
IMHO, there are always cons in using Singleton design pattern in your applications. Some of them are (from the top of my head):
Coupling between otherwise unrelated objects and flows through Singleton's instance
Emergence of a "global state", which makes debug a lot harder
Inability to mock static fields and methods through "conventional" mocking
The fact that a reference to Singleton can be easily obtained in any part of the application leads to a total mess (people stop thinking about dependency graph)
Singletons tend to breed: you introduce one, then another one, then you find yourself with 10 singletons which hold app's state in a "global cloud state"
Note that what you're trying to do is against Android guidelines - if the user taps on "back" button, then he should find the previous Activity or Fragment in the exact same state it had the last time the user saw it, without any additions (unless you explicitly don't want to save it in the back-stack).
If you still want to do it, then I could suggest several options:
Use SharedPreferences and store the value there. Get the value in each Activity and diplay it in onResume()
Use startActivityForResult() call in order to start new Activities and pass the value back in the result. Note that by default press on "back" cancels the action, therefore you'll have to override onBackPressed() method.
Override onBackPressed() method in Activity in such a way that it starts another Activity (instead of just popping the back-stack) and pass the value in the Intent that you use. You might want to use FLAG_ACTIVITY_CLEAR_TOP in this case.
Use some event bus that supports "sticky" events. When user inputs the text you post a sticky event to event bus. In onResume() of Activity you check whether event of this type exists and if it is - you update UI.
Once again - the fact that you CAN do what you want doesn't mean it SHOULD be done.
Simply set into onResume() method of your class A, a call to the Singleton class instance you want to save (or istance of Application class which is the same)
LocalBroadcastManager is not a reliable option. It assumes the bottom activity to still be alive, which might not be the case. While you use B, A might be collected to free resources. Also, you should unregister LocalBroadcastManager receivers onResume(). So, no.
Singletons with static fields are generally to be avoided. It’s not worrying for a single string of text, but singleton fields are easily forgotten and can lead to memory leaks. Better to avoid this pattern if possible, and in your case it is.
Possible options.
If the field is something that must persist, e.g. user editing his username, use SharedPreferences or another storing solution (saving to a server, saving to cache, saving to device SQLite database).
If the field is temporary and is the result of activity B, you can start activity B with startActivityForResult() and then send the result back to activity A through an Intent.
For your problem the simpliest solution - store your value in Application class. Any activity can access it and read/write values.
Cons is that if you accidentally store static reference to activity, it will cause memory leak.
You may try using EventBus for horizontal communication: Activity-> Service, Service -> Fragment, etc.
It has static instance by default plus you can subscribe/unsubscribe to it in onPause and onResume methods.
Another advantage is a STICKY EVENTS - you can post event from Service and it will wait until something handle it - Activity will receive this event when it is ready - after onResume().
I create an app that has tabs. Each tab using static factory to instantiate the fragment. I use it so that each time the tab is loaded, my app need not to load the content again.
But, my app is able to log in and because the fragment is static, when I log out and log in as another user, the content of the fragments is of the old user, not the new one. How do I erase or make it completely remove all the content of the fragment? Right now, the solution is to kill the app and ask the user to launch the app again, but it's ugly.
Ditch the statics. Ugh. Use the built-in bundles with the activity/fragment lifecycle callbacks for state management.
Another possible solution would be to store the state of the user's login in your application class. For all intents and purposes that is a singleton and you can be relatively certain that there will only be 1 instance of the isUserLoggedIn boolean (or whatever). Then query the state of that boolean before displaying any content in your fragments. That's probably the easiest means to an end.
I'm writing a simple android application which is basically a modification of the fragments demo available in the android documentation.
In the app, there is a file called Ipsum.java which has a static ArrayList of Strings called Headlines.
In the onCreate() method of the main activity, I have the following code which adds some elements into the array list.
if (savedInstanceState == null){
Ipsum.Headlines.add("String 1 ");
Ipsum.Headlines.add("String 2");
}
savedInstanceState is a Bundle that the system passes to the method, if the app is being resumed from some inactive state. The logic is that if savedInstanceState is null, then the app is not being resumed but being started as a new instance.
If I leave the app using the "Home" button and re-enter the app, the arrayList contains only the two elements: "String 1" and "String 2". (This is the desired behavior)
However, if I leave the app using the back button, and then re-enter the app, the "String 1" and "String 2" elements are added again. The array then has 4 elements.
String 1
String 2
String 1
String 2
(The contents of the arrayList can be seen because they are used to populate a listView)
It seems that the app is storing the contents of the static array list when the back button is pressed.. and that a Bundle is not passed to the onCreate() method when the app is restarted. Can someone explain what's happening here, in terms of the app life cycle?
May This Help you:
Lets start with a bit of background: What happens when you start an application?
The OS starts a process and assigns it a unique process id and allocates a process table.A process start an instance of DVM(Dalvik VM); Each application runs inside a DVM.
A DVM manages class loading unloading, instance lifecycle, GC etc.
Lifetime of a static variable: A static variable comes into existence when a class is loaded by the JVM and dies when the class is unloaded.
So if you create an android application and initialize a static variable, it will remain in the JVM until one of the following happens:
1. the class is unloaded
2. the JVM shuts down
3. the process dies
Note that the value of the static variable will persist when you switch to a different activity of another application and none of the above three happens. Should any of the above three happen the static will lose its value.
For More Detail: Read the Answer of Samuh in this Link... Click Here
Your activity is being resumed. If you want to control what happens, implement onResume().
See Managing the Activity Lifecycle for details.
EDIT:
Static variables are a Java concept. static just means that there is only one copy of the variable for the whole class. The alternative is that each object would have it's own copy.
So while your code is running, you just have one copy of the variable in your program. It doesn't get saved anyplace, unless you add code to do that.
Static variables are associated with a class and they will live as long as the class is in the memory,and destroy when class gets unloaded (which very rarely happens). It can happen when-
-You force stop your app.
-Application crashes.
-You clear your app data.
-Switch off your Device(Shutdown DVM).
I would like to determine if this is bad practice, since I have implemented this in some locations.
I have two activities, MainActivity and SecondActivity.
If I want to transfer the string "Hello" from Main to Second, I use a class called Transfer. In this class I have a static String that I set to "Hello", which I access from the onResume method of SecondActivity.
How does android manage the "Transfer" class? Is it tied to MainActivity and destroyed along with it? Is there any other behavior I should be aware of?
Given that the String field is static, I'd say is bounded to the whole process and not to the MainActivity.
The problem is, the android os might free your app's resources to start another process.
What may happen is that your app gets backgrounded, the os needs it resources and frees the memory, and then the user gets back to SecondActivity. The process gets recreated and the previously initialized static field is now null.
If your need is to pass Strings between activities, I would bundle them into the intent's extras.
Static members exist as long as the app is in the memory.
This approach works fine. Another way to share data between two activities is to make use of putExtra to put data into second activity and getExtras to get the data.
When an app have been put into the background and later resumes to an activity, is it possible that static class variables set in another Activity could have been reset by the garbage collector and have got the value set to zero?
I use a couple of public static int variables in my main Activity and use them as global variables in various other Activities. I have received a crash report in the developer console from Android Market where the only explanation I can find is that the app resumes to an Activity which uses the value of a public static int variable in another class, but the value has (mysteriously?) become zero. I know that it was set to something else when the app first started. Is this at all possible?
If my suspicion is correct, what is the recommended way to preserve the values of the global variables when an app is put in to background? Save them in SharedPreferences in OnPause() or use onSaveInstanceState or something else?
When an app have been put into the background and later resumes to an activity, is it possible that static class variables set in another Activity could have been reset by the garbage collector and have got the value set to zero?
It would not be "reset by the garbage collector". However, the process may have been terminated by Android, to free up memory for other applications.
what is the recommended way to preserve the values of the global variables when an app is put in to background?
Static data members should only be a cache. Data you want to retain regardless of what happens (e.g., process being terminated) needs to go in some persistent store, such as a flat file, SharedPreferences, or database. onPause() is a likely time to arrange to persist that data, as any time after that, your process could be terminated without notice.
Be careful with static variables. Follow the link for an explanation concerning Singleton (which also use a static variable to maintain state): https://stackoverflow.com/a/9004638/1127492
You can save this values on SQLite on method onDestroy in activity or another method with response to exit.