I have an Activity
that starts and binds to a Service
. I then have another Activity
, launched from the first. Upon returning to the first Activity
from the second, I need to invoke a method of the Service
(saves some data).
While viewing each Activity
, my Activity
lifecycle methods appear to cope adequately with screen orientation changes, provided I return to the same screen orientation before exiting the Activity
.
The problem happens when I return to the first Activity with a different orientation from when I left it. If that happens, I lose my reference to my Service
and consequently run into a NullPointerException
in onActivityResult()
. So if I launch my second Activity
in portrait mode, switch to landscape while viewing the second Activity
, and return to the first Activity
in landscape mode, it'll crash.
What might I be missing? I don't want to use the manifest file to indicate I'll handle configuration changes - strikes me as a somewhat ugly hack which doesn't address the main problem. Unless I'm missing something again...
Here are extracts from my lifecycle methods from the first Activity:
@Override
protected void onStart()
{
super.onStart();
// start and bind to service
startService(smsIntent);
connection = new SMServiceConnection();
bindService(smsIntent, connection, Context.BIND_AUTO_CREATE);
}
@Override
protected void onRestart()
{
super.onRestart();
}
@Override
protected void onResume()
{
super.onResume();
}
@Override
protected void onPause()
{
super.onPause();
sms.save(); // autosave
}
@Override
protected void onStop()
{
super.onStop();
unbindService(connection);
// stopService(smsIntent); //doesn't appear to have any effect
}
@Override
protected void onDestroy()
{
super.onDestroy();
}
EDIT: Here are extracts from my SMServiceConnection class, which is a private inner class in my Activity, which extends from a custom ServiceConnection class.
@Override
public void onServiceConnected(ComponentName name, IBinder service)
{
super.onServiceConnected(name, service);
msg("Service connected");
sms = getSMService();
if (sms != null)
{
String s = sms.getStuff(); //etc.; haven't listed every method invoked on sms
sms.saveSurvey();
}
} else
{
System.out.println("sms is null!");
}
}
@Override
public void onServiceDisconnected(ComponentName name)
{
super.onServiceDisconnected(name);
msg("Service disconnected");
}
My ServiceConnection superclass is something like:
public class MyServiceConnection implements ServiceConnection
{
private boolean serviceAvailable = false;
private SMService sms;
public void onServiceConnected(ComponentName name, IBinder service)
{
serviceAvailable = true;
LocalBinder b = (LocalBinder) service;
sms = b.getService();
}
public void onServiceDisconnected(ComponentName name)
{
serviceAvailable = false;
}
public boolean isServiceAvailable()
{
return serviceAvailable;
}
public SMService getSMService()
{
return sms;
}
}
Your problem might be that onActivityResult() is called prior to the service being binded again when you return, which happens slightly after the bindcall in onstart.
I would try one of two things:
Try saving the data as pending information:
if (sms == null) {
mPendingResultCode = resultCode;
mPedingResultData = new Bundle(intent.getExtras()); } else {
handleData(resultCode, intent.getExtras()); }
And then later in onServiceConnected
call
handleData(mPedingResultCode, mPedingResultData)
if for example
mPendingResultData != null
And make sure to unset mPendingResultCode and mPendingResultData or some other indicator when you are done with the data.
I'm unsure of this, but would perhaps try add the data handling to the back of the event queue by doing something like this in onActivityResult:
final Bundle data = new Bundle(intent.getExtras);
new Handler().postRunnable(new Runnable() {
public void run() {
"do some stuff with data and resultcode (which should be final in the parameter list anyway)"
}
}
As you said you should not change the manifest to not recreate on orientation changed. It is an ugly hack that does not solve the problem and I don't like when that is suggested. If you do that you still risk the same thing happening if some other configuration has changed such as language or if the activity has been destroyed temporarily by the framework to save resources.
configchanges in manifest must only be used if you want to get callbacks on the change rather than recreate for a good. reason. Laziness is not one.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With