I have a multi activity application and save data in the main menu activity that is used by many of the other activities.
One of my variables in the Main activity might be this
static double targetAngle = 45;
I might call that variable from another activity like this
diff = Main.targetAngle - angle;
or I might set it like this
Main.targetAngle = angle;
From this reference, http://developer.android.com/guide/faq/framework.html This seems like a correct way to pass data. But there is always talk about activities being killed by the OS at any time.
My question is, is this safe or not?
As an alternative, I have at the suggestion of SO members, a Class called Helper that has some functions that are used in every activity which also have some static data. For example, the Helper Class has this data followed by my functions
public class Helper {
static double[] filter1 = new double[]{0,0,0,0,0};
static double[] filter2 = new double[]{0,0,0,0,0};
static double cog = 0;
...
various functions....
}
I could save my shared variables in that helper class if that would be better. That class is called once a second and if it is ever killed, I am dead and really need to rethink things. I should mention that I have had no issues with what I am doing but one of my users is having his Nexus-7 crash and we don't know why so I was thinking he might have more applications running than I do, thus my question.
I should also mention that if the user exits the application, I have saved any variables that need to be saved in files on the SD card so they can be re-loaded. In other words, the loss of data when the application is killed is not an issue. My question is only if my main activity was killed when the application was still alive.
My thanks to selbie and squonk for answers in the comments. Lacking an official answer from either I post my own as I want to close this out.
What I conclude is that per this post
Using static variables in Android, the static variables themselves are not destroyed and what I am doing is safe.
This post, Clearing Static data onDestroy() states that "The value of static variables will persist as long as the class is loaded...The only reason ... that Android will unload a class is that your app gets completely removed from memory"
However, it may not be good practice as pointed out by squonk. Using a Class that is not an Activity to host static global variables and common functions may be better practice and is easier to maintain and generally cleaner. I will be moving in that direction as it has other advantages as well.
In either case, it is clear that when the application is destroyed, the variables will be re-initialized and needs to be reset manually. In my case, I store data on the SD card in files, which is one of several ways to save data.
I found the above links with a new Google search. Obviously I should have done a search with that wording earlier but none of my searches returned useful results, mostly finding the singleton vs extension of application debate.
static variable cannot use over through Activity. As you said, they become initial value when you called again from another activity even you assign value.
Use SharedPreference or pass value with Bundle.
Related
In my Android App I have a static class to share some variables and functions within the whole application.
some variables from this class are initiated in other Activities (once, for example, user select something from the grid view, then I store its selection in this static class to use it later in another activity)
Everything was fine, but it looks like that after some period of inactivity of the App (once it stays in the Background), this static class is destroyed and then re-initialized with default values, which are "wrong", let's say.
Or, probably, the whole app is disloaded, and after I call it back, it restores the last activity which is trying to access some variables but they are re-initiaed
It there any way to prevent class from re-initialization or keep the static values or to keep these values somehow else and restore them once activity is re-created?..
Thanks a lot!
Instead of looking for ways (or rather hacks) to stop re-initialisation of your classes or storing the variables in a static class I would rather suggest you to store the state of your app in local storages like Shared Preferences or the SQLite DB.
The advantage of this would be you can access this variables in any part of your app and secondly you will get rid of those static classes and variables which are the main culprit of Memory leaks and ANRs.
I think sharedPreference is the perfect alternative for you. It helps to store your data locally.
Android Studio now displays a warning when a class contains a static Context object. It says this causes a memory leak. However, I have noticed this is also done in android libraries. For instance, the LocalBroacastManager class has a static instance and it contains a context object.
So how bad is this as a memory leak?
I have a singleton geofencing class that runs in the background and saves a boolean to sharedPreferences indicating if the user is in the geofence or not. To save the preferences I need a context object, but since the method is an overridden method, I have no way of passing a context object in.
How can this be accomplished without a context instance variable?
Its about the worst you can have. Lets say that you have an Activity, and store that as a static Context. Unless you null it out when the activity finishes, you now have leaked a whole Activity. That means every variable that the activity holds is leaked, including the entire view hierarchy. Its basically preventing anything in that Context from freeing up.
The best thing to do is not to store a Context, but instead to pass it in as a parameter to functions that need it. If you must store a Context, do not make it static. A non-static variable won't leak it so long as nothing in the framework continues to hold a reference to the object after the activity is finished.
If you absolutely must use a static Context, make it the Application context. That one is valid over the length of your app, so it can't really be leaked.
Statics should be rarely used, especially in Android. There are ways and reasons of using statics, but in 90% of cases, it is just a misuse of them.
Keeping the context as a static variable is a big no-no. Imagine following scenario:
You go from activity A to activity B.
While in activity B you keep activity B reference as static Context somewhere.
You go back to activity A. Activity B should be destroyed, but instead it is kept, since you keep a static reference to it.
Now you go again to B from A, et voila - you have two B instances: the one you see and another one kept as static context.
You may NEVER have two instances of the same activity. It could cause a lot of issues.
Now, I'm aware that a lot of developers (even ones making libraries) every now and then make mistakes and use anti-patterns, so you should not blindly rely on practice/pattern seen in someone other's code. Hell, I've even seen a lot of garbage code in something written by Google devs.
If you really need a singleton (not Singleton pattern (uppercase S)), but single instance of some class, if you don't want to use libraries like Dagger and so, you can instantiate that class in your Application class, and then reference it from wherever you want.
For quite some time I've had troubles passing variables from one Activity to another, and I've usually had to resolve to some pretty ugly Static-class-hacks to make it work.
Generally something along the lines of a static method that I call with the type of the Activity, along with the variables the Activity requires. These gets stored in a static variable, and retrieved in the constructor of said activity.
Like I said, pretty ugly. And there's no such thing as "myActivity.StartActivity(new Activity);". All of the overloads for StartActivity takes either an Intent, or a typeof(MyOtherActivity).
So my question is, have I completely misunderstood the concept of Activities, or am I simply missing a completely obvious way to pass arguments to them?
#Edit: The reason I want to pass an actual reference to an object, instead of simply a copy of the object, is because I'm trying to pass a View Model from an overlying Activity, down to the new Activity. And of course any changes made to this view model, should be reflected on the parent activity, which will only be possible if the the two activy's viewmodels points to the same instance.
I'm writing the app using Xamarin.Android, but the code is nearly identical between C# and Java, so answers in either those languages is fine.
The problem is that Android can kill the process hosting your app at any time (if it is in the background). When the user then returns to your app, Android will create a new process to host your app and will recreate the Activity at the top of the stack. In order to do this, Android keeps a "serialized" version of the Intent so that it can recreate the Intent to pass it to the Activity. This is why all "extras" in an Intent need to be Parcelable or Serializable.
This is also why you cannot pass a reference to an object. When Android recreates the process, none of these objects will exist anymore.
Another point to consider is that different activities may run in different processes. Even activities from the same application may be in different processes (if the manifest specifies this). Since object references don't work across process boundaries, this is another reason why you cannot pass a reference to an object in an Intent.
You can also use The Application class to store objects globally and retrieve them:
using Android.Runtime;
namespace SomeName
{
[Application]
public class App : Application
{
public string Name { get; set;}
public App (IntPtr javaReference, JniHandleOwnership transfer) : base(javaReference, transfer)
{
}
public override void OnCreate ()
{
base.OnCreate ();
Name = "";
}
}
}
And you can access the data with:
App application = (App)Application.Context;
application.Name = "something";
I choose to do this on the Application calss because this class is called on the App startup so you don't have to initiate it manually.
Keep in mind that variables which are scoped to the Application have their lifetime scoped to the application by extension.
This class will be Garbage Collected if the Android feels it is necessary so you have to modify the code to include this case also.
You can use SharedPreferences or a Database to save your variables in case they get deleted and retrieve them from the App class for faster results.
Don't be overly wasteful in how you use this approach though, as attaching too much information on this class it can lead to a degradation in performance. Only add information that you know will be needed by different parts of the application, and where the cost of retrieving that information exceeds the cost of storing it as an application variable.
Investigate which information you need to hold as application wide state, and what information can simply be retrieved straight from your database. There are cost implications for both and you need to ensure you get the balance right.
And don't forget to release resources as needed on OnStop and OnDestroy
I rarely use intents, i find this way better.
In android, are using static variables a recommended practice?
E.g, implementing a Singleton pattern in Java, I usually do:
private static A the_instance;
public static A getInstance() {
if (the_instance == null) {
the_instance = new A();
}
return the_instance;
}
Also, when does this get cleaned up by the Android JVM?
static fields are attached to the Class instance as a whole, which is in turn attached to the ClassLoader which loaded the class. the_instance would be unloaded when the entire ClassLoader is reclaimed. I am 90% sure this happens when Android destroys the app (not when it goes into the background, or pauses, but is completely shut down.)
So, think of it as living as long as your app runs. Is Singleton a good idea? People have different views. I think it's fine when used appropriately, myself. I don't think the answer changes much on Android. Memory usage isn't the issue per se; if you need to load a bunch of stuff in memory, that's either a problem or it isn't, regardless of whether you encapsulate the data in a Singleton.
I think static variables are OK.
This is what Android doc says:
http://developer.android.com/guide/appendix/faq/framework.html
How do I pass data between Activities/Services within a single application?
A public static field/method
An alternate way to make data accessible across Activities/Services is to use public static fields and/or methods. You can access these static fields from any other class in your application. To share an object, the activity which creates your object sets a static field to point to this object and any other activity that wants to use this object just accesses this static field.
Contrary to what other people say - it is more than ok. Granted, it has some structure to it. In the official googlesamples/android-architecture repo it is used under todo-mvp-clean (Todo app implementing MVP pattern and following Clean Architecture principles).
Check out this file.
What you can see is a lot of static methods referencing singleton getters.
Modern, less error prone and convenient alternative is the Dagger DI framework.
I'm not sure if such approach is good for mobile platform where you have limited memory available to you. Not to mention that the application will be run on a multi-tasking enabled device.
I think, this approach may hog memory from the device but I have no document to support this. Perhaps someone who's more educated than me can share their thoughts.
No. Don't do it! Singleton is an anti-patern!. Instead, use dependency injection, whether via a framework (such as via Dagger or Roboguice) or by explicitly passing the instantiated object.
I have created a SettingsActivity for my app. In this Activity I am using the SharedPreferences class to do handle the user editable preferences.
While setting up the SharedPreferences, I have to load them in the onCreate of my main activity and then again in the SettingsActivity. The probably was that both calls to the getXXXX() methods require defaults and I figured that it would not be good to hard-code the default values into both places because I would imagine it would be problematic in the future if I ever changed them.
Which is the best/most popular (or accepted standard) of doing this?
Create a global variables class in which I import into each activity and define my default constants in there?
Use putExtra and getExtra to pass the data from the main activity to the settings activity?
Any other suggestions?
I think Squonk has a good answer, but if you're looking for an alternative, consider creating a Settings class with all of your settings as members. It could have a static method like loadFromPreferences(Context) that would return a Settings object constructed from SharedPreferences, using whatever defaults you need. It could also have a saveSettings(Context) method to save your edits. Hope that helps.
Personally, in this situation, I'd put the default values in a resource file. In that way there's no need to use a global variables class or a helper class. Android resources already do that for you.
See:
Providing resources
More resource types
Instead of using a class with static values why dont you extend the Application class which will always live when the application's process lives. you can keep shared methods and variables in it
I would highly recommend opening the SharedPreference in the onCreate of both activities. Every time I've tried to use global variables, the values disappear in a way that's difficult to detect and fix. Activities are destroyed when they are closed. Services can be removed from memory at any time. The application context will be destroyed if your services are sleeping and don't have activities in memory.
That being said, putting a variable in the application context is probably the best place. Create a class that extends Application and set AndroidManifest.xml to use this. Just don't expect the value to be there if you try to use it from services or broadcast receivers.
Also, unless you're having problems with the activities loading too slowly, you're better off spending time on features than optimization.
You can declare objects as public static and reference them from another class. ActivityA:
public static int testIntegerA = 42;
Intent intentInteger = new Intent(getActivityContext(), ActivityB.class);
intentInteger.putExtra("INTENT_EXTRA", testIntegerA);
startActivity(intentInteger);
ActivityB:
public static int intentInt, staticInt;
staticInt = ActivityA.testIntegerA;
intentInt = getIntent().getExtras().getInt("INTENT_EXTRA");
Now both intentInt and staticInt equal 42;