Meh*_*sar 6 android locationlistener android-location
为了在后台检索融合位置,我创建了一个与Commonsguy创建的cwac -locpoll库非常相似的库.
在PollerThread内部,我正在尝试使用连接,请求和检索位置LocationClient.
我可以通过接收onConnected方法的回调来连接,但是我无法在方法上获得回调.因此onLocationChanged我的onTimeout线程按照确定的间隔执行.
注意: 此问题仅在屏幕指示灯熄灭时发生.否则它完全正常.
我怀疑新的位置Api可能存在错误.
这是我的实施PollerThread,
private class PollerThread extends WakefulThread implements GooglePlayServicesClient.ConnectionCallbacks,
GooglePlayServicesClient.OnConnectionFailedListener,LocationListener{
private static final String TAG = "PollerThread";
//context
private Context mContext=null;
private LocationClient mLocationClient=null;
private LocationRequest mLocationRequest=null;
private LocationManager locMgr=null;
private Intent intentTemplate=null;
private Handler handler=new Handler();
private Runnable onTimeout = new Runnable() {
@Override
public void run() {
Log.e(TAG, "onTimeout");
//prepare broadcast intent
Intent toBroadcast=new Intent(intentTemplate);
toBroadcast.putExtra(FusedPoller.EXTRA_ERROR, "Timeout!");
toBroadcast.putExtra(
FusedPoller.EXTRA_ERROR_PROVIDER_DISABLED, false);
toBroadcast.putExtra(FusedPoller.EXTRA_LASTKNOWN,
mLocationClient.getLastLocation());
sendBroadcast(toBroadcast);
//stop the thread
quit();
}
};
PollerThread(Context mContext,LocationRequest mLocationRequest,PowerManager.WakeLock lock, LocationManager locMgr,
Intent intentTemplate) {
super(lock, "LocationPoller-PollerThread");
Log.e(TAG, "PollerThread");
this.mContext=mContext;
this.mLocationRequest=mLocationRequest;
this.locMgr=locMgr;
this.intentTemplate=intentTemplate;
}
@Override
protected void onPreExecute() {
super.onPreExecute();
Log.e(TAG, "onPreExecute");
//setup timeout
setTimeoutAlarm();
//initiate connection
initiateConnection();
}
@Override
protected void onPostExecute() {
super.onPostExecute();
Log.e(TAG, "onPostExecute");
//remove timeout
removeTimeoutAlarm();
//disconnect
initiateDisconnection();
}
/**
* Called when the WakeLock is completely unlocked.
* Stops the service, so everything shuts down.
*/
@Override
protected void onUnlocked() {
Log.e(TAG, "onUnlocked");
stopSelf();
}
private void setTimeoutAlarm() {
Log.e(TAG, "setTimeoutAlarm");
handler.postDelayed(onTimeout, FusedLocationUtils.DEFAULT_TIMEOUT);
}
private void removeTimeoutAlarm()
{
Log.e(TAG, "removeTimeoutAlarm");
handler.removeCallbacks(onTimeout);
}
private void initiateConnection()
{
Log.e(TAG, "initiateConnection");
mLocationClient = new LocationClient(this.mContext, this, this);
mLocationClient.connect();
}
private void initiateDisconnection()
{
Log.e(TAG, "initiateDisconnection");
if(mLocationClient.isConnected())
{
mLocationClient.disconnect();
}
}
@Override
public void onConnected(Bundle arg0) {
Log.e(TAG, "onConnected");
Log.e(TAG, "provider: GPS-"+locMgr.isProviderEnabled(LocationManager.GPS_PROVIDER)+" NETWORK-"+locMgr.isProviderEnabled(LocationManager.NETWORK_PROVIDER));
if (!(locMgr.isProviderEnabled(LocationManager.GPS_PROVIDER)) && !(locMgr.isProviderEnabled(LocationManager.NETWORK_PROVIDER))) {
Log.e(TAG, "both disabled");
//get last location and broadcast it
getLastLocationAndBroadcast();
//stop the thread
quit();
}
else
{
Log.e(TAG, "provider enabled");
//get latest location and broadcast it
getLatestLocationAndBroadcast();
//don't quit from here,quit from onLocationChanged
}
}
@Override
public void onDisconnected() {
Log.e(TAG, "onDisconnected");
// TODO Auto-generated method stub
}
@Override
public void onConnectionFailed(ConnectionResult arg0) {
Log.e(TAG, "onConnectionFailed");
// TODO Auto-generated method stub
}
@Override
public void onLocationChanged(Location location) {
Log.e(TAG, "onLocationChanged");
//prepare broadcast intent
Intent toBroadcast=new Intent(intentTemplate);
toBroadcast.putExtra(FusedPoller.EXTRA_LOCATION, location);
sendBroadcast(toBroadcast);
//stop further updates
stopUpdates();
//stop the thread
quit();
}
private void getLatestLocationAndBroadcast() {
Log.e(TAG, "getLatestLocationAndBroadcast");
if(mLocationClient.isConnected() && servicesConnected())
{
Log.e(TAG, "going to request updates");
Log.e(TAG, "lockStatic.isHeld(): "+lockStatic.isHeld());
mLocationClient.requestLocationUpdates(mLocationRequest, this);
}
else
{
Log.e(TAG, "not going to request updates");
}
}
private void stopUpdates() {
Log.e(TAG, "stopUpdates");
if(servicesConnected())
{
Log.e(TAG,getString(R.string.location_updates_stopped));
mLocationClient.removeLocationUpdates(this);
}
else
{
Log.e(TAG,"can't do:"+getString(R.string.location_updates_stopped));
}
}
private void getLastLocationAndBroadcast() {
Log.e(TAG, "getLastLocationAndBroadcast");
if(mLocationClient.isConnected() && servicesConnected())
{
Log.e(TAG, "going to get last location: "+mLocationClient.getLastLocation());
Intent toBroadcast = new Intent(intentTemplate);
toBroadcast.putExtra(FusedPoller.EXTRA_ERROR,
"Location Provider disabled!");
toBroadcast.putExtra(
FusedPoller.EXTRA_ERROR_PROVIDER_DISABLED, true);
toBroadcast.putExtra(FusedPoller.EXTRA_LASTKNOWN,
mLocationClient.getLastLocation());
sendBroadcast(toBroadcast);
}
else
{
Log.e(TAG, "not going to get last location");
}
}
}
Run Code Online (Sandbox Code Playgroud)
和servicesConnected方法实施,
/**
* Verify that Google Play services is available before making a request.
*
* @return true if Google Play services is available, otherwise false
*/
private boolean servicesConnected() {
Log.e(TAG, "servicesConnected");
// Check that Google Play services is available
int resultCode =
GooglePlayServicesUtil.isGooglePlayServicesAvailable(this);
// If Google Play services is available
if (ConnectionResult.SUCCESS == resultCode) {
// In debug mode, log the status
Log.d(FusedLocationUtils.APPTAG, getString(R.string.play_services_available));
// Continue
return true;
// Google Play services was not available for some reason
} else {
// Display an error dialog
Log.d(FusedLocationUtils.APPTAG, getString(R.string.play_services_unavailable));
Toast.makeText(this, getString(R.string.play_services_unavailable), Toast.LENGTH_SHORT).show();
return false;
}
}
Run Code Online (Sandbox Code Playgroud)
Sea*_*eau 18
如果您想在后台监听频繁的位置更新(例如,每秒),您应该在以下位置运行代码Service:
http://developer.android.com/reference/android/app/Service.html
Android平台可以在不在前台的任何时间点结束活动.
使用服务时,我建议让服务直接实现LocationListener,而不是服务中的Thread.例如,使用:
public class LocListener extends Service implements com.google.android.gms.location.LocationListener, ...{
Run Code Online (Sandbox Code Playgroud)
我已经LocationClient在我的GPS Benchmark应用程序中使用这个设计直接在服务上使用融合位置提供程序实现了LocationListener ,我可以确认即使屏幕关闭且应用程序在后台运行也能正常工作.
如果您想使用融合位置提供程序在后台(例如,每分钟)收听偶尔的位置更新,则更好的设计是使用PendingIntents,使用以下LocationClient.requestLocationUpdates(Location Request, PendingIntent callbackIntent)方法:
从上面的Android文档:
此方法适用于后台用例,更具体地说,适用于接收位置更新,即使应用程序已被系统杀死也是如此.为此,请对已启动的服务使用PendingIntent.对于前台用例,建议使用该方法的LocationListener版本,请参阅requestLocationUpdates(LocationRequest,LocationListener).
在此PendingIntent上注册的任何先前LocationRequests都将被替换.
使用KEY_LOCATION_CHANGED键和intent上的Location值发送位置更新.
有关PendingIntents在后台运行时使用获取更新的更详细说明,请参阅活动识别示例:
https://developer.android.com/training/location/activity-recognition.html
以下是本文档的修改摘录,由我更改为特定于位置更新.
首先声明意图:
public class MainActivity extends FragmentActivity implements
ConnectionCallbacks, OnConnectionFailedListener {
...
...
/*
* Store the PendingIntent used to send location updates
* back to the app
*/
private PendingIntent mLocationPendingIntent;
// Store the current location client
private LocationClient mLocationClient;
...
}
Run Code Online (Sandbox Code Playgroud)
按照您目前的要求进行更新,但这次传递了待处理的意图:
/*
* Create the PendingIntent that Location Services uses
* to send location updates back to this app.
*/
Intent intent = new Intent(
mContext, LocationIntentService.class);
...
//Set up LocationRequest with desired parameter here
...
/*
* Request a PendingIntent that starts the IntentService.
*/
mLocationPendingIntent =
PendingIntent.getService(mContext, 0, intent,
PendingIntent.FLAG_UPDATE_CURRENT);
/*
* Request location updates
*/
mLocationClient.requestLocationUpdates(mLocationRequest, callbackIntent);
Run Code Online (Sandbox Code Playgroud)
处理位置更新
要处理位置服务为每个更新间隔发送的Intent,请在onHandleIntent()上定义IntentService及其所需方法.位置服务使用您在调用requestLocationUpdates()时提供的PendingIntent以Intent对象的形式发送...更新.由于您为PendingIntent提供了明确的意图,因此接收意图的唯一组件是您正在定义的IntentService.
在onHandleIntent()中定义类和所需的方法:
/**
* Service that receives Location updates. It receives
* updates in the background, even if the main Activity is not visible.
*/
public class LocationIntentService extends IntentService {
...
/**
* Called when a new location update is available.
*/
@Override
protected void onHandleIntent(Intent intent) {
Bundle b = intent.getExtras();
Location loc = (Location) b.get(LocationClient.KEY_LOCATION_CHANGED);
Log.d(TAG, "Updated location: " + loc.toString());
}
...
}
Run Code Online (Sandbox Code Playgroud)
重要信息 - 为了尽可能高效,您的代码onHandleIntent()应尽快返回以允许IntentService关闭.来自IntentService文档:
在工作线程上调用此方法并请求处理.一次只处理一个Intent,但处理发生在独立于其他应用程序逻辑运行的工作线程上.因此,如果此代码需要很长时间,它将阻止对同一个IntentService的其他请求,但它不会阻止其他任何内容.处理完所有请求后,IntentService会自行停止,因此不应调用stopSelf().
我对IntentService设计的理解是你可以在里面生成Threads onHandleIntent()以避免通过平台调用阻止其他位置更新onHandleIntent(),只要知道服务将继续运行直到所有正在运行的线程终止.
| 归档时间: |
|
| 查看次数: |
6787 次 |
| 最近记录: |