问题描述
我无法发送额外的字符串,并将 PendingIntent
传递给 LocationServices.FusedLocationApi.requestLocationUpdates(GoogleApiClient客户端,LocationRequest请求, PendingIntent callbackIntent)
。
看起来,我将其放到 Intent
上的用户名额外是损坏 requestLocationUpdates
试图将我的 IntentService
交给 intent.getParcelableExtra(FusedLocationProviderApi.KEY_LOCATION_CHANGED)
返回 null
。
编辑
我尝试了一个实现 Parcelable
的 User
类并将它作为一个额外:
mRequestLocationUpdatesIntent.putExtra(username,new User(username));
我也试着把 Parcelable 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,在intent中发现的键:+ TextUtils.join(,,extras.keySet()));
字符串用户名= intent.getStringExtra(username);
if(username!= null){
Log.d(TAG,username:+ username);
} else {
Log.d(TAG,username:null); $!
$ b if(!intent.hasExtra(FusedLocationProviderApi.KEY_LOCATION_CHANGED)){
Log.d(TAG,intent does not have 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 $ c
<$ c
$ b布尔mLocationUpdatesEnabled = false;
保护void createLocationRequest(){
mLocationRequest = new LocationRequest();
mLocationRequest.setInterval(LOCATION_UPDATE_INTERVAL);
mLocationRequest.setFastestInterval(LOCATION_UPDATE_FASTEST_INTERVAL);
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
保护无效startLocationUpdates(){
Log.d(标签,startng位置更新...);
mLocationUpdatesEnabled = true;
if(mLocationRequest == null){
createLocationRequest();
}
//创建使用WebViewActivity处理结果的Intent
Intent mRequestLocationUpdatesIntent = new Intent(this,LocationUpdateService.class);
//创建一个PendingIntent
mRequestLocationUpdatesPendingIntent = PendingIntent.getService(getApplicationContext(),0,
mRequestLocationUpdatesIntent,
PendingIntent.FLAG_CANCEL_CURRENT);
//请求位置更新
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient,
mLocationRequest,
mRequestLocationUpdatesPendingIntent);
Log.d(TAG,位置更新开始);
保护无效stopLocationUpdates(){
Log.d(标记,停止位置更新...);
mLocationUpdatesEnabled = false;
LocationServices.FusedLocationApi.removeLocationUpdates(
mGoogleApiClient,
mRequestLocationUpdatesPendingIntent);
Log.d(TAG,停止位置更新);
}
这一切都很好,当用户按下按钮时,调用 toggleLocationUpdates
,调用 LocationServices.FusedLocationApi.requestLocationUpdates
,它调用我的 LocationUpdateService
我可以获取位置。
当我试图在我的 Intent
使用Intent.putExtra(String,String):
主要活动类:
...
保护无效startLocationUpdates(字符串用户名){
....
//创建使用WebViewActivity处理结果的意图
Intent mRequestLocationUpdatesIntent = new Intent(this,LocationUpdateService.class);
////////////////////////////////////////// ////////////////////////
//
//当我把这个额外的,IntentService看到我的用户名额外
//但是parcelableExtra`location` == null :(
//
////////////////////////// ////////////////////
mRequestLocationUpdatesIntent。 putExtra(username,username);
...
}
...
编辑 我已经开始下一个句子,而不是一个问题:我正在使用...
我是否使用正确的方法将一些额外的数据发送到此位置更新处理 IntentService
或者有更多的方法去处理这是什么?
这是一个错误还是只是糟糕的文档?
将IntentService与FusedLocationProviderAPI结合使用会带来问题。从标题为 Receipt的开发人员文档位置更新:
此外, PendingIntent
用于扩展另一段代码的权限( FusedLocationProviderAPI
在谷歌播放服务)在您的apk内执行他们的代码。一个 IntentService
用于启动在您的apk范围内定义的服务。
因此,该方法需要为前台更新实现 LocationListener
,或者 PendingIntent
用于与广播接收器配合使用的后台更新。
这是一些用于从 PendingIntent
请求位置更新以及额外值的方法的示例。注意: LocalStorage.java
是存储局部变量的工具类,它不是Android API
GPSPlotter
/ **
*使用
* LocationServices Api初始化Google Api客户端的私人帮助程序方法并构建它以供使用。
* /
private void initializeGoogleApiClient(){
mGoogleApiClient = new GoogleApiClient.Builder(mContext)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
}
/ **
*用于确定GooglePlayServices
*是否安装在本地系统上的专用辅助方法。
*
* @return服务已安装。
* /
private boolean googlePlayServicesInstalled(){
int result = GooglePlayServicesUtil.isGooglePlayServicesAvailable(mContext);
返回结果== ConnectionResult.SUCCESS;
}
/ **
*使用LocationServices API构建Api客户端的私有方法。
* /
私有同步void buildApiClient(){
Log.w(TAG,构建Google Api客户端...);
initializeGoogleApiClient();
}
/ **
*用于将ApiClient连接到Google为
托管的API的私有方法*访问位置。
* /
private void connectClient(){
mGoogleApiClient.connect();
}
/ **
*用户在请求的间隔轮询时间内以秒为单位传递一个
*整数。
*
* @param theAccount是对用于更新视图的父活动的引用。
* /
public void beginManagedLocationRequests(MyAccount theAccount){
if(mAccount == null)
mAccount = theAccount;
startBackgroundUpdates();
}
/ **
*公共方法结束托管的位置请求。
* /
public void endManagedLocationRequests(){
endBackgroundUpdates();
}
/ **
*此方法通过停止然后再次启动
*背景udpates来处理轮询速率的切换,依次在调用堆栈中的另一个方法中设置间隔。
* @param theInterval期望的间隔轮询率
* /
public void changeRequestIntervals(int theInterval){
mIntentInterval = theInterval;
if(LocalStorage.getRequestingBackgroundStatus(mContext)){
endBackgroundUpdates();
startBackgroundUpdates();
}
}
/ **
*建立Intent的私人助手方法将与待处理意图使用
*发出后台位置请求。
*
* @return theIntent
* /
private Intent buildBackgroundRequestIntent(){
Intent intent = new Intent(mContext,BackgroundLocationReceiver.class);
intent.setAction(BACKGROUND_ACTION);
intent.putExtra(User.USER_ID,mUserID);
返回意图;
}
$ b $ ** ** b $ b *用于在用户请求后台服务
*时在FusedLocationApi内生成PendingIntent的专用辅助方法,直到间隔更改。
*
* @return pendingIntent
* /
private PendingIntent buildRequestPendingIntent(Intent theIntent){
Log.w(TAG,building pending intent);
返回PendingIntent.getBroadcast(mContext,0,theIntent,0);
}
/ **
*在后台使用FusedLocation API启动位置更新的私有方法。
* /
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 void endBackgroundUpdates(){
Log.w(TAG,Ending background updates);
LocalStorage.putBackgroundRequestStatus(false,mContext);
LocalStorage.putLocationRequestStatus(false,mContext);
unregisterAlarmManager();
LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient,buildRequestPendingIntent(buildBackgroundRequestIntent()));
}
BackgroundLocationReceiver $ b
public class BackgroundLocationReceiver extends BroadcastReceiver {
private static final String TAG =BLocRec:;
private static final String UPLOAD_ERROR_MESSAGE =上传坐标后台服务失败。;
private static final String UPLOAD_MESSAGE =坐标批处理推送到数据库。
public BackgroundLocationReceiver(){
//默认,无参数构造函数
}
$ b $ / **
*此方法处理任何在应用程序不再焦点时收到的位置更新。坐标是
*存储在本地数据库中并且每小时上传一次。
* @param context应用程序上下文
* @param intent是待处理的意图
* /
@Override
public void onReceive(Context context,Intent intent){如果(intent.getAction()。matches(GPSPlotter.BACKGROUND_ACTION)){
Log.w(TAG,BLR Received-background);
位置位置= intent.getParcelableExtra(FusedLocationProviderApi.KEY_LOCATION_CHANGED);
storeLocation(location,context,intent.getStringExtra(User.USER_ID));
$编辑
下面的方法创建了调用 requestLocationUpdates()
方法所必需的LocationRequest / **
*用于生成LocationRequest的私有助手方法,该方法将用于处理FusedLocationApi中的所有位置更新
*,直到间隔改变。
*
* @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(标签,建筑物位置请求);
返回locationRequest;
}
编辑
After在与Catherine聊天的长时间讨论中,我们得出的结论是,Google Play服务库7.5有一个错误,当其他附加内容放入Intent时,它不处理从FusedLocationProviderAPI传递的Parcelable Extra Location。但是,7.0确实提供了这种功能。她表示她会提交一个错误,我们会看到Android团队需要多长时间才能解决问题。
I'm having trouble sending a string extra with my PendingIntent
that I pass to LocationServices.FusedLocationApi.requestLocationUpdates(GoogleApiClient client, LocationRequest request, PendingIntent callbackIntent)
.
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
.
EDIT
I've tried making a User
class that implements Parcelable
and putting it as an extra:
mRequestLocationUpdatesIntent.putExtra("username", new User(username));
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);
in my service:
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.
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()));
...
}
}
When the user clicks a button, the startLocationUpdates
is called in my main activity:
main activity class:
...
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");
}
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.
The trouble comes when I tried to put a string extra onto my Intent
using Intent.putExtra(String, String):
main activity class:
...
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);
...
}
...
EDIT I had started the next sentence as a statement rather than a question: "I am using..."
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?
解决方案 Using the IntentService coupled with the FusedLocationProviderAPI will present issues. From the Developer Docs titled Receiving Location Updates:
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.
So, the method requires an implementation of LocationListener
for foreground updates, or a PendingIntent
for background updates coupled with a Broadcast Receiver.
This is a working example of some methods used to request location updates from a PendingIntent
coupled with extra values.
Note: LocalStorage.java
is a utility class for storing local variables, it is not part of the 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));
}
EDITThe 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;
}
EDITAfter a long discussion in chat with Catherine, we came to the conclusion that google play services library 7.5 has a bug that does not process the Parcelable Extra Location passed from FusedLocationProviderAPI when other extras are put into the Intent. However, 7.0 does provide this capability. She said that she will submit a bug and we'll see how long it takes the Android team to resolve
这篇关于向requestLocationUpdates发送额外的intentService打破位置更新的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!