I know this issue has been discussed already (here for example), but It's still unclear to me whether it is, or not, safe to have a Preference activity that updates the SharedPreferences and background threads that read from it simultaneously ?
In my specific example, I have a PreferenceActivity and PreferenceFragments that the user interacts with to change the preferences, and a background Service that read and acts upon those prefs.
I don't want to leave it to luck, just want to make sure if I should be locking the SharedPreference object each time I read from it (because writing to it is done automatically through the PreferencesActivity).
Thanks!
As discussed in the post you linked. Unless you specifically tells Android in you manifest to run your service in another process it should be safe to write and read at the same time.
So it would probably be fine your case.
Related
I am new to android development and I see that there are different components (activities, services, etc.) where each component has a different life cycle.
I am encountering a situation where I have an object that should be accessed by different components. Namely, I have a list of objects that changes dynamically, and that list should be accessed by:
An activity that displays the list in a ListView
A broadcast receiver, that responds to alarm events scheduled in the AlarmManager.
The broadcast receiver may kick in hours after the activity was used. At this time, the activity may or may not be still alive in memory.
Is there anywhere I can put the list so it will be accessible to all app parts? My idea was to serialize the objects I need to share, write them to shared preferences and then recreate them whenever needed. I'm not sure it's a good idea, and even if it is - how would I design it? when would writing to shared preferences (or somewhere else) occur? when would reading occur (it would be preferable to read the object from memory when possible)?
You can put it in SharedPreferences if it a compatible data type, or serialize the list to a file in the internal or external storage (see saving files, you probably want internal storage for your situation).
You can read the list in the onResume() method of the Activity or the onReceive() method of the receiver. Writing will occur whenever a new element needs to be added to the list, you will deserialize the list, add the element and re-serialize it. You may need to place the reading and writing in a synchronized block or method to prevent simultaneous access.
If the list may be added to outside of the Activity when the Activity is resumed you may need to provide a broadcast receiver or other mechanism for the Activity to be alterted and reload the list.
As Gabe pointed out, you could store it in a static variable somewhere, but the way you described the situation serializing sounds like a better option. Otherwise the list is gone if your process is terminated by the Android system.
As kcoppock pointed out, you could use an SQLite database to store the data, but this sounds like overkill from what you described. You will be in for some additional coding without much benefit.
What you are looking for is the Android Shared Preferences. You can access Sharepreferences using getApplicationContext() from an Activity or a Service.
Hope this helps
If you don't want it permanently stored, put it in a static variable somewhere (anywhere they both agree to- a separate class would be a good idea). Then you can access the list unless Android kicks the class out of memory- which it should only do it its terminating the app due to lack of memory, in which case it doesn't matter much anyway.
If you do want it permanently stored, the filesystem is the best way. You'll need to synchronize access to it of course.
An application background service updates sqlite database. Therefore my activities are becoming outdated. Activity intents also contain outdated params so onCreate, onResume will crash the application. An easiest solution is to restart whole application. I don't want to add IFs to all onCreate, onResume methods in all activities to handle one special case.
I noticed that ACRA has following code executed after an exception has been handled.
android.os.Process.killProcess(android.os.Process.myPid());
System.exit(10);
However many people discourage use of System.exit(0). Is System.exit(0) really that dangerous for an Android application data integrity? Of course my code will close the database before existing.
Update:
I known how to use finish(), content providers, send broadcasts, read many answers here on SO, etc. However each of these approaches requires additional thousands lines of code. I implemented solution with System.exit(0) in ten minutes. The restart is so fast that it is indistinguishable from ordinary startActivity action. The db update/restart is done after longer user inactivity so the app is already suspended by the system. My app doesn't require real time syncing. During tests the application behaves correctly. This is quick and dirty solution.
Therefore I asked the question about possible side effects of System.exit(0). Not how I can do the design differently. I know that current design is not perfect.
System.exit(0) is an artifact from Java runtime, it isn't meant for Android. So in any cases using it would be worst solution.
Why don't you use Activity.finish() gracefully?
If you terminate the process you are living in, you'll loose most of the caching and restart time (~resume in the eyes of the user) for it next time will be higher.
Read more in Activity Lifecycle documentation on Android Developers.
Killing the process will not clean up any registered resources from outside the process. BroadcastReceivers, for example. This is a leak and the device will tell you as much.
You really shouldn't be updating the database schema from a background service. Do it when your activities resume.
If you are just updating your data, resuming an activity should validate the data specified by the Intent and tell the user if, for example, Item X is no longer there.
No tool is that dangerous if used carefully and for a specific, well thought off purpose.
However, In your case I do not believe System.exit() is the right way to go. If your application depends on data from a database, create a background service (or a few, depending on what you need) that will inform your application of changes and update the data. It is, in my opinion the right way to handle changes.
As for scenarios when you want to use System.exit() I personally sometimes use it when I can't recover from a critical error and no graceful degradation is possible. In those cases it is better to force all resources associated with your application to cease rather than just leave loose ends tangling around. To clarify, you should always use error handling before doing anything radical. Proper error handling is often the way to go.
But this is a very delicate topic and you are likely to receive quite a few diverging answers.
Therefore my activities are becoming outdated.
Use a ContentProvider and ContentObserver (or the Loader framework), or use a message bus (LocalBroadcastManager, Otto, etc.) to update the activities in situ.
Activity intents also contain outdated params so onCreate, onResume will crash the application
Copy the relevant "params" to data members of the activities. Update those data members as needed (e.g., from the handlers from the message bus-raised events). Hold onto that data as part of your instance state for configuration change (e.g., onSaveInstanceState()). Use this data from onCreate(), onResume(), etc.
An easiest solution is to restart whole application
It is not easiest, if you value your users, as your users will not appreciate your app spontaneously evaporating while they are using it. Do you think that Gmail crashes their own app every time an email comes in?
Next, you will propose writing a Web app that uses some exploit to crash the browser, because you cannot figure out how to update a Web page.
I noticed that ACRA has following code executed after an exception has been handled.
A top-level exception handler is about the only sensible place to have this sort of code, and even there, the objective is for this code to never run (i.e., do not have an unhandled exception).
There's an existing answer HERE that might give you some help as to why people say it's bad to use System.Exit().
Given that a Service may be running even when the launching activity is destroyed,
and also that data is passed usually using the extra bundle along the intent,
I wonder if the Service is able to directly access the activity's preferences.
My guess is no, it cannot. But it would save me writing a chunk of code if it can do it.
Assuming that You're asking about SharedPreferences. If so, then documentation is clear (by link above):
Note: currently this class does not support use across multiple
processes. This will be added later.
So, currently, if Your service is running in a separate process it's not possible. In that case I would suggest to store Your preferences not in a SharedPreferences, but in some base which could be accessible via specific ContentProvider.
P.S. Actually I tried access SharedPreferences from multiple processes and it has worked (at least in my case), but I've decided to use another way because of the documentation mentioned in the answer.
If you mean SharedPreferences then you can just call getSharedPreferences with the same name.
I want to save some small data structures (~1kB total), as well as the user's preferences, while my app is closed. The settings are modified only in my PreferenceActivity, but the data structures are modified in pretty much every activity. I've extended Application and made all the data structures and preferences static. I've then tried saving to SharedPreferences in my application class's onTerminate() and loading it again in onCreate(). However, onTerminate()'s documentation states that "It will never be called on a production Android device, where processes are removed by simply killing them".
Answers to this question suggest saving to SharedPreferences in the onStop() method of each activity modifying their data. Will this guarantee that the data is saved in all cases? Is there a way to avoid the waste of saving every time the user transitions between activities (or should I even care)?
I would honestly just save in the onPause() of each activity as is recommended by Android (i.e. when you write an email notice how the draft is saved when the app pauses, such as if the screen turns off). Unless you notice that it is causing lags/delays, it probably won't matter too much.
If you do notice lags with this "autosave" method, then you should probably have some sort of "Save" functionality implemented in each activity, which could, for example, entail using a ProgressDialog / AsyncTask combination.
I am developing an Android application consisting of over 10 activities. I have some state objects that I access in almost every activity and for this purpose these were implemented as global static variables in the MyApplication class.
I noticed that this approach is OK as long as the user is "in" the application. However, when he presses the home button and opens another apps and then goes back to my app through the "Recent activities" button, I see that the Android system resets the statics from the MyApplication so I have to deal with NullPointerExceptions. I know that this behaviour is caused by Android killing and recreating the application process.
I know that the best way to persist this kind of data is using SharedPreferences or SQLite, and I have no problem checking if MyState==null in the onCreate for and restoring it, but the problem is that I don't know when to properly store my state object (in prefs or database). I tried to override MyApplication's finalize() - no good, I saw that onLowMemory may not be called, I don't see how can I use onPause, OnStop and so on because I have so many activities that the serialization de-serialization would considerably slow down the app.
Any thoughts?
Thanks in advance!
It is better to not depend on the Application class unless you need to load some data, before anything else is started. Android can kill your process at any time to free resources, so your app should be able to handle this. Save all of your data in a snigleton class, and load it lazily -- check for null, and if so load on first access. It the state needs to be persistent, consider staving it file/shared prefs. If not, your app can probably live without it, so just make sure you check for null, etc.
Generally, you should persist state when activities become inactive -- onStop(), onPause(), but you can save as soon as it makes sense (e.g., the user has entered all required data). Spin off an AsyncTask to save data in the background and let the user continue their work.