如何将数据从 Android 后台服务传递到 activity

How to pass data from an Android background service to an activity

我有一个 Android 应用程序,有两个组件

  1. 一个 activity,它在网络视图中创建、显示 javascript 代码 运行 并与之通信。
  2. 创建并绑定到上述 activity 的后台服务,即使 activity 对用户不可见,它也会捕获位置数据。

谁能告诉我将位置数据从服务传回 activity 的最简单方法,无论 activity 是否显示给用户,该方法都有效。

我应该使用 EventBus 吗?广播接收器、本地广播管理器或什么?

理想情况下,我希望有人指出 GitHub(或类似)上的示例应用程序的方向,我可以下载并检查它是如何工作的,如果失败,一些代码会很好。

这是您的服务:

<service
    android:name=".Services.Service.GPSTracker"
    android:exported="false" />

和java class:

import android.Manifest;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.location.Criteria;
import android.location.GpsSatellite;
import android.location.GpsStatus;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.IBinder;
import android.provider.Settings;
import android.support.v4.app.ActivityCompat;
import android.util.Log;

import static android.location.GpsStatus.GPS_EVENT_SATELLITE_STATUS;

public class GPSTracker extends Service {

    private Context mContext;

    // flag for GPS status
    boolean isGPSEnabled = false;

    // flag for network status
    boolean isNetworkEnabled = false;

    // flag for GPS status
    boolean canGetLocation = false;

    Location location; // location
    double latitude; // latitude
    double longitude; // longitude
    float bearing; // bearing

    // The minimum distance to change Updates in meters
    private static final long MIN_DISTANCE_CHANGE_FOR_UPDATES = 1; // 10 meters

    // The minimum time between updates in milliseconds
    private static final long MIN_TIME_BW_UPDATES = 1000; // 5 sec

    // Declaring a Location Manager
    protected LocationManager locationManager;
    protected LocationListener locationListenerNetwork;
    protected LocationListener locationListenerGPS;
    protected GpsStatus.Listener gpsStatusListener;
    protected GpsListener gpsListener;


    public GPSTracker(Context context, LocationListener listenerNetwork, LocationListener listenerGPS, GpsListener gpsListener) {
        locationListenerGPS = listenerGPS;
        locationListenerNetwork = listenerNetwork;
        this.mContext = context;
        this.gpsListener = gpsListener;
        getLocation();
    }

    public GPSTracker() {
    }

    private GPSTracker(Context mContext) {
        this.mContext = mContext;
    }

    public Location getLocation() {
        try {
            locationManager = (LocationManager) mContext
                    .getSystemService(LOCATION_SERVICE);

            // getting GPS status
            isGPSEnabled = locationManager
                    .isProviderEnabled(LocationManager.GPS_PROVIDER);

            // getting network status
            isNetworkEnabled = locationManager
                    .isProviderEnabled(LocationManager.NETWORK_PROVIDER);

            if (!isGPSEnabled && !isNetworkEnabled) {
                // no network provider is enabled
            } else {
                this.canGetLocation = true;
                // if GPS Enabled get lat/long using GPS Services
                if (isGPSEnabled) {
                    if (location == null) {
                        if (ActivityCompat.checkSelfPermission(mContext, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(mContext, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
                            // TODO: Consider calling
                            //    ActivityCompat#requestPermissions
                            // here to request the missing permissions, and then overriding
                            //   public void onRequestPermissionsResult(int requestCode, String[] permissions,
                            //                                          int[] grantResults)
                            // to handle the case where the user grants the permission. See the documentation
                            // for ActivityCompat#requestPermissions for more details.
                            return null;
                        }


                        final Criteria criteria = new Criteria();
                        criteria.setCostAllowed(true);
                        criteria.setPowerRequirement(Criteria.POWER_HIGH);
                        criteria.setAccuracy(Criteria.ACCURACY_FINE);
                        final String p = locationManager.getBestProvider(criteria, true);

                        locationManager.requestLocationUpdates(
                                LocationManager.GPS_PROVIDER,
                                MIN_TIME_BW_UPDATES,
                                MIN_DISTANCE_CHANGE_FOR_UPDATES, locationListenerGPS);
                        gpsStatusListener = new GpsStatus.Listener() {
                            @Override
                            public void onGpsStatusChanged(int event) {
                                if (event == GPS_EVENT_SATELLITE_STATUS) {
                                    if (ActivityCompat.checkSelfPermission(mContext, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
                                        // TODO: Consider calling
                                        //    ActivityCompat#requestPermissions
                                        // here to request the missing permissions, and then overriding
                                        //   public void onRequestPermissionsResult(int requestCode, String[] permissions,
                                        //                                          int[] grantResults)
                                        // to handle the case where the user grants the permission. See the documentation
                                        // for ActivityCompat#requestPermissions for more details.
                                        return;
                                    }
                                    GpsStatus status = locationManager.getGpsStatus(null);
                                    Iterable<GpsSatellite> sats = status.getSatellites();
                                    gpsListener.OnGpsSatelliteChanged(sats);
                                    // Check number of satellites in list to determine fix state
                                }
                            }
                        };
                        locationManager.addGpsStatusListener(gpsStatusListener);
                        Log.d("GPS Enabled", "GPS Enabled");
                        if (locationManager != null) {
                            location = locationManager
                                    .getLastKnownLocation(LocationManager.GPS_PROVIDER);
                            if (location != null) {
                                latitude = location.getLatitude();
                                longitude = location.getLongitude();
                                bearing = location.getBearing();
                            }
                        }
                    }
                }
                if (isNetworkEnabled) {
                    if (ActivityCompat.checkSelfPermission(mContext, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(mContext, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
                        // TODO: Consider calling
                        //    ActivityCompat#requestPermissions
                        // here to request the missing permissions, and then overriding
                        //   public void onRequestPermissionsResult(int requestCode, String[] permissions,
                        //                                          int[] grantResults)
                        // to handle the case where the user grants the permission. See the documentation
                        // for ActivityCompat#requestPermissions for more details.
                        return null;
                    }
                    locationManager.requestLocationUpdates(
                            LocationManager.NETWORK_PROVIDER,
                            MIN_TIME_BW_UPDATES,
                            MIN_DISTANCE_CHANGE_FOR_UPDATES, locationListenerNetwork);
                    Log.d("Network", "Network");
                    if (locationManager != null) {
                        location = locationManager
                                .getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
                        if (location != null) {
                            latitude = location.getLatitude();
                            longitude = location.getLongitude();
                            bearing = location.getBearing();
                        }
                    }
                }

            }

        } catch (Exception e) {
            e.printStackTrace();
        }

        return location;
    }

    /**
     * Stop using GPS listener
     * Calling this function will stop using GPS in your app
     */
    public void stopUsingGPSProvider() {
        if (locationManager != null) {
            locationManager.removeUpdates(locationListenerGPS);
        }
    }

    public void stopUsingNetworkProvider() {
        if (locationManager != null) {
            locationManager.removeUpdates(locationListenerNetwork);
        }
    }

    /**
     * Function to get latitude
     */
    public double getLatitude() {
        if (location != null) {
            latitude = location.getLatitude();
        }

        // return latitude
        return latitude;
    }

    /**
     * Function to get longitude
     */
    public double getLongitude() {
        if (location != null) {
            longitude = location.getLongitude();
        }

        // return longitude
        return longitude;
    }

    public float getBearing() {
        if (location != null) {
            bearing = location.getBearing();
        }
        return bearing;
    }

    /**
     * Function to check GPS/wifi enabled
     *
     * @return boolean
     */
    public boolean canGetLocation() {
        return this.canGetLocation;
    }

    /**
     * Function to show settings alert dialog
     * On pressing Settings button will lauch Settings Options
     */
    public void showSettingsAlert() {
       /*
        AlertDialog.Builder alertDialog = new AlertDialog.Builder(mContext);

        // Setting Dialog Title
        alertDialog.setTitle("GPS is settings");

        // Setting Dialog Message
        alertDialog.setMessage("GPS is not enabled. Do you want to go to settings menu?");

        // On pressing Settings button
        alertDialog.setPositiveButton("Settings", new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialog, int which) {*/
        Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
        mContext.startActivity(intent);
          /*  }
        });

        // on pressing cancel button
        alertDialog.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialog, int which) {
                dialog.cancel();
            }
        });

        // Showing Alert Message
        alertDialog.show();*/
    }


    @Override
    public IBinder onBind(Intent arg0) {
        return null;
    }

    public interface GpsListener {
        void OnGpsSatelliteChanged(Iterable<GpsSatellite> gpsSatellites);
    }

}

在 activity 中:

 GPSTracker gps;


    LocationListener locationListenerNetwork = new LocationListener() {
        @Override
        public void onLocationChanged(Location location) {

        }

        @Override
        public void onStatusChanged(String provider, int status, Bundle extras) {

        }

        @Override
        public void onProviderEnabled(String provider) {

        }

        @Override
        public void onProviderDisabled(String provider) {

        }
    };
    LocationListener locationListenerGPS = new LocationListener() {
        @Override
        public void onLocationChanged(Location location) {


        }

        @Override
        public void onStatusChanged(String provider, int status, Bundle extras) {

        }

        @Override
        public void onProviderEnabled(String provider) {

        }

        @Override
        public void onProviderDisabled(String provider) {

        }
    };

     GPSTracker.GpsListener gpsListener = new GPSTracker.GpsListener() {
        @Override
        public void OnGpsSatelliteChanged(Iterable<GpsSatellite> gpsSatellites) {

        }
    };


    void start(){
        gps = new GPSTracker(this, locationListenerNetwork, locationListenerGPS, gpsListener);
    }

    void stop(){
        if (gps != null) {
            gps.stopUsingGPSProvider();
            gps.stopUsingNetworkProvider();
        }
    }


    @Override
    protected void onPause() {
        super.onPause();
        stop();
    }

    @Override
    protected void onResume() {
        super.onResume();
        start();
    }

只要你的 activity 打开并开始向你的 activity 发送 gps 数据,如果 activity 进入后台或停止,上面的代码将 运行 gps 并且等等... gps 也会停止(您也需要处理许可)。另外,如果你想在 activity 未打开时也有 gps 数据,你可以制作一个 List<location> 并将其保存在服务中,并且当 activity 被重置时通过接口将其发回(希望你知道如何创建接口和传递数据);

由于您使用的是 Bound service,最简单的方法是在 Activity 绑定到 Service 时 return 一个合适的 Binder 对象.

相关文档在 here

此外,这是绑定的示例代码 service and the corresponding actvitiy

请注意,Activity 一旦连接,就可以调用添加到相应 Binder 对象的 public 方法。如果您希望 Service 自行决定向 Activity 提供信息,只需注册一个服务可以调用的侦听器即可。

我发现最简单的解决方案实际上是使用 EventBus。他们的 website 入门页面说明了四个简单的步骤

  1. 在我的 gradle 文件中添加 "implementation 'org.greenrobot:eventbus:3.1.1'"
  2. 在我的 MainActivity 中注册和取消注册接收器。我在 onCreate 和 onDestroy 中做了这个,但他们推荐 onStart 和 onStop
  3. 添加一个新的 JavaClass MessageEvent - 来自上面 link 的 4 行代码
  4. 在我的服务中,使用 EventBus post 可用的新位置数据
  5. 在我的 MainActivity 中使用 onMessageEvent
  6. 对这些 post 做出反应

即使主 activity 暂停(在后台)也能正常工作

有两件额外的事情要做,上面的 link 中没有记录。

  1. 我必须将 "import org.greenrobot.eventbus.EventBus;" 添加到我的 MainActivity class 文件和我的 BackgroundService class 文件。
  2. 必须将 mavenCentral() 添加到顶级构建文件的所有项目部分。