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.
Related
In my app, I inject some singleton manager objects using dagger.
Suppose one of these managers, say myManager, keeps data in a list, say myList.
Also I have a BroadcastReceiver class, say myBroadcastReceiver which calls one of myManager methods, say myMethod, when it receives some particular intents.
If I open my app and wait until myList is initialized, then press home, and after that myBroadcastReceiver receives the intent and calls myMethod, myList is null (though myManager itself is not null).
I can't figure if it's a matter of android's natural behavior or if I've actually made a mistake that it happens.
I think your singleton class is getting unloaded due to low memory you need to save that list in onSaveInstanceState(Bundle outState) and retrieve the same in onCreate method
You could either implement a "save state" solution using onSaveIntanceState functionality provided by android in your activity or service or whatever component you're using
Or you can save your data locally in a file or even better a sqlite database, which could be very simple and straight forward to implement.
And by keeping your list "in memory" synch'd with the local storage, you'll never lose any data.
Simply using lazy loading, each time your list is null, fetch the data back from local storage.
I am looking for a way to keep reference of an object/instance that's a member object of a service. I know in case of Activities, we can save it by the provided onSaveInstance method. However, I couldn't find any similar way for a service.
I can use static object but it's unsafe as there is no guaranty, if the reference would be valid the next time, the service is created.
Another possible way would be, I store all the data on storage & later on when the service is created again, I can read the data from storage. Then traverse through information/data provided by the another class & find the relevant reference for the info read from the storage, which I think is very expensive interms of execution time.
So I am looking for a way to get rid of all this process & keep a strong reference (of the object in service) in the memory as long as the task/app is running.
Regards
You can use application class to persist data as
public class MyApplication extends Application
{
public MyDataClass data = new MyDataClass();
}
Then call it in any activity/service by:
MyApplication appState = ((MyApplication)this.getApplication());
appState.data.useAGetterOrSetterHere(); // Do whatever you need to with the data here.
In your manifest mention it as follows::
<application android:name="yourpkgname.MyApplication"/>
More info are like
Application object is an object whose lifecycle is same as our Application.
When Application starts this object is created automatically by Android Framework.
When you want to share data between more than one activities of your application or you want to retain something at application level.In that scenario you can use Application object as a global store for your application.
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
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.
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.