如何接收位置更新,每5分钟使用FusedLocation API [英] How to receive location updates every 5 minutes using the FusedLocation API

查看:296
本文介绍了如何接收位置更新,每5分钟使用FusedLocation API的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我目前的工作有检查用户的位置,每五分钟发送坐标到服务器的应用程序。我决定去与在谷歌播放服务,而不是普通的旧的LocationManager API的FusedLocation API,主要是因为我注意到在 LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY 优先级,宣称提供以合理的100米精度等级电池的使用,这正是我需要的。

在我的情况,我有一个活动的继承结构是:

 公共类MainActivity扩展AppCompatActivity工具
        GoogleApiClient.ConnectionCallbacks,
        GoogleApiClient.OnConnectionFailedListener,LocationListener的

和它实现了相关的回调(onConnected,onConnectionFailed,onConnectionSuspended,onLocationChanged)。我也得到了GoogleApiClient的实例,用这种方法,由官方文档建议:

 受保护的同步GoogleApiClient buildGoogleApiClient(){
        返回新GoogleApiClient.Builder(本).addConnectionCallbacks(本)
                .addOnConnectionFailedListener(本)
                .addApi(LocationServices.API).build();

在onConnected,我用启动位置更新

  LocationServices.FusedLocationApi.requestLocationUpdates(mApiClient,
                mLocationRequest,这一点);

...在onLocationChanged()。捕获的变化

不过,我很快发现,位置更新似乎一段时间后停止。也许是因为这个方法是联系在一起的活动周期,我不知道。反正,我试图通过创建延伸IntentService的内部类,并通过AlarmManager启动它来解决这个问题。因此,在onConnected,我结束了这样:

  AlarmManager alarmMan =(AlarmManager)本
                .getSystemService(Context.ALARM_SERVICE);        意图updateIntent =新意图(这一点,LocUpService.class);        的PendingIntent pIntent = PendingIntent.getService(这一点,0,updateIntent,
                PendingIntent.FLAG_UPDATE_CURRENT);
        alarmMan.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,0,
                1000 * 60 * 5,pIntent);

该LocUpService类看起来是这样的:

 公共静态类LocUpService扩展IntentService {        公共LocUpService(){
            超级(LocUpService);        }        @覆盖
        保护无效onHandleIntent(意向意图){
            COORDS COORDS = LocationUpdater.getLastKnownLocation(mApiClient);
        }    }

LocationUpdater是另一个类,它包含静态方法getLastKnownLocation,这是这样的:

 公共静态COORDS getLastKnownLocation(GoogleApiClient apiClient){        COORDS COORDS =新COORDS();
        地点= LocationServices.FusedLocationApi
                .getLastLocation(apiClient);        如果(位置!= NULL){            coords.setLatitude(location.getLatitude());
            coords.setLongitude(location.getLongitude());            Log.e(纬度,location.getLatitude()+度);
            Log.e(LON,location.getLongitude()+度);        }
        返回COORDS;
    }

但惊喜!我得到抛出:IllegalArgumentException:GoogleApiClient参数是必须的,当我清楚地通过参考静态方法,它再次我想一定有事情做与GoogleApiClient实例与Activity的生命周期以及一些与通过实例到脚麻受到牵连在IntentService。

所以,我在想:我怎么获得常规位置,而要疯了,每五分钟更新?难道我延伸服务,实现该组件的所有接口回调,在那里建立GoogleApiClient实例,并保持它在后台运行?难道我有一个AlarmManager开始延伸IntentService每五分钟就做好了,再有在建IntentService所有相关的回调和GoogleApiClient服务?难道我继续做我在做什么,但现在构建GoogleApiClient作为一个单身,期待它会有所作为?你会怎么做呢?

谢谢,对不起,这是这么啰嗦。


解决方案

  

我目前的工作有检查用户的位置,每五分钟发送坐标到服务器的应用程序。我决定去与在谷歌播放服务FusedLocation API,而不是普通的旧的LocationManager API


我们的应用程序已经正是同样的要求,我实现了一两天以前,这里是我如何做的。

在推出活动或任何你想创业,配置LocationTracker为每5分钟运行,使用AlarmManager。

 私人无效startLocationTracker(){
    //配置LocationTracker的广播接收器每5分钟运行一次。
    意向意图=新意图(这一点,LocationTracker.class);
    AlarmManager alarmManager =(AlarmManager)getSystemService(Context.ALARM_SERVICE);
    的PendingIntent的PendingIntent = PendingIntent.getBroadcast(这一点,0,意向,0);
    alarmManager.setRepeating(AlarmManager.RTC_WAKEUP,Calendar.getInstance()。getTimeInMillis(),
            LocationProvider.FIVE_MINUTES,的PendingIntent);
}

LocationTracker.java

 公共类LocationTracker扩展广播接收器{    私人PowerManager.WakeLock激活锁定;    @覆盖
    公共无效的onReceive(上下文的背景下,意图意图){
        电源管理POW =(电源管理)context.getSystemService(Context.POWER_SERVICE);
        激活锁定= pow.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,);
        wakeLock.acquire();        位置currentLocation = LocationProvider.getInstance()getCurrentLocation()。        //发送新的位置到后端。 //这会为你不同
        UserService.registerLocation(上下文,新Handlers.OnRegisterLocationRequestCompleteHandler(){
            @覆盖
            公共无效的onSuccess(){
                Log.d(成功,UserService.RegisterLocation()成功);                wakeLock.release();
            }            @覆盖
            公共无效onFailure处(INT状态code,弦乐的errorMessage){
                Log.d(错误,UserService.RegisterLocation()失败);
                Log.d(错误的errorMessage);                wakeLock.release();
            }
        }, 当前位置);
    }
}

LocationProvider.java

 公共类LocationProvider {    私有静态LocationProvider实例= NULL;
    私有静态上下文的背景下;    公共静态最终诠释ONE_MINUTE = 1000 * 60;
    公共静态最终诠释FIVE_MINUTES = ONE_MINUTE * 5;    私有静态位置currentLocation;    私人LocationProvider(){    }    公共静态LocationProvider的getInstance(){
        如果(例如== NULL){
            例如=新LocationProvider();
        }        返回实例;
    }    公共无效configureIfNeeded(上下文CTX){
        如果(上下文== NULL){
            上下文= CTX;
            configureLocationUpdates();
        }
    }    私人无效configureLocationUpdates(){
        最终LocationRequest locationRequest = createLocationRequest();
        最后GoogleApiClient googleApiClient =新GoogleApiClient.Builder(上下文)
                .addApi(LocationServices.API)
                。建立();        googleApiClient.registerConnectionCallbacks(新GoogleApiClient.ConnectionCallbacks(){
            @覆盖
            公共无效onConnected(束束){
                startLocationUpdates(googleApiClient,locationRequest);
            }            @覆盖
            公共无效onConnectionSuspended(int i)以{            }
        });
        googleApiClient.registerConnectionFailedListener(新GoogleApiClient.OnConnectionFailedListener(){
            @覆盖
            公共无效onConnectionFailed(ConnectionResult connectionResult){            }
        });        googleApiClient.connect();
    }    私有静态LocationRequest createLocationRequest(){
        LocationRequest locationRequest =新LocationRequest();
        locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
        locationRequest.setInterval(FIVE_MINUTES);
        返回locationRequest;
    }    私有静态无效startLocationUpdates(GoogleApiClient客户端,LocationRequest要求){
        LocationServices.FusedLocationApi.requestLocationUpdates(客户机,请求,新com.google.android.gms.location.LocationListener(){
            @覆盖
            公共无效onLocationChanged(地点){
                currentLocation =位置;
            }
        });
    }    公共场所getCurrentLocation(){
        返回currentLocation;
    }
}

我先在扩展应用程序中的类LocationProvider的一个实例,在创建时,应用程序启动实例:

MyApp.java

 公共类MyApp的扩展应用{    @覆盖
    公共无效的onCreate(){
        super.onCreate();        LocationProvider locationProvider = LocationProvider.getInstance();
        locationProvider.configureIfNeeded(本);
    }
}

该LocationProvider实例化和配置的位置更新只出现一次,因为它是一个单例。每5分钟会更新其 currentLocation 价值,这是我们可以从任何地方,我们需要以

检索

 位置LOC = LocationProvider.getInstance()getCurrentLocation()。

运行任何种类的背景服务不是必需的。该AlarmManager将广播LocationTracker.onReceive()每5分钟和部分激活锁定将确保code将完成运行,即使设备处于待机状态。这也是节能。

请注意,您需要下列权限

 <使用许可权的android:NAME =android.permission.ACCESS_FINE_LOCATION/>
<使用许可权的android:NAME =android.permission.INTERNET对/><! - 对于保持LocationTracker活着,而它是做网络 - >
<使用许可权的android:NAME =android.permission.WAKE_LOCK/>

和不要忘记注册接收器:

 <接收机器人:LocationTrackerNAME = />

I am currently working on an app that has to check the user's location every five minutes and send the coordinates to a server. I decided to go with the FusedLocation API in Google Play Services instead of the plain old LocationManager API, mainly because I noticed the LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY priority level, which claims to offer a 100-meter accuracy level with reasonable battery usage, which is EXACTLY what I need.

In my case, I have an Activity whose inheritance structure is:

public class MainActivity extends AppCompatActivity implements
        GoogleApiClient.ConnectionCallbacks,
        GoogleApiClient.OnConnectionFailedListener, LocationListener

and which implements the relevant callbacks (onConnected, onConnectionFailed, onConnectionSuspended, onLocationChanged). I also get an instance of the GoogleApiClient, with this method, as suggested by the official documentation:

protected synchronized GoogleApiClient buildGoogleApiClient() {
        return new GoogleApiClient.Builder(this).addConnectionCallbacks(this)
                .addOnConnectionFailedListener(this)
                .addApi(LocationServices.API).build();

In onConnected, I start the location updates by using

LocationServices.FusedLocationApi.requestLocationUpdates(mApiClient,
                mLocationRequest, this);

... and capture changes in onLocationChanged().

However, I quickly found out that the location updates seem to stop after a while. Perhaps it's because this method is tied to the Activity lifecycle, I'm not sure. Anyway, I tried to get around this by creating an inner class which extends IntentService and starting it by an AlarmManager. So in onConnected, I ended up doing this:

AlarmManager alarmMan = (AlarmManager) this
                .getSystemService(Context.ALARM_SERVICE);

        Intent updateIntent = new Intent(this, LocUpService.class);

        PendingIntent pIntent = PendingIntent.getService(this, 0, updateIntent,
                PendingIntent.FLAG_UPDATE_CURRENT);
        alarmMan.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, 0,
                1000 * 60 * 5, pIntent);

The LocUpService class looks like this:

public static class LocUpService extends IntentService {

        public LocUpService() {
            super("LocUpService");

        }

        @Override
        protected void onHandleIntent(Intent intent) {
            Coords coords = LocationUpdater.getLastKnownLocation(mApiClient);


        }

    }

LocationUpdater is another class, which contains the static method getLastKnownLocation, which is this:

public static Coords getLastKnownLocation(GoogleApiClient apiClient) {

        Coords coords = new Coords();
        Location location = LocationServices.FusedLocationApi
                .getLastLocation(apiClient);

        if (location != null) {

            coords.setLatitude(location.getLatitude());
            coords.setLongitude(location.getLongitude());

            Log.e("lat ", location.getLatitude() + " degrees");
            Log.e("lon ", location.getLongitude() + " degrees");

        }
        return coords;
    }

But surprise!! I get "IllegalArgumentException: GoogleApiClient parameter is required", when I clearly pass the reference to the static method, which again I guess must have something to do with the GoogleApiClient instance being implicated with the Activity's lifecycle and something going wrong with passing the instance into the IntentService.

So I'm thinking: how do I get regular location updates every five minutes without going crazy? Do I extend a Service, implement all interface callbacks on that component, build the GoogleApiClient instance in there and keep it running in the background? Do I have an AlarmManager start a service that extends IntentService every five minutes to do the work, again having all relevant callbacks and GoogleApiClient constructed in the IntentService? Do I keep doing what I'm doing right now but construct the GoogleApiClient as a singleton, expecting that it'll make a difference? How would you do it?

Thanks and sorry for this being so long-winded.

解决方案

I am currently working on an app that has to check the user's location every five minutes and send the coordinates to a server. I decided to go with the FusedLocation API in Google Play Services instead of the plain old LocationManager API

Our app has exactly that same requirement, I implemented that a couple of days ago and here is how I did it.

In the launch activity or wherever you want to start, configure a LocationTracker to run every 5 minutes, using an AlarmManager.

private void startLocationTracker() {
    // Configure the LocationTracker's broadcast receiver to run every 5 minutes.
    Intent intent = new Intent(this, LocationTracker.class);
    AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
    PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, intent, 0);
    alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, Calendar.getInstance().getTimeInMillis(),
            LocationProvider.FIVE_MINUTES, pendingIntent);
}

LocationTracker.java

public class LocationTracker extends BroadcastReceiver {

    private PowerManager.WakeLock wakeLock;

    @Override
    public void onReceive(Context context, Intent intent) {
        PowerManager pow = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
        wakeLock = pow.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "");
        wakeLock.acquire();

        Location currentLocation = LocationProvider.getInstance().getCurrentLocation();

        // Send new location to backend. // this will be different for you
        UserService.registerLocation(context, new Handlers.OnRegisterLocationRequestCompleteHandler() {
            @Override
            public void onSuccess() {
                Log.d("success", "UserService.RegisterLocation() succeeded");

                wakeLock.release();
            }

            @Override
            public void onFailure(int statusCode, String errorMessage) {
                Log.d("error", "UserService.RegisterLocation() failed");
                Log.d("error", errorMessage);

                wakeLock.release();
            }
        }, currentLocation);
    }
}

LocationProvider.java

public class LocationProvider {

    private static LocationProvider instance = null;
    private static Context context;

    public static final int ONE_MINUTE = 1000 * 60;
    public static final int FIVE_MINUTES = ONE_MINUTE * 5;

    private static Location currentLocation;

    private LocationProvider() {

    }

    public static LocationProvider getInstance() {
        if (instance == null) {
            instance = new LocationProvider();
        }

        return instance;
    }

    public void configureIfNeeded(Context ctx) {
        if (context == null) {
            context = ctx;
            configureLocationUpdates();
        }
    }

    private void configureLocationUpdates() {
        final LocationRequest locationRequest = createLocationRequest();
        final GoogleApiClient googleApiClient = new GoogleApiClient.Builder(context)
                .addApi(LocationServices.API)
                .build();

        googleApiClient.registerConnectionCallbacks(new GoogleApiClient.ConnectionCallbacks() {
            @Override
            public void onConnected(Bundle bundle) {
                startLocationUpdates(googleApiClient, locationRequest);
            }

            @Override
            public void onConnectionSuspended(int i) {

            }
        });
        googleApiClient.registerConnectionFailedListener(new GoogleApiClient.OnConnectionFailedListener() {
            @Override
            public void onConnectionFailed(ConnectionResult connectionResult) {

            }
        });

        googleApiClient.connect();
    }

    private static LocationRequest createLocationRequest() {
        LocationRequest locationRequest = new LocationRequest();
        locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
        locationRequest.setInterval(FIVE_MINUTES);
        return locationRequest;
    }

    private static void startLocationUpdates(GoogleApiClient client, LocationRequest request) {
        LocationServices.FusedLocationApi.requestLocationUpdates(client, request, new com.google.android.gms.location.LocationListener() {
            @Override
            public void onLocationChanged(Location location) {
                currentLocation = location;
            }
        });
    }

    public Location getCurrentLocation() {
        return currentLocation;
    }
}

I first create an instance of the LocationProvider in a class that extends application, creating the instance when the app is launched:

MyApp.java

public class MyApp extends Application {

    @Override
    public void onCreate() {
        super.onCreate();

        LocationProvider locationProvider = LocationProvider.getInstance();
        locationProvider.configureIfNeeded(this);
    }
}

The LocationProvider is instantiated and configured for location updates exactly once, because it is a singleton. Every 5 minutes it will update its currentLocation value, which we can retrieve from anywhere we need with

Location loc = LocationProvider.getInstance().getCurrentLocation();

Running a background service of any kind is not required. The AlarmManager will broadcast to LocationTracker.onReceive() every 5 minutes and the partial wakelock will ensure that the code will finish running even if the device is standby. This is also energy efficient.

Note that you need the following permissions

<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.INTERNET" />

<!-- For keeping the LocationTracker alive while it is doing networking -->
<uses-permission android:name="android.permission.WAKE_LOCK" />

and don't forget to register the receiver:

<receiver android:name=".LocationTracker" />

这篇关于如何接收位置更新,每5分钟使用FusedLocation API的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆