Потеря ссылки на сервис Android при возврате в Activity после изменения ориентации экрана - PullRequest
4 голосов
/ 17 февраля 2012

У меня есть Activity, который запускается и связывается с Service.У меня потом еще один Activity, запущенный с первого раза.После возврата к первому Activity из второго мне нужно вызвать метод Service (сохраняет некоторые данные).

При просмотре каждого Activity мои Activity методы жизненного цикла выглядят так:адекватно справляться с изменениями ориентации экрана, при условии, что я возвращаюсь к той же ориентации экрана перед выходом из Activity.

Проблема возникает, когда я возвращаюсь к первому действию с ориентацией, отличной от той, которую я оставил.Если это произойдет, я потеряю свою ссылку на Service и, следовательно, столкнусь с NullPointerException в onActivityResult().Поэтому, если я запускаю свой второй 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;
    }


    }

1 Ответ

4 голосов
/ 17 февраля 2012

Ваша проблема может заключаться в том, что onActivityResult () вызывается до повторного связывания службы при возврате, что происходит немного после bindcall в onstart.

Я бы попробовал одну из двух вещей:

  1. Попробуйте сохранить данные в качестве ожидающей информации:

    if (sms == null) {
        mPendingResultCode = resultCode;
        mPedingResultData = new Bundle(intent.getExtras()); } else {
        handleData(resultCode, intent.getExtras()); }
    

    А затем позже onServiceConnected вызовите handleData(mPedingResultCode, mPedingResultData), например, mPendingResultData != null

    Иубедитесь, что вы сбросили mPendingResultCode и mPendingResultData или какой-либо другой индикатор, когда закончите работу с данными.

  2. Я не уверен в этом, но, возможно, попробую добавить обработку данных в концеочередь событий, выполнив что-то подобное в 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)"
        }
    }
    

Как вы сказали, вы не должны изменять манифест, чтобы не создавать заново при изменении ориентации.Это уродливый хак, который не решает проблему, и мне не нравится, когда это предлагается.Если вы делаете это, вы все равно рискуете произойти то же самое, если какая-то другая конфигурация была изменена, например, язык, или если действие было временно разрушено платформой для экономии ресурсов.

configges в манифесте должны использоваться только в том случае, если выхочу получить ответные реакции на изменение, а не воссоздать для хорошего.причина.Лень не одна.

...