1

目标:在服务中精确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

    }

}

定位服务

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。

我已经参考了这个代码

谢谢。

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

活动中的代码

    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);
  • 我删除了位置服务类并添加了位置接收器

位置接收器

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");
    }
}
4

2 回答 2

1

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

如果您坚持每 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!";
}
于 2014-08-25T11:55:26.067 回答
-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 不支持这个。如果您希望在低于 19 且高于或等于 19 的 SDK 上具有相同的行为,这有点自相矛盾。

于 2014-08-25T12:06:08.857 回答