requestLocationUpdates在确切的固定间隔后

时间:2014-08-25 11:49:54

标签: android gps location location-client

目标:在完全 15分钟后在服务中使用更少的电池来保存服务在数据库中的当前位置。我在我的应用中的不同位置使用这些位置

locationrequest = LocationRequest.create();
        locationrequest.setInterval(5*60000);
locationrequest
        .setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);
        locationclient.requestLocationUpdates(locationrequest, mPendingIntent);

问题:我正在使用上面的代码不按照设置的间隔值请求位置。虽然,我知道这个间隔是不准确的。您可能根本没有收到更新,或者您可能会收到比请求更慢的更新。您也可以比要求更快地收到它们。有时,位置会在1分钟后更新,我不想浪费处理和电池来以较小的间隔获取位置。

public class LoginActivity extends Activity implements OnClickListener  
    , 

GooglePlayServicesClient.ConnectionCallbacks,GooglePlayServicesClient.OnConnectionFailedListener,LocationListener {

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.login_screen);
///my code 
mIntentService = new Intent(LoginActivity.this,LocationService.class);
        mIntentService.putExtra("time",String.valueOf(System.currentTimeMillis()) );
          mPendingIntent = PendingIntent.getService(LoginActivity.this, 1, mIntentService, 0);

          int resp =GooglePlayServicesUtil.isGooglePlayServicesAvailable(this);
          if(resp == ConnectionResult.SUCCESS){
           locationclient = new LocationClient(this,this,this);
           locationclient.connect();
          }
          else{
           Toast.makeText(this, "Google Play Service Error " + resp, Toast.LENGTH_LONG).show();
          }


    @Override
    public void onLocationChanged(Location location) {
        // TODO Auto-generated method stub

    }

    @Override
    public void onConnectionFailed(ConnectionResult arg0) {
        // TODO Auto-generated method stub

    }

    @Override
    public void onConnected(Bundle arg0) {
        // TODO Auto-generated method stub
        Log.i("fused", " onConnected " );
//      mIntentService = new Intent(LoginActivity.this,LocationService.class);
//        mPendingIntent = PendingIntent.getService(LoginActivity.this, 1, mIntentService, 0);

        locationrequest = LocationRequest.create();
        locationrequest.setInterval(5*60000);
//      locationrequest
//      .setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);
        locationclient.requestLocationUpdates(locationrequest, mPendingIntent);
//       locationrequest = LocationRequest.create();
//         locationrequest.setInterval(1000);//??
//         locationclient.requestLocationUpdates(locationrequest, this);

    }

    @Override
    public void onDisconnected() {
        // TODO Auto-generated method stub

    }

}

LocationService

public class LocationService extends IntentService {

    private String TAG = this.getClass().getSimpleName();
    public LocationService() {
        super("Fused Location");
    }

    public LocationService(String name) {
        super("Fused Location");
    }

    @Override
    protected void onHandleIntent(Intent intent) {
//      Log.i("fused", "onHandleIntent LocationService");

            Location location = intent.getParcelableExtra(LocationClient.KEY_LOCATION_CHANGED);
            if(location !=null){
                String time= intent.getStringExtra("time");
                Log.i("fused", "onHandleIntent LocationService " +time+"---"+ location.getLatitude() + "," + location.getLongitude());


                updateTransientLocation(getApplicationContext(), location);


            }

    }

此外,我需要在后台只在数据库中定期保存这些位置,因此无法使用requestLocationUpdates而无需等待服务的意图。

我已将this提到代码

感谢。

编辑 - 解决方案这就是我的问题解决方法

活动代码

    Intent myIntent = new Intent(context,LocationReceiver.class);


        PendingIntent pi = PendingIntent.getBroadcast(context, 0, myIntent, 0);

        alarmMgr.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
                SystemClock.elapsedRealtime(),
//              120000,pi);
  • 我删除了位置服务类并添加了位置接收器

LocationReceiver

public class LocationReceiver extends BroadcastReceiver implements
        GooglePlayServicesClient.ConnectionCallbacks,
        GooglePlayServicesClient.OnConnectionFailedListener, LocationListener {
    SharedPreferences prefs = null;
    LocationClient locationclient = null;
    Context contxt;

    /** For location poller NO LONGER IN USE **/


    @Override
    public void onReceive(Context context, Intent intent) {
        contxt=context;
        //Log.i("locationreciever", "in location rec");
        Log.i("fused", "in location rec");


        int resp = GooglePlayServicesUtil
                .isGooglePlayServicesAvailable(context);

        if (resp == ConnectionResult.SUCCESS) {
            locationclient = new LocationClient(context, this, this);
            locationclient.connect();
        } else {
            Log.i("fused", "loc client Google Play Service Error");
        }
}

@Override
    public void onLocationChanged(Location location) {
        Log.i("fused", " onLocationChanged Location Request :" + location.getLatitude() + "," + location.getLongitude());
        updateTransientLocation(contxt, location);
        if (locationclient != null) {
            if (locationclient.isConnected()) {
                locationclient.removeLocationUpdates(this);
                locationclient.disconnect();
            }
        }
    }

    @Override
    public void onConnectionFailed(ConnectionResult arg0) {
        Log.i("fused", "loc client connection failed");
    }

    @Override
    public void onConnected(Bundle arg0) {
        Log.i("fused", "loc client onConnected");
        LocationRequest locationrequest = LocationRequest.create();
        locationrequest
    .setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);
        locationclient.requestLocationUpdates(locationrequest, this);
    }

    @Override
    public void onDisconnected() {
        Log.i("fused", "loc client disconnected");
    }
}

2 个答案:

答案 0 :(得分:1)

最好的解决方案是使用您当前的方法。你告诉操作系统你不经常需要位置,但是其他东西可能正在请求位置,在这种情况下你可能只是接受它,因为手机已经唤醒了获得GPS修复并将其广播到对某个位置感兴趣的每个进程。这样,您的应用程序实际上可能永远不必打开GPS,因为您基本上只使用另一个进程请求的位置修复程序,每15分钟更频繁一次。要在此处搜索的关键字是新的fused location provider

如果您坚持每15分钟获取一个位置,则可以使用AlarmManager来安排作业每15分钟运行一次,而不是安排位置请求。在警报管理器中,您可以立即请求新的单个位置,然后完全停止请求新位置,直到您的作业再次安排运行。如果你沿着这条路走下去,由于位置服务的异步特性,你可能会在得到结果之前遇到服务结束的问题。因此,您希望轮询以获取警报管理器中的某个位置。您可以使用CWAC LocationPoller之类的项目

该文档包含如何安排重复活动的示例: https://developer.android.com/training/scheduling/alarms.html

根据您的需要,您应该考虑一个位置可能每15分钟无法使用的事实。也许用户不在GPS / wifi /电话范围之内。因此,在你的15分钟窗口过去之后,确保你有一个合理的解决方案,或许更早或更频繁地启动任务可能有用也可能没有益处。

总而言之,这是您实际感兴趣的代码片段,用于解决您的特定问题(直接从CWAC locationpoller网站获取):

<强> 1。创建定期警报管理器

mgr=(AlarmManager)getSystemService(ALARM_SERVICE);

Intent i=new Intent(this, LocationPoller.class);

Bundle bundle = new Bundle();
LocationPollerParameter parameter = new LocationPollerParameter(bundle);
parameter.setIntentToBroadcastOnCompletion(new Intent(this, LocationReceiver.class));
// try GPS and fall back to NETWORK_PROVIDER
parameter.setProviders(new String[] {LocationManager.GPS_PROVIDER, LocationManager.NETWORK_PROVIDER});
parameter.setTimeout(60000);
i.putExtras(bundle);


pi=PendingIntent.getBroadcast(this, 0, i, 0);
mgr.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
                                    SystemClock.elapsedRealtime(),
                                    PERIOD,
                                    pi);

<强> 2。创建BroadcastReceiver以接收您的位置数据

Bundle b=intent.getExtras();

LocationPollerResult locationResult = new LocationPollerResult(b);

Location loc=locationResult.getLocation();
String msg;

if (loc==null) {
  loc=locationResult.getLastKnownLocation();

  if (loc==null) {
    msg=locationResult.getError();
  }
  else {
    msg="TIMEOUT, lastKnown="+loc.toString();
  }
}
else {
  msg=loc.toString();
}

if (msg==null) {
  msg="Invalid broadcast received!";
}

答案 1 :(得分:-1)

来自http://developer.android.com/reference/android/app/AlarmManager.html#setRepeating%28int,%20long,%20long,%20android.app.PendingIntent%29

  

从API 19开始,所有重复警报都不准确。如果您的应用程序需要精确的交付时间,那么它必须使用一次性精确警报,每次重新安排如上所述。 targetSdkVersion早于API 19的旧应用程序将继续将所有警报(包括重复警报)视为完全警报。

所以你必须做这样的事情:

public void startTheClock(int interval) {       
    Intent pingerIntent = new Intent(this, findLoc.class);
    pingerIntent.setAction("start_clock");

    PendingIntent pendingIntent = PendingIntent.getBroadcast(
         this.getApplicationContext(), 
         0,
         pingerIntent,
         PendingIntent.FLAG_CANCEL_CURRENT);
    AlarmManager alarms = (AlarmManager) this.getSystemService(
             Context.ALARM_SERVICE);

    alarms.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP,
            SystemClock.elapsedRealtime() + interval,
            pendingIntent);

}

在捕获该意图的类中(在此示例中为findLoc.java):

public class findLoc extends BroadcastReceiver{

    @Override
    public void onReceive(Context context, Intent intent) {

        callMethodThatSearchesForLocation();

        startTheClock(INTERVAL);

    }

}

其中interval是以毫秒为单位的常量。

注意:我实际上遇到了一些问题,因为它在setExact(..)上显示错误,因为我的最低SDK不支持此问题。如果您希望SDK上的相同行为低于19且高于或等于19,那么这有点悖论。