屏幕方向改变后返回Activity时丢失Android服务的引用

5
我有一个Activity启动并绑定到一个Service。然后我有另一个Activity,从第一个Activity启动。从第二个Activity返回到第一个Activity时,我需要调用Service的一个方法(保存一些数据)。
在查看每个Activity时,我的Activity生命周期方法似乎能够很好地处理屏幕方向的更改,只要我在退出Activity之前返回相同的屏幕方向。
问题发生在我以不同于离开时的方向返回第一个Activity时。如果发生这种情况,我将失去对我的Service的引用,因此在onActivityResult()中遇到NullPointerException。所以如果我在纵向模式下启动我的第二个Activity,在查看第二个Activity时切换到横向,然后以横向模式返回第一个Activity,它将崩溃。
我可能错过了什么?我不想使用清单文件指示我将处理配置更改 - 这让我觉得有点丑陋的黑客,不能解决主要问题。除非我又错过了什么...
以下是我第一个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();
}

编辑:这是我的SMServiceConnection类的摘录,它是我Activity中的一个私有内部类,该类扩展自自定义的ServiceConnection类。

@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");
}

我的ServiceConnection超类大致如下:

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;
    }


    }

请问您能否发布SMServiceConnection的代码?我期望在其中看到onServiceConnected()方法,该方法可以保存binder。我使用内部类来实现ServiceConnection;这样ServiceConnection就可以将binder保存到活动(包含类)中。 - Stefan
1个回答

4

你的问题可能是当你返回时,在服务重新绑定之前就已经调用了onActivityResult(),这会在onStart中的绑定调用稍后发生。

我建议尝试以下两种方法之一:

  1. 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.

  2. 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)"
        }
    }
    
如你所说,不应该更改清单以防止在方向更改时重新创建。这是一种丑陋的技巧,不能解决问题,我不喜欢建议这样做。如果你这样做,仍然有可能发生同样的事情,例如语言变化或者活动被框架暂时销毁以节省资源。
在清单中使用configchanges必须仅用于希望在更改时获得回调而不是为了好而重新创建的场景。懒惰不是好理由。

谢谢,我已经按照你的第一个建议做了一些事情。现在我有一个私有的帮助方法来存储保存请求;onServiceConnected() 然后检查是否有挂起的请求并在必要时执行它。不过现在发现了另一个问题,我会关闭这个。 - Spinner

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接