向 requestLocationUpdates 发送额外的 intentService 中断位置更新 [英] sending extra to requestLocationUpdates intentService breaks location updates

本文介绍了向 requestLocationUpdates 发送额外的 intentService 中断位置更新的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我无法使用传递给 LocationServices.FusedLocationApi.requestLocationUpdates(GoogleApiClient client, LocationRequest request, PendingIntent callbackIntent)PendingIntent 发送额外的字符串.

I'm having trouble sending a string extra with my PendingIntent that I pass to LocationServices.FusedLocationApi.requestLocationUpdates(GoogleApiClient client, LocationRequest request, PendingIntent callbackIntent).

看来,我在 Intent 上添加的额外用户名正在破坏 requestLocationUpdates 试图移交给我的 IntentService 的位置> as intent.getParcelableExtra(FusedLocationProviderApi.KEY_LOCATION_CHANGED) 返回 null.

It appears that the username extra i'm putting onto the Intent is mangling the location that requestLocationUpdates is trying to hand off to my IntentService as intent.getParcelableExtra(FusedLocationProviderApi.KEY_LOCATION_CHANGED) returns null.

编辑

我尝试制作一个实现 ParcelableUser 类并将其作为额外的:

I've tried making a User class that implements Parcelable and putting it as an extra:

mRequestLocationUpdatesIntent.putExtra("username", new User(username));

并且我还尝试将 Parcelable User 放入 Bundle 中,如通过此错误报告中的评论https://code.google.com/p/android/issues/detail?id=81812:

and I've also tried to put the Parcelable User inside a Bundle as suggested via comment in this bug report https://code.google.com/p/android/issues/detail?id=81812:

Bundle userBundle = new Bundle();
userBundle.putParcelable("user", new User(username));
mRequestLocationUpdatesIntent.putExtra("user", userBundle);

在我的服务中:

Bundle userBundle = intent.getBundleExtra("user");
User user = userBundle.getParcelable("user");
String username = user.getUsername();

然而,这两种方法都没有产生任何区别.每当我在意图上添加任何额外内容时,位置永远不会在发生更新时添加到意图中.

However neither of these approaches has made any difference. Whenever I put any extra onto my intent, the location is never added to the intent when the updates occur.

我设置了这个 IntentService 来处理位置更新:

I setup this IntentService to handle location updates:

public class LocationUpdateService extends IntentService {

    private final String TAG = "LocationUpdateService";

    public LocationUpdateService() {
        super("LocationUpdateService");
    }


    @Override
    protected void onHandleIntent(Intent intent) {

        Log.d(TAG, "onHandleIntent");

        Bundle extras = intent.getExtras();
        Log.d(TAG, "keys found inside intent: " + TextUtils.join(", ", extras.keySet()));

        String username = intent.getStringExtra("username");

        if (username != null) {
            Log.d(TAG, "username: " + username);
        } else {
            Log.d(TAG, "username: null");
        }

        if (!intent.hasExtra(FusedLocationProviderApi.KEY_LOCATION_CHANGED)) {
            Log.d(TAG, "intent does not have location :(");
        }

        Location location = intent.getParcelableExtra(FusedLocationProviderApi.KEY_LOCATION_CHANGED);

        if (location == null) {
            Log.d(TAG, "location == null :(");
        }

        Log.d(TAG, "latitude " + String.valueOf(location.getLatitude()));
        Log.d(TAG, "longitude " + String.valueOf(location.getLongitude()));

        ...

    }


}

当用户点击一个按钮时,startLocationUpdates 在我的主要活动中被调用:

When the user clicks a button, the startLocationUpdates is called in my main activity:

主要活动类:

...

Boolean mLocationUpdatesEnabled = false;

protected void createLocationRequest() {
    mLocationRequest = new LocationRequest();
    mLocationRequest.setInterval(LOCATION_UPDATE_INTERVAL);
    mLocationRequest.setFastestInterval(LOCATION_UPDATE_FASTEST_INTERVAL);
    mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
}

protected void startLocationUpdates() {

    Log.d(TAG, "startng location updates...");

    mLocationUpdatesEnabled = true;

    if (mLocationRequest == null) {
        createLocationRequest();
    }

    // create the Intent to use WebViewActivity to handle results
    Intent mRequestLocationUpdatesIntent = new Intent(this, LocationUpdateService.class);

    // create a PendingIntent
    mRequestLocationUpdatesPendingIntent = PendingIntent.getService(getApplicationContext(), 0,
            mRequestLocationUpdatesIntent,
            PendingIntent.FLAG_CANCEL_CURRENT);

    // request location updates
    LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient,
            mLocationRequest,
            mRequestLocationUpdatesPendingIntent);

    Log.d(TAG, "location updates started");
}

protected void stopLocationUpdates() {

    Log.d(TAG, "stopping location updates...");

    mLocationUpdatesEnabled = false;

    LocationServices.FusedLocationApi.removeLocationUpdates(
            mGoogleApiClient,
            mRequestLocationUpdatesPendingIntent);

    Log.d(TAG, "location updates stopped");
}

这一切都运行良好;当用户按下按钮时,toggleLocationUpdates 被调用,它调用 LocationServices.FusedLocationApi.requestLocationUpdates 调用我的 LocationUpdateService 在那里我可以得到位置.

This all works well and good; When the user presses the button, toggleLocationUpdates is called, which calls LocationServices.FusedLocationApi.requestLocationUpdates which calls my LocationUpdateService where I'm able to get the location.

当我尝试使用 Intent.putExtra(String, String) 将额外的字符串放入我的 Intent 时,问题就出现了:

The trouble comes when I tried to put a string extra onto my Intent using Intent.putExtra(String, String):

主要活动类:

...
protected void startLocationUpdates(String username) {
    ....

    // create the Intent to use WebViewActivity to handle results
    Intent mRequestLocationUpdatesIntent = new Intent(this, LocationUpdateService.class);

    //////////////////////////////////////////////////////////////////
    //
    //  When I put this extra, IntentService sees my username extra
    //  but the parcelableExtra `location` == null :(
    // 
    //////////////////////////////////////////////////////////////////

    mRequestLocationUpdatesIntent.putExtra("username", username);
    ...
}
...

编辑 我将下一句话作为陈述而不是问题开始:我正在使用..."

我是否使用正确的方法将一些额外的数据发送到这个位置更新处理 IntentService 或者是否有更明智的方法来解决这个问题?

Am I using the correct approach to sending some extra data to this location update handling IntentService or is there a more-sane way to go about this?

这是一个错误还是文档很差?

Is this a bug or just poor documentation?

推荐答案

将 IntentService 与 FusedLocationProviderAPI 结合使用会出现问题.来自标题为接收位置更新的开发者文档:

Using the IntentService coupled with the FusedLocationProviderAPI will present issues. From the Developer Docs titled Receiving Location Updates:

根据请求的形式,融合位置提供者要么调用 LocationListener.onLocationChanged() 回调方法并向其传递一个 Location 对象,或者发出一个 PendingIntent在其扩展数据中包含该位置.精度和频率的更新受您拥有的位置权限的影响请求和您在位置请求对象中设置的选项

Depending on the form of the request, the fused location provider either invokes the LocationListener.onLocationChanged() callback method and passes it a Location object, or issues a PendingIntent that contains the location in its extended data. The accuracy and frequency of the updates are affected by the location permissions you've requested and the options you set in the location request object

此外,PendingIntent 用于扩展另一段代码(Google Play 服务中的 FusedLocationProviderAPI)的权限,以在您的 apk 中执行它们的代码.IntentService 用于启动在您的 apk 范围内定义的服务.

Further, a PendingIntent is used for extending permissions for another piece of code (FusedLocationProviderAPI in Google Play Services) to execute their code within your apk. An IntentService is used to start a Service defined within the scope of your apk.

因此,该方法需要实现用于前台更新的 LocationListener,或用于后台更新的 PendingIntent 和广播接收器.

So, the method requires an implementation of LocationListener for foreground updates, or a PendingIntent for background updates coupled with a Broadcast Receiver.

这是一些用于从 PendingIntent 和额外值请求位置更新的方法的工作示例.

This is a working example of some methods used to request location updates from a PendingIntent coupled with extra values.

注意:LocalStorage.java 是一个用于存储局部变量的实用类,它不是 Android API 的一部分

Note: LocalStorage.java is a utility class for storing local variables, it is not part of the Android API

GPS绘图仪

/**
 * Private helper method to initialize the Google Api Client with the
 * LocationServices Api and Build it for use.
 */
private void initializeGoogleApiClient() {
    mGoogleApiClient = new GoogleApiClient.Builder(mContext)
            .addConnectionCallbacks(this)
            .addOnConnectionFailedListener(this)
            .addApi(LocationServices.API)
            .build();

}

/**
 * Private helper method to determine whether or not GooglePlayServices
 * are installed on the local system.
 *
 * @return services are installed.
 */
private boolean googlePlayServicesInstalled() {
    int result = GooglePlayServicesUtil.isGooglePlayServicesAvailable(mContext);
    return result == ConnectionResult.SUCCESS;
}

/**
 * Private method to build the Api Client for use with the LocationServices API.
 */
private synchronized void buildApiClient() {
    Log.w(TAG, "Building Google Api Client...");
    initializeGoogleApiClient();
}

/**
 * Private method used to connect the ApiClient to the Api hosted by Google for
 * Accessing Locations.
 */
private void connectClient() {
    mGoogleApiClient.connect();
}

 /**
 * User passes in a requested interval polling time in seconds as an
 * integer.
 *
 * @param theAccount is a reference to the parent activity used for updating views.
 */
public void beginManagedLocationRequests(MyAccount theAccount) {
    if (mAccount == null)
        mAccount = theAccount;

    startBackgroundUpdates();

}

/**
 * Public method to end the managed Location Requests.
 */
public void endManagedLocationRequests() {
        endBackgroundUpdates();

}

/**
 * This method handles the switch in polling rates by stopping and then starting once more the
 * background udpates, which in turn sets the interval in another method in the call stack.
 * @param theInterval the desired interval polling rate
 */
public void changeRequestIntervals(int theInterval) {
    mIntentInterval = theInterval;
    if (LocalStorage.getRequestingBackgroundStatus(mContext)) {
        endBackgroundUpdates();
        startBackgroundUpdates();
    }



}

/**
 * Private helper method to build an Intent that will be couple with a pending intent uses
 * for issuing background Location requests.
 *
 * @return theIntent
 */
private Intent buildBackgroundRequestIntent() {
    Intent intent = new Intent(mContext, BackgroundLocationReceiver.class);
    intent.setAction(BACKGROUND_ACTION);
    intent.putExtra(User.USER_ID, mUserID);
    return intent;
}

/**
 * Private helper method used to generate a PendingIntent for use when the User requests background service
 * within the FusedLocationApi until the Interval is changed.
 *
 * @return pendingIntent
 */
private PendingIntent buildRequestPendingIntent(Intent theIntent) {
    Log.w(TAG, "building pending intent");
    return PendingIntent.getBroadcast(mContext, 0, theIntent, 0);
}


/**
 * Private method to start the Location Updates using the FusedLocation API in the background.
 */
private void startBackgroundUpdates() {
    Log.w(TAG, "Starting background updates");
    if (googlePlayServicesInstalled()) {
        LocalStorage.putBackgroundRequestStatus(true, mContext);
        LocalStorage.putLocationRequestStatus(true, mContext);
        registerAlarmManager();
        LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, buildLocationRequest(), buildRequestPendingIntent(buildBackgroundRequestIntent()));
    }
}


/**
 * Private method to end background updates.
 */
private void endBackgroundUpdates() {
    Log.w(TAG, "Ending background updates");
    LocalStorage.putBackgroundRequestStatus(false, mContext);
    LocalStorage.putLocationRequestStatus(false, mContext);
    unregisterAlarmManager();
    LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, buildRequestPendingIntent(buildBackgroundRequestIntent()));
}

BackgroundLocationReceiver

public class BackgroundLocationReceiver extends BroadcastReceiver {
private static final String TAG = "BLocRec: ";
private static final String UPLOAD_ERROR_MESSAGE = "Background Service to Upload Coordinates Failed.";
private static final String UPLOAD_MESSAGE = "Coordinate Batch Pushed to Database.";

public BackgroundLocationReceiver() {
    //Default, no-arg constructor
}

/**
 * This method handles any location updates received when the app is no longer in focus. Coordinates are
 * stored in the local database and uploaded once every hour.
 * @param context the application context
 * @param intent is the pending intent
 */
@Override
public void onReceive(Context context, Intent intent) {

    if (intent.getAction().matches(GPSPlotter.BACKGROUND_ACTION)) {
        Log.w(TAG, "BLR Received-background");
        Location location = intent.getParcelableExtra(FusedLocationProviderApi.KEY_LOCATION_CHANGED);
        storeLocation(location, context, intent.getStringExtra(User.USER_ID));

    }

编辑下面的方法构建了一个调用requestLocationUpdates()方法所必需的LocationRequest

EDIT The method below builds a LocationRequest necessary for invoking the requestLocationUpdates() method

/**
 * Private helper method used to generate a LocationRequest which will be used to handle all location updates
 * within the FusedLocationApi until the Interval is changed.
 *
 * @return locationRequest
 */
private LocationRequest buildLocationRequest() {
    int dateConversion = 1000;
    LocationRequest locationRequest = LocationRequest.create();
    locationRequest.setInterval(mIntentInterval * dateConversion);
    locationRequest.setFastestInterval((mIntentInterval / 2) * dateConversion);
    locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
    Log.w(TAG, "Building location request");
    return locationRequest;
}

编辑在与Catherine的聊天中经过长时间的讨论后,我们得出的结论是,google play services library 7.5存在一个错误,即当其他额外内容放入Intent时,不会处理从FusedLocationProviderAPI传递过来的Parcelable Extra Location.但是,7.0 确实提供了此功能.她说她会提交一个bug,我们看看Android团队需要多长时间来解决

这篇关于向 requestLocationUpdates 发送额外的 intentService 中断位置更新的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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