从 Android 中的两个不同活动访问已启动服务的结果

Access the results of a started service from two different activities in Android

我有一项服务可以获取用户的位置并在意图中广播纬度和经度。

我认为我需要该服务成为启动服务(而不是绑定服务),因为我希望它能够在来自 firebase 的新 geoFire 条目进入时向用户发送推送通知即使应用程序关闭,它们的半径也是如此。

目前,该服务设置为广播位置。

鉴于位置服务将是一项启动服务,我不知道如何从两个单独的活动访问广播。

如果它是绑定服务,我相信我可以实现这一点,但由于我希望它无限期地保持活力,我不确定该怎么做。

这里是minimal example that demonstrates my issue.

具体来说,我在第一个activity上注册了一个广播接收器就可以获取到显示的经纬度,但是在第二个activity上获取不到显示的经纬度通过注册一个单独的广播接收器。

我已经阅读 Android's documentation on Services 但仍然不知道我应该怎么做才能解决这个问题。

我一直在 Android Studio 的模拟器上测试这一切:Nexus 5X API 25 x86.

2017 年 11 月 8 日更新:我更新了 github 项目以包含下面提供的 EventBus 解决方案。它在 eventBus 分支中。 master 分支仍然包含与问题相关的已更改、有问题的代码。

查看:

git clone https://github.com/Atticus29/locationServiceMCV.git
git checkout eventBus

然后,像往常一样打开 AndroidStudio 或 IDE 和 view/run。

广播结果是解决此问题的一种方法。但是如果你愿意在你的项目中添加一个库,我会强烈推荐 Green Robot's EventBus. It's a very lightweight lib, as it's fast. Also, it's simple to post complex objects through it without having to implement the Parcelable 接口。

此库以 publisher/subscriber 方式工作,在您的情况下,两个 Activity 都是订阅者,而 Service 将是发布者。

首先,您必须添加对 build.gradle 文件的依赖,如下所示。

implementation 'org.greenrobot:eventbus:3.0.0'

如果你在 Kotlin 项目上,还要添加此依赖项:

kapt 'org.greenrobot:eventbus-annotation-processor:3.0.1'

然后,定义一个事件 class,它将负责通过应用程序传输您的数据。请注意,这可以从 ServiceActivity 完成。从一个 Fragment 到另一个。在活动之间,等等。

public class MessageEvent { 
    public double lat;
    public double lng;
    // Add additional fields here if needed

    public MessageEvent(double lat, double lng) {
        this.lat= lat;
        this.lng = lng;
    }
}

之后,您必须在 Activity 上订阅这些活动。

public class MyActivity extends AppCompatActivity {
    // ...

     @Override
     public void onResume() {
         super.onResume();
         // This line will register your Activity to the EventBus
         // making sure that all the methods annotated with @Subscribe 
         // will be called if their specific Events are posted.
         EventBus.getDefault().register(this);
     }

     @Override
     public void onPause() {
         super.onPause();
         // This line will unregister your Activity.
         // It's a good practice to put this on the onPause() method
         // to make your event handling system tied to the Activity lifecycle.
         EventBus.getDefault().unregister(this);
     }

    // The threadMode MAIN makes sure this method is called on the main Thread. 
    // But you could also set it up to be called on other threads if needed. Check the docs for more info.
    @Subscribe(sticky = true, threadMode = ThreadMode.MAIN)  
    public void onMessageEvent(MessageEvent event) {
        /* Call this line below if you want to remove the sticky event.
        *  That will prevent that this event will be seen by other subscribers once they subscribe.
        *  In your specific use case, you don't have to remove the sticky event here. 
        */
        // EventBus.getDefault().removeStickyEvent(event);
        double lat = event.lat;
        double lng = event.lng;
        // Do whatever you want with the data.
    };
}

实施后,您就可以 post 您的活动了。现在,在您的 Service 中,当您获得新的 Lat/Lng 信息时调用以下代码。

EventBus.getDefault().postSticky(new MessageEvent(lat,lng));

您可以阅读有关如何设置和自定义 EventBus 的更多信息on the docs, or on this tutorial