发送额外的requestLocationUpdates intentService中断位置更新

时间:2015-06-16 00:09:21

标签: android android-intent google-play-services android-location fusedlocationproviderapi

我在传递给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)); 并将其作为额外内容添加:

Parcelable User

我还尝试将Bundle置于Bundle userBundle = new Bundle(); userBundle.putParcelable("user", new User(username)); mRequestLocationUpdatesIntent.putExtra("user", userBundle); 内,如此错误报告https://code.google.com/p/android/issues/detail?id=81812中的评论所示:

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.requestLocationUpdates,调用LocationUpdateService来调用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

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

我是否使用正确的方法向此位置更新处理#include <iostream> #include <typeinfo> struct Bar { Bar(double); // some non-default ctor double f(); // some function of which return type we want to get }; using Barref = Bar&&; // emulating std::declval<Bar>() int main() { // FUNKY, compiles in g++, not in clang++ // error: unexpected type name 'Barref': expected expression decltype(Barref.f()) x; // (1) std::cout << typeid(x).name() << std::endl; // i -> int INCORRECT // OK, just for testing decltype(std::declval<Bar>().f()) y; // (2) std::cout << typeid(y).name() << std::endl; // d -> double CORRECT } 发送一些额外数据,还是有更合理的方法来解决这个问题?

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

1 个答案:

答案 0 :(得分:-1)

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

  

根据请求的形式,融合位置提供商   或者调用LocationListener.onLocationChanged()回调   方法并将其传递给Location对象,或者发出PendingIntent   包含其扩展数据中的位置。准确性和频率   您所拥有的位置权限会影响更新   请求以及您在位置请求对象中设置的选项

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

因此,该方法需要实现LocationListener用于前景更新,或PendingIntent用于与广播接收器配合的后台更新。

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

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

<强> GPSPlotter

/**
 * 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

/**
 * 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确实提供了这种功能。她说她会提交一个错误,我们会看到Android团队需要多长时间来解决