I have recently encountered a problem where sometimes accessing a singleton from a background Service threw a NullPointerException.
The singleton instance is constructed in the launcher activity and is guaranteed to not be null for the duration of my app.
This leads to my questions of how the Service lifecycle is related to the application process's lifecycle. Concretely, here are the specific questions:
When an activity goes into background, will the containing process be swapped out to secondary storage? If so, how does that affect the service running in the background?
When a service is restarted by the android OS, how much of the containing process will be restored? Will the process just become a wrapper for the service?
Update: Here are the code related to my singleton Implementation
private static User curUser = null;
public static User getCurUser(){
return curUser;
}
public static void setCurUser(User u){
curUser = u;
}
There is only 1 place in my app that calls setCurUser(), that is in the launcher activity, which gurantees that the user is non-null before setting it.
Related
The code is like below:
public class MyTestHelperHelper {
static MyTestApi storeApi = null;
public static synchronized void initial(Application application) {
if (storeApi == null) {
storeApi = new MyTestApiImplImpl();
storeApi.initiImplal(application);
}
}
public static MyTestApi getInstance() {
return storeApi;
}
}
MyTestHelperHelper's initial method is called in Application's onCreate, which is in UI thread. MyTestHelperHelper's getInstance method is called in the Activity's onCreate, which is also in UI thread.
In most case, it works normally. But sometimes, it return null with MyTestHelperHelper's getInstance, which leads to the NPE when I do further operations.
Though the case is rare, I can see it several times in the crash report.
I just don't quite understand why:
There is no write to the "storeApi", except in the initial method.
Both initial and getInstance is in main thread, because initial is called in Application onCreate, and getInstance is called in Activity onCreate.
If my app is in background and process is killed, I think the application will be re-created when bring to foreground, so the initial is called.
Seems the NPE occurs only when
1.process starts without application's oncreate. OR
2.When memory is low, many process data, including static variables, classloaders, classes, etc, are cleaned, except the application instance stays in the process. Is it possible?
It is not possible that a process is newly created and Application.onCreate() is not called.
Whenever a process is created, Application.onCreate() will be called.
However there are certain scenarios where lifetime of static variables could be impacted.
Lifecycle of static variable starts with class been loaded by the JVM and ends with class being unloaded.
A static variable will remain alive as long as one of following won't happen:
The class is unloaded due to low memory conditions.
Note: In this case Application object still persists since it will be the last object to be deallocated. This deallocation cannot be controlled by apps but determined by OS. This could happen if your app is in background and OS wants to relinquish the memory.
The process is killed -> Both static object and Application object are deallocated.
You can use onSaveInstanceState() and onRestoreInstanceState() to save and restore state of your static variable respectively.
If I leave a thread running when I quit my android app, can I get access to that thread when the app is restarted? I know that the thread is still associated with my app because I can kill it by going to settings-apps-force stop.
more details: my app connects to a device via bluetooth. when i rotate the tablet, it restarts the app, but if i don't stop all the threads, the old thread reconnects to the device and the app is not able to connect with a new thread.
I have fixed the basic problem by not allowing the app screen to rotate, and by killing the connect thread onDestroy(). but I would like to know how to re-connect with that sort of zombie thread just out of curiosity.
I can see threads that I don't recognize in Thread.enumerate(), but I don't know how to get access to those threads, other than seeing the name and their state.
The way I deal with this in my apps is to override an Activity's onRetainCustomNonConfigurationInstance() method, which allows you to retain an object through the restart that happens when the screen is rotated. Here's how I implement it.
I have an AsyncTask that performs a web request. The AsyncTask is in a separate file, and takes a reference to the calling Activity as a listener for some callbacks I have implemented. So the constructor for my web request AsyncTask is something like this:
private Callbacks listener;
public WebRequest(Callbacks listener) {
this.listener = listener;
}
I implement onRetainCustomNonConfigurationInstance() in my Activity like this:
#Override
public Object onRetainCustomNonConfigurationInstance() {
if(webRequest != null) {
webRequest.detachFromActivity();
return webRequest;
} else {
return null;
}
}
Now, when my screen is rotated, the Activity restarts, and if my AsyncTask is running, it will save a reference to it here. Notice that I also "detach" my task from this current Activity, which will now be destroyed. I accomplish this in my task by just making the listener (which is the current Activity) null. Like this:
public void detachFromActivity() {
listener = null;
}
Now when the Activity restarts, in onCreate(), I check to see if there was a retained reference to my running thread by calling getLastCustomNonConfigurationInstance() like this:
Object retainedRequest = getLastCustomNonConfigurationInstance();
if(retainedRequest != null) {
if(retainedRequest instanceof WebRequest) {
webRequest = (WebRequest) retainedRequest;
webRequest.setListener(this);
}
}
Since the reference to my running thread is passed as an Object, I need to retrieve it as an Object, then check if it's an instance of my AsyncTask, then cast it if it is.
The last step is to "reconnect" the callbacks to this NEW Activity, which was just created, so the task knows where to send the results. I use the setListener(this) method to do it in my task, like this:
public void setListener(Callbacks listener) {
this.listener = listener;
}
Now I can re-attach a reference to an old thread with a newly re-created Activity. You may not be using an AsyncTask, but the concept is the same and should work for any Thread, or any object you want, really.
Hope this helps!
Im not sure on your question, but what you are doing is kinda wrong. Screen rotation are UI changes and they should not affect your other code.
Check this answer for some guidance- http://stackoverflow.com/questions/5913130/dont-reload-application-when-orientation-changes
PS: NoChinDeluxes answer is also good for decoupling UI with other elements
The basic problem, as you have discovered, is that you have implemented your app in such a way that your bluetooth connection is logically bound to an Activity (i.e. the Activity is responsible for keeping track of the thread handling bluetooth activity).
To have the bluetooth connection reference survive a rotation, you will need to decouple it from the Activity. There are a number of ways to do this, depending on exactly what your requirements are.
You could, for instance, implement the bluetooth code as a Service.
There are other ways as well - for instance, take a look at Activity restart on rotation Android
I am writing an Android app that plays music. When the Activity is the foregroud, the media control buttons (Play, Pause, Stop, etc..) are visible. The music should keep playing when the user exits the activity. He can restart the Activity to hit the stop button later if he chooses.
At present, the instance of MediaPlayer is wrapped by a class that is a singleton:
public class MediaPlayerPresenter {
public static final String TAG = MediaPlayerPresenter.class.getSimpleName();
MediaPlayer _player;
PlayerState _state;
public MediaPlayerPresenter() {
_state = PlayerState.Idle;
_player = createMediaPlayer(); // calls new MediaPlayer and hooks up event callbacks
}
static public MediaPlayerPresenter getInstance() {
if (_staticInstance == null) {
_staticInstance = new MediaPlayerPresenter();
}
return _staticInstance;
}
// not shown - code that keeps track of MediaPlayer events, state, updating the
// view, handling view events, etc...
As it works now, the activity may get destroyed or stopped as a result of the user leaving the application, but the running process (evidently) lives on as music continues to play. When the activity is restarted or brought back to the foreground, the media controls of the view re-associate with the already running MediaPlayer via the singleton instance above.
So far, so good. But I've been reading that background music should be managed by a service. So my questions:
Why is it better to use a Service to maintain the lifetime of the MediaPlayer instance instead of a plain old singleton class? Is it because the lifetime of the singleton running in a process without an Activity or Service is not guaranteed? Or something else?
I'm ok with using a Service in lieu of a singleton. And if I understand correctly, Service and Activities of an application run in the same thread. If that's the case, when my Activity starts back up again, is it ok for it to access the the instance of the MediaPlayer class owned by the Service class directly ? I don't see much value of using a binder interface for the Activity code to to talk to a local Service in the same process.
Any good examples of a background music player using a Service pattern?
Background playback is the key here.
The music should keep playing when the user exits the activity.
If that is what you really want then I am afraid a singleton is not an good option. No guarantee if your singleton object will be keep alive once the user exits the activity. Your singleton will be eligible for gc() once the activity is destroyed and when your device runs low on memory, it will be destroyed so will your MediaPlayer lifecycle.
If you are testing this on a device , go to Developer options and check "Don't keep activities ...". Exit the activity and see the outcome.
Personally I will go with a Service, and try to connect back with the service in onResume().
As for the tutorial please refer to this.
Background audio streaming tutorial
Why implementing a Singleton pattern in Java code is (sometimes) considered an anti-pattern in Java world?
http://blogs.msdn.com/b/scottdensmore/archive/2004/05/25/140827.aspx
http://caines.ca/blog/programming/singletons-anti-pattern-or-worst-anti-pattern-ever/
So I have the following:
A Common class that many of my Activities access in my android application, via setting the class in my manifest:
<application android:name="com.dev.games.phraseparty.Common"... />
Now, within this class I have several objects that are constructed to preserve application state and common services to perform applications that are constructed in the Common constructor
ie
GameStateVO gameState;
public Common()
{
gameState = new GameStateVO();
}
My problem is that my Activity has an Admob ad. When the user clicks on the ad, it calls the webbrowser intent to open the ad URL in a webbrowser.
Now, when I click back from the webbrowser launched by admob, it takes me back to the caling activity and the OnCreate method is called.
This activity then gets a null pointer exception because it will do something like:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Common common = this.getApplication();
//null pointer here since the game state VO is null since the Common has lost its state.
int score = common.getGameState().getScore();
}
If you have no active foreground activity, then your process is ripe for shutdown by the OS to obtain more resources. The browser app in particular i've noticed uses a lot of resources and can quickly lead to background activities and later processes being killed off. Having a service can help keep your process around, but even then it can still be killed off if needed. I think you'll need to use the activity lifetime cycle method to save & restore your state. See the process lifecycle section of the docs for more info
You might want to look into implementing the onSaveInstanceState method: this lets you store any relevant information before it gets killed off. See http://developer.android.com/reference/android/app/Activity.html#onSaveInstanceState%28android.os.Bundle%29 for the actual call you need to implement, and Saving Android Activity state using Save Instance State for a quite excellent example.
My app is made of two activities, A and B. I'm considering this sequence of steps:
Activity A is started.
A launches B [A is paused, B is running].
B launches a map intent [A and B are both paused now].
Now the user is using the maps application and the system decides it needs more memory. Can the system kill only one of my activities for memory, or will it always kill all activities in a "process" in this situation?
Both activities share some static data like:
class Data {
public static String mName;
public void save() {
// write to file: mName;
}
public void load() {
// mName = read from file;
}
}
ActivityA.mTextView.setText(Data.mName);
ActivityB.mListView.addText(Data.mName);
so when any activity in my app gets onSaveInstanceBundleSate() called, I call Data.save() to write it to disk. Now the question is, in an Activity's onCreate() method, should I simply check to see if Data.mName == null, and if so, assume the Activity is returning from a kill state, and try restoring from disk again? I'm unclear when this restoring should be done, considering Activity A may or may not still be alive etc. - and I don't want to corrupt state if Activity A is still alive but B is coming back from a kill state,
Thanks
Thanks
Probably the best solution is to move your static data to a Service. That way the data can be saved and restored when android shuts down the Service rather than when Android shuts down either of the individual activities using the data.
Without using a Service (or alternately a Content Provider, or even overriding Application although that seems to be frowned upon), you have to manage that lifecycle yourself, which as you've seen can be tricky.