EventBus:应用程序在后台时,活动无法接收事件

23

我正在使用EventBusActivityService之间通信。 今天我遇到了一个问题,不知道为什么。

  1. 我有ActivityFragmentService。它们都正常工作。

  2. ActivityFragment中,我将它们注册到从Service传递的事件中来接收events

  3. ActivityFragment中,当调用onDestroy()时,我将它们取消注册

  4. 在正常情况下,当Services传递事件时,FragmentActivity可以接收这些events并正常工作。

  5. 但是,当App被推到background(通过按Home键或电源按钮)时,只有Fragment能够接收从Service传递的events,而Activity无法接收。

  6. ActivityFragmentonPause()中,我都没有做任何事情。

问题:

有什么解释吗?如何让我的Activity在将应用程序推到后台时像Fragment一样接收事件?


也许该活动的 onDestroy 方法会被调用并取消注册它。 - Vucko
2
由于您现在所遇到的问题,若您按下主页或返回键,您的活动就会立即被销毁,因此无法接收到任何数据。 - pskink
1
我认为完全排除事件总线作为应用程序/服务通信选项是不公平的。这取决于消息的目的。如果应用程序依赖于服务的状态,则绑定是最佳选择。如果服务引发事件,则总线更好。此外,粘性事件将使您的活动在重新注册后接收事件。 - Kevin
@pskink:它没有解释为什么Activity没有接收到事件,而Fragment却接收到了。我同意你的观点,当应用程序在后台运行时,Activity可能会被销毁,但这个时候Fragment也会被销毁。 - ThaiPD
需要看一些示例代码。 - Naveen Prince P
显示剩余9条评论
5个回答

18

在EventBus 3.0.0版本中,您可以使用sticky posts。

这样做可以并且应该在“onStop()”上取消注册EventBus以防止内存泄漏,并且仍然在应用程序返回前台时接收事件。

按照以下方式发布事件:

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

使用 sticky 标志订阅事件,如下所示:

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

EventBus 文档: http://greenrobot.org/eventbus/documentation/configuration/sticky-events/


14
当用户按下“返回/主页”按钮时,Activity 可能会被随时销毁,因此您将无法使用EventBus接收数据。如果在Activity 处于后台时仍然尝试接收数据,则可能会泄漏内存并导致应用崩溃。
获取用户恢复activity时的数据还可以采用其他方法。
您可以使用 sharedpreferences 或本地数据库来保存 service 传递的结果。当用户返回到该Activity时,从 sharedpreferences 或数据库中读取数据。
这样就不会有内存泄露或数据丢失的问题。
编辑1:
通常建议在onPauseonStop中取消注册监听器,因为Activity在后台时不需要这些事件。而由于不能保证调用onDestroy(),因此当Activity不再打开时,您可能会继续接收广播。

是的,问题只发生在应用程序被推到后台时。但是Fragment工作正常。 - ThaiPD
好的,让我先澄清一下。您能在调用onStop之前接收事件。并且由于您在onDestroy中取消了事件注册,因此您期望在调用onDestroy之前继续接收事件。对吗? - Rohit Arya
我在这一点上不同意你。让我们谈论正常情况,当我只按下主页按钮时,事件就被分派了,仅有几秒钟,此时活动并没有被销毁。你可以从我的问题中看到,在同一时间,Fragment 接收到事件而 Activity 没有。这意味着它们都还活着。 - ThaiPD
这是我的答案,只是重新表述了一下。您可以看到日期。 - M. Reza Nasirloo
有时候我需要在onDestroy()方法内取消注册总线,以确保ActivityFragment能够接收发布的事件。 - blueware
显示剩余4条评论

3
Activity类提供了两个生命周期方法,即onStop()和onRestart(),当活动不可见(后台模式)时,它们允许您专门处理活动的停止和重新启动方式。与暂停状态不同,暂停状态标识部分UI阻塞,而停止状态保证UI不再可见,并且用户的焦点在单独的活动(或完全不同的应用程序)中。
为了理解这个周期,请看一下这张图,它展示了当您的应用程序退出前台模式时的流程。

When the user leaves your activity

在您的情况下,您可以像这样处理该问题。
  • Provide to the user a mechanism to save persistent application data using either local database(Sqlite), sharedPreferences.
  • Handle your data persistency on onStop() method.
  • When user callback your app, then you will need to restore the data using onRestart() method.

    Here is the way to implement that.

    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 Developer网站的以下文档。

2
很难猜测您做了什么导致了这种行为,考虑提供一些代码。但很明显,您有一些设计缺陷。当用户从应用程序返回时,您必须取消注册任何事件总线或监听器在您的UI组件中,例如Activities或Fragments,如果不这样做,很可能会泄漏您的Activity和它所持有的所有资源。您应该将您在后台服务中接收或计算的任何数据存储到文件或数据库中,当用户打开或重新打开您的应用程序时,您应该检查该数据并采取相应措施。

2

需要更多代码或示例才能帮助您。但是请尝试以下操作:

  1. 您的活动是否从baseActivity扩展而来?如果是,请删除onDestroy中的eventbus取消注册代码并检查。
  2. 在开发人员选项中,检查“不保留活动”选项是否未选中。
  3. 按返回按钮将无论如何关闭您的应用,除非您已覆盖返回事件。

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