EventBus: активность не получает событие, когда приложение находится в фоновом режиме

Я использую EventBus для связи между Activity и Service. Сегодня у меня проблема, и я не знаю почему.

  • У меня есть Activity, Fragment и Service. Все они работают нормально.

  • В Activity и Fragment я registered до Receive events, который доставлен из Service

  • В Activity и Fragment, я un-register их при вызове onDestroy().

  • В обычных случаях, когда Services поставляет events, Fragment и Activity могут получать те events и работать хорошо.

  • Но когда App нажата на background (нажатием кнопки "Домой" или "Питание" ), только Fragment получает события, которые доставлены из Service, а Activity не получает их.

  • Я ничего не делал в onPause() как Activity, так и Fragment.

Вопрос:

Есть ли объяснения? И как я могу сделать событие Activity принимает событие, подобное Fragment, когда приложение было нажато на фоне?

Ответ 1

Когда пользователь нажимает кнопку "назад/домой", Activity может быть уничтожен в любое время и, следовательно, вы не сможете получать данные с помощью EventBus. Если вы пытаетесь получить данные, когда Activity находится в фоновом режиме, это может привести к утечке памяти, и приложение выйдет из строя.

Существуют другие подходы к получению данных в Activity, когда пользователь возобновляет Activity.

Вы можете либо пользователь sharedpreferences, либо локальную базу данных, чтобы сохранить пройденные результаты service. И когда пользователь перейдет к активности, прочитайте его из sharedpreferences или базы данных.

Таким образом не будет проблем с утечкой памяти или потерей данных.

Изменить 1:

Всегда рекомендуется отменить регистрацию слушателей в onPause или onStop, потому что для этого события не нужны эти события, если он не находится на переднем плане. А поскольку onDestroy() не гарантируется, что вы вызываете, вы можете продолжать получать трансляции, когда активность больше не открыта.

Ответ 2

Класс Activity предоставляет два метода жизненного цикла: onStop() и onRestart(), когда они не видны (фоновый режим), которые позволяют вам конкретно обрабатывать способы остановки и перезапуска вашей активности. В отличие от приостановленного состояния, которое идентифицирует частичную обструкцию пользовательского интерфейса, остановленное состояние гарантирует, что пользовательский интерфейс больше не отображается, а пользовательский фокус находится в отдельной деятельности (или полностью отдельном приложении).

Чтобы понять этот цикл, взгляните на это изображение, которое показывает поток, когда ваше приложение выходит из режима переднего плана.

Когда пользователь покидает вашу деятельность

В вашем случае вы можете справиться с такой проблемой.

  • Предоставить пользователю механизм сохранения постоянных данных приложения с использованием локальной базы данных (Sqlite), sharedPreferences.
  • Управляйте своей устойчивостью данных по методу onStop().
  • Когда пользователь обращается к вашему приложению, вам необходимо восстановить данные с помощью метода onRestart().

    Вот как это реализовать.

    public class Calc extends Activity {
    public static final String PREFS_NAME = "MyPrefsFile";
    
    @Override
    protected void onCreate(Bundle state){
       super.onCreate(state);
       . . .
    
       // Restore preferences
       SharedPreferences settings = getSharedPreferences(PREFS_NAME, 0);
       boolean silent = settings.getBoolean("silentMode", false);
       setSilent(silent);
    }
    
    @Override
    protected void onStop(){
       super.onStop();
    
      // We need an Editor object to make preference changes.
      // All objects are from android.context.Context
      SharedPreferences settings = getSharedPreferences(PREFS_NAME, 0);
      SharedPreferences.Editor editor = settings.edit();
      editor.putBoolean("silentMode", mSilentMode);
    
      // Commit the edits!
      editor.commit();
    }
    

    }

Прочтите следующую документацию Сайт разработчика Android

Ответ 3

В EventBus версии 3.0.0 вы можете использовать липкие сообщения.

Таким образом, вы можете и должны отменить регистрацию EventBus на "onStop()", чтобы предотвратить утечку памяти и все еще получать события, когда приложение выходит на передний план.

Опубликовать события следующим образом:

EventBus.getDefault().postSticky(new MessageEvent("Hello everyone!"));

Подписка событий с липким флагом, например:

@Subscribe(sticky = true, threadMode = ThreadMode.MAIN)
public void onEvent(MessageEvent event) {   
    textField.setText(event.message);
}

Документация EventBus: http://greenrobot.org/eventbus/documentation/configuration/sticky-events/

Ответ 4

Трудно догадаться, что вы сделали, что вызывает это поведение, подумайте о предоставлении некоторого кода.

Но очевидно, что у вас есть некоторые недостатки дизайна.

Вы должны отменить регистрацию из любой шины или прослушивателя событий в ваших компонентах ui, таких как "Действия" или "Фрагменты", когда пользователь перейдет из приложения, если вы этого не сделаете, есть хорошая вероятность утечки вашей активности и всех ресурсов, которые она имеет место.

Вы должны хранить любые данные, которые вы получаете или рассчитываете в своей фоновой службе, в файл или базу данных, когда пользователь открывает или снова открывает ваше приложение, вы должны проверить эти данные и действовать на него.

Ответ 5

Вам нужно больше кодов или примеров, чтобы помочь вам. Но попробуйте следующее.

  • Расширяются ли ваши действия от базы? и если так, удалите незарегистрированный код события onDestroy eventbus и проверьте.
  • В настройках разработчика проверьте, не отключена ли опция "Не сохранять действия".
  • Нажатие на кнопку "назад" убьет ваше приложение, если вы не переопределили это событие.