web-dev-qa-db-ja.com

EventBus:アプリがバックグラウンドにある場合、アクティビティはイベントを受信しません

EventBusActivityの間の通信にServiceを使用しています。今日、私は問題を抱えていて、その理由がわかりません。

  1. ActivityFragment、およびServiceがあります。それらはすべて正常に動作しています。

  2. ActivityFragmentで、私はそれらをregisteredから配信されたReceiveeventsServiceします。

  3. ActivityFragmentでは、onDestroy()が呼び出されたときにそれらを_un-register_します。

  4. 通常、Serviceseventsを配信すると、FragmentActivityはそれらのeventsを受け取り、正常に機能します。

  5. ただし、Appbackgroundで押されると([ホーム]または[電源]ボタンを押す)、FragmentのみがServiceから配信されたイベントを受信し、Activityはそれらを受信しません。

  6. ActivityFragmentの両方のonPause()では何もしませんでした。

質問:

それについて何か説明はありますか?また、アプリがバックグラウンドでプッシュされたときにActivityが行ったように、Fragmentがイベントを受信するようにするにはどうすればよいですか?

17
Phan Dinh Thai

EventBusバージョン3.0.0では、スティッキー投稿を使用できます。

このようにして、「onStop()」でEventBusの登録を解除して、メモリリークを防ぎ、アプリがフォアグラウンドになったときにイベントを受信することができます。

この方法でイベントを投稿します。

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/

15
Kunami

ユーザーが戻る/ホームボタンを押すと、Activityはいつでも破棄される可能性があるため、EventBusを使用してデータを受信することはできません。 Activityがバックグラウンドにあるときにデータを受信しようとすると、メモリリークが発生し、アプリがクラッシュする可能性があります。

ユーザーがActivityを再開したときに、activityのデータを取得する方法は他にもあります。

ユーザーsharedpreferencesまたはローカルデータベースのいずれかを使用して、serviceに渡された結果を保存できます。また、ユーザーがアクティビティに戻ったら、sharedpreferencesまたはデータベースから読み取ります。

このようにして、メモリリークやデータ損失の問題は発生しません。

編集1:

アクティビティがフォアグラウンドにない場合、アクティビティはこれらのイベントを必要としないため、onPauseまたはonStopのいずれかでリスナーの登録を解除することを常にお勧めします。また、onDestroy()が呼び出されることが保証されていないため、アクティビティが開いていなくてもブロードキャストを受信し続けることができます。

13
Rohit Arya

Activityクラスは、非表示時(バックグラウンドモード)のonStop()とonRestart()の2つのライフサイクルメソッドを提供します。これにより、アクティビティの停止と再開の処理方法を具体的に処理できます。部分的なUI障害を識別する一時停止状態とは異なり、停止状態はUIが表示されなくなり、ユーザーのフォーカスが別のアクティビティ(または完全に別のアプリ)にあることを保証します。

このサイクルを理解するために、アプリがフォアグラウンドモードを終了したときのフローを示すこの画像を見てください。

When the user leaves your activity

あなたの場合、あなたはこのような問題を扱うことができます。

  • ローカルデータベース(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
Carlos

適切に支援するには、さらに多くのコードまたは例が必要です。ただし、次のことを試してください。

  1. あなたの活動はbaseActivityから拡張されていますか?その場合は、onDestroyイベントバスの登録解除コードを削除して確認してください。
  2. 開発者向けオプションで、[アクティビティを保持しない]オプションがオフになっているかどうかを確認します。
  3. 戻るイベントをオーバーライドしない限り、押し戻すとアプリが強制終了されます。
2
Kishath

この動作を引き起こす原因を推測するのは難しいので、コードを提供することを検討してください。

しかし、明らかなことは、いくつかの設計上の欠陥があるということです。

ユーザーがアプリから戻ったときに、アクティビティやフラグメントなどのUIコンポーネントのイベントバスまたはリスナーから登録を解除する必要があります。登録を解除しないと、アクティビティとそれが保持するすべてのリソースがリークする可能性があります。

バックグラウンドサービスで受信または計算したデータはすべてファイルまたはデータベースに保存する必要があります。ユーザーがアプリを開いたり再度開いたりするときは、そのデータを確認して操作する必要があります。

2