9

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

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

编辑

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

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

而且我还尝试按照此错误报告https://code.google.com/p/android/issues/detail?id=81812Parcelable User中的评论建议将内部放入:Bundle

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();

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

我设置它IntentService来处理位置更新:

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在我的主要活动中被调用:

主要活动类:

...

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.requestLocationUpdateswhich call my LocationUpdateServicewhere I can get the location。

当我尝试在我的Intent使用 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或者是否有更明智的方法来解决这个问题?

这是一个错误还是只是糟糕的文档?

4

1 回答 1

-1

将 IntentService 与 FusedLocationProviderAPI 结合使用会出现问题。从标题为接收位置更新的开发人员文档中:

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

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

因此,该方法需要实现LocationListener前台更新,或者PendingIntent后台更新与广播接收器相结合。

这是一些用于从附加值请求位置更新的方法的工作示例PendingIntent

注意:LocalStorage.java是一个用于存储局部变量的实用程序类,它不是 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()));
}

背景位置接收器

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

/**
 * 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 服务库 7.5 存在一个错误,当其他额外内容放入 Intent 时,该错误不会处理从 FusedLocationProviderAPI 传递的 Parcelable Extra Location。但是,7.0 确实提供了这种能力。她说她会提交一个bug,我们看看Android团队需要多长时间才能解决

于 2015-08-15T16:10:53.120 回答