My app has an Activity class called MainActivity and one of its members is
public static SharedPreferences prefsdefault;
My app has also a service (in another process) which runs in background. Inside the service I wrote
MainActivity.prefsdefault.getString(Key,"Hello");
The app sometimes throws null pointer exception at this line. Why? Does it mean that this member is cleaned up by the garbage collector when I close the activity and I cannot access it at anytime (when my service runs)? So what is the perfect solution for this?
Should I pass the MainActiviy.class to the service? It also happens when I implement a thread that requires a context.
That's because, even if your prefsdefault may have been initialized once, your whole app can be garbage collected and restarted again.
In that case your service will find that field as null. Using static fields inside activities is wrong for a bunch of reasons, the most important is that your app may be killed and restarted by the operating system and after that all the static fields are wiped out again.
The correct way to use shared preferences is to access them using getSharedPreferences whenever you need to access / write.
The other weird thing is that you say that the service runs in another process. In that case it should not be able to access to data from another process.
Because prefsdefault is NULL. I don't see that it is initialized.
You can do that by
prefsdefault = getSharedPreferences("my_preferences", Activity.MODE_PRIVATE);
Hot tip: Never make your SharedPreference instance static.
The reason for this is SharedPreferences is not initialised u dont need to do like this as SharedPreferences are global available with in app if MODE is Private just create new instance in service as well it will work
Related
Following solutions are mostly suggested to do this:
using Intent like here
using Handler like here
using SharedPreferences like here
Question
What is the problem of defining a public method to set the variable like:
public class Activity1 {
private int var1;
public void setVar1(int val){
var1=val;
}
}
and in Activity2:
public class Activity2 {
Activity1.setVar1(4);
}
It seems that it is applicable for both static and non-static variables
EDIT1:
It is a simple case of my current project. In original case, the Activity2 connects to a bluetooth Hub and receives data of several sensors. If the values are changed, it should pass the changed values (and off course sensor ID's) to Activity1 which is responsible for updating UI. The number of sensors can be more than 100 and update period is in range of 100 msec, which means a runnable reads the incomming BT messages each 100 msec and checks changes.
EDIT2:
BroadcastReceiver is also solution. But the question is: Whats wrong with defining a set method to change/update a variable. Is this method inefficient in terms of memory? Does it makes the app slow? Is it an inappropriate code?
I just wanna know what kind of problems/inefficiencies I would face if I define set methods to change activity variables.
keep in mind that an Activity instance is itself a Context, and that these can be very heavy in terms of the amount of memory they occupy because they keep a reference to the Activity's view hierarchy and all its associated resources. retaining long-lived references to Activity instances is a common source of memory leaks.
keeping that in mind, in this particular setup:
public class Activity1 {
private int var1;
public void setVar1(int val){
var1=val;
}
}
...invoking activity1.setVar1(...) would imply that the running instance of Activity2 has a reference to an instance of Activity1, meaning the system hasn't been allowed to garbage collect it. this pattern could eventually lead to the application exhausting its heap and crashing.
you also inquired about the possibility of exposing these methods as static methods. while you'd avoid the aforementioned problem, one potential pitfall here is if a user switches to another application, and the system is running low on memory, your application process could be killed by the system. as static variables are tied to the running process instance, when the user returns to your application and the system restores its state, var1 would be reset to it's default value (zero). (you could probably mitigate this by hooking into the lifecycle methods to save values into a Bundle instance, etc).
those are some reasons i can think of to avoid writing getters/setters into your Activity's interface.
Having reference to another activity is not a good way to do it since each activity has it own life cycle. The activity that you are referring to probably get get destroyed or the system might already start a new instance of that activity whilst you still reference to the old one.
Alternatively, you can use event bus (Otto for example) to publish object/event to another activity.
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.
I have a BroadcastReceiver that has to get and modify some data from the application class. This data is retrieved and modified in some activities too.
I read this post:
getApplication() vs. getApplicationContext()
And, as it says, getApplication doesn't always return the same object as getApplicationContext. In my case, if I set an integer in my BroadcastReceiver using getApplicationContext and then I check its value in my activity (using getApplication) it's always 0 (default value).
I tried using getApplicationContext in both places, but the objects returned aren't the same. Is there any way to get the same object in BroadcastReceiver as I get in my activity using getApplication? Should I use SharedPreferences instead?
Here's an example:
BroadcastReceiver:
MyApp app = (MyApp)context.getApplicationContext();
app.setNumPA(10);
Activity:
MyApp app = (MyApp) getApplication();
Log.d("MyActivity", "Num PA: "+app.getNumPA());
In my activity the log always shows "Num PA: 0".
You should definately use some persistent storage, for example SharedPreferences.
A reason behind this - your application instance can be killed by Android OS almost at any time (while your app in background). So, you can't rely on your variables, even static. You should save your state in persistent storage instead.
In my application I have Loginactivity. It has a static variable username and it will be assigned with the user enter values of username. Loginactivity launch activity A and A launch B. In A i use the variable Loginactivity.username.
Now due to some bug in B, application crashes. When I press force close, application is restarted and activity A is the current activity. In activity A I am using a static variable Loginactivity.username. I see that after crash this variable is getting its initial value which is empty string "";
Why is it happening like this? Can you explain this behaviour? So when application crashes all the activities in the stack are restarted? I see that oncreate of Loginactivity is not getting called. Then how is the static variable value getting changed ?
Yes, when an application crashes, the jvm for this app is restarted, your classes are reloaded and you lose all static variables as well as instance variables.
The solution is to remove the crash cause. :)
Use SharedPreferences instead, or store information in Application class
When your Activity B crashes the Android Dalvik Virtual Machine that your application runs in (each app has its own DVM which are separate processes) is killed. When you are starting Activity A the username is "" because Java by defaults sets all instance variable (class variable or fields if you like) to null (references), 0 (primitives), and "" for strings. So your Activity A is working correctly. You just need to either store the username in the shared preferences, a database, or trigger the event for the user to login again... I would also fix Activity B... Haha
This is because you have a memory leak caused by this static member you keep in LoginActivity.
I would consider keeping this variable in Application scope (custom application class) or save it into DB.
Anyway, just remember to nullify this variable when your application is done.
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.