Reputation: 299
I am re-submitting this question, as I don't think my last one really went into the problem I was having.
So I have a thread that returns and then uses a handler to update the UI as the following:
public void completeSignIn(final boolean success, final String error) {
Log.d(Constants.LogTag, "Finalising Sign In...");
final Looper mainLooper = Looper.getMainLooper();
final Handler mainHandler = new Handler(mainLooper);
mainHandler.post(new Runnable() {
@Override
public void run() {
if (success) {
TextView tv = (TextView) getActivity().findViewById(R.id.register);
tv.setText("SIGNED IN!!");
} else if (!success) {
}
}
});
}
The problem I am having is that because the thread could return at any point after it is done querying the server, there is not gaurantee that getActivity() will return the Activity. I have found that if I rotate my device as the thread is about to return, this bit of code can be called inbetween the activities destroy/create cycle. I am unsure if it is important that I am using a fragment here, but I don't think there is any harm in using the parent activity to update views?
So I am unsure how I could force the handler to wait until the activity is created - is this possible, or is thee a standard way of dealing with this? As I don't see this in other apps I have tested.
UPDATE
I put some logs in my fragment and managed to get the following to illustrate my issue:
07-09 22:17:15.164 25435-25435/? D/Kevins_Tag﹕ Detaching Activity...
07-09 22:17:15.234 25435-26702/? D/Kevins_Tag﹕ Signing in...
07-09 22:17:15.234 25435-26702/? E/Kevins_Tag﹕ Activity is null
07-09 22:17:15.234 25435-26687/? D/Kevins_Tag﹕ Finalising Sign In...
07-09 22:17:15.284 25435-25435/? D/Kevins_Tag﹕ Attaching Activity...
07-09 22:17:15.284 25435-25435/? D/Kevins_Tag﹕ Activity Exists
As you can see, the thread is calling the UI in between detach and attach...
Upvotes: 1
Views: 52
Reputation: 38319
As you explain in your question, method completeSignIn()
is in one of your fragments. The Runnable
that completeSignIn()
contains is an inner class of the fragment, and as such, holds a reference to the fragment. That is how the code in the Runnable
can call fragment method getActivity()
--the call is made using the "hidden" fragment reference.
You correctly observe that during a configuration change, completeSignIn()
can get called after the fragment has been detached from the activity, resulting in a null activity reference. You ask:
I am unsure how I could force the handler to wait until the activity is created
That is not possible in this case. However, even if it were, it wouldn't help. The fragment that completeSignIn()
has a reference to is dead. It was detached and destroyed and will eventually be garbage collected. When your activity is recreated, the old fragment is not used--a new fragment is constructed and goes through the creation lifecyle steps using the saved state of the old fragment.
It's difficult to suggest an alternative approach without knowing how the overall server sign-in status and display is managed. One option would be to maintain the status in a singleton in addition to updating the sign-in view when sign-in completed. For configuration changes, where the view may not have been updated because it was inaccessible, the activity would be responsible for updating the view when the activity is recreated, using the status from the singleton.
Upvotes: 1
Reputation: 356
I don't know for sure if this could solve your problem, but one thing I would try is check for an existing activity before do anything, like this:
//any code
Activity activity = getActivity();
if(activity != null) {
if (success) {
TextView tv = (TextView) activity.findViewById(R.id.register);
tv.setText("SIGNED IN!!");
} else if (!success) {
}
}
//any code
Upvotes: 1