【问题标题】:How to collect location updates for later processing outside of onLocationChanged如何收集位置更新以供以后在 onLocationChanged 之外进行处理
【发布时间】:2017-03-09 11:52:42
【问题描述】:

我想收集特定时间段内的位置更新,并在最后对位置进行处理。我目前正在跟踪 onLocationChanged 方法中传递的时间。

public class LocationProvider implements
        GoogleApiClient.ConnectionCallbacks,
        GoogleApiClient.OnConnectionFailedListener,
        LocationListener {
    private static final String TAG = LocationProvider.class.getSimpleName();

    private Context mContext;

    private GoogleApiClient mGoogleApiClient;
    private LocationRequest mLocationRequest;

    private long mStartTime;
    private long mDuration;

    List<Location> locations;

    public LocationProvider(Context context) {
        mContext = context;

        GoogleApiAvailability api = GoogleApiAvailability.getInstance();
        if (api.isGooglePlayServicesAvailable(mContext) == ConnectionResult.SUCCESS) {
            mGoogleApiClient = new GoogleApiClient.Builder(mContext)
                    .addConnectionCallbacks(this)
                    .addOnConnectionFailedListener(this)
                    .addApi(LocationServices.API)
                    .build();
        } else {
            Log.e(TAG, "Could not connect to Google Play services");
        }
    }

    @Override
    public void onConnected(Bundle bundle) {
        LocationServices.FusedLocationApi.requestLocationUpdates(
                mGoogleApiClient, mLocationRequest, this);
    }

    @Override
    public void onConnectionFailed(ConnectionResult connectionResult) {
        Log.e(TAG, "onConnectionFailed: " + connectionResult.toString());
    }

    @Override
    public void onConnectionSuspended(int i) {
        Log.e(TAG, "GoogleApiClient connection has been suspended: " + String.valueOf(i));
    }

    @Override
    public void onLocationChanged(Location location) {
        locations.add(location);

        if (System.currentTimeMillis() - mStartTime > mDuration) {
            stopTracking();
            // do stuff
        }
    }

    public void startTracking(long interval, long fastInterval, long duration) {
        mDuration = duration;
        locations = new ArrayList<>();

        mLocationRequest = LocationRequest.create()
                .setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY)
                .setInterval(interval)
                .setFastestInterval(fastInterval);

        if (!mGoogleApiClient.isConnected() || !mGoogleApiClient.isConnecting()) {
            mGoogleApiClient.connect();
        }

        mStartTime = System.currentTimeMillis();
    }

    private void stopTracking() {
        if (mGoogleApiClient.isConnected()) {
            LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, this);
            mGoogleApiClient.disconnect();
        }
    }
}

但是,我想打破这个逻辑,因为我想根据我的需要对位置做不同的事情。我推断如果我创建一个新线程来注册我的位置侦听器,我可以在主线程上等待,直到位置收集完成才能使用locations 列表。

public class LocationUpdates {
    private LocationProvider mLocationProvider;
    private Looper mLooper;

    public List<Location> gatherUpdates(final Context context,
                                        final long interval,
                                        final long fastInterval,
                                        final long duration)
            throws InterruptedException {

        long startTime = System.currentTimeMillis();

        new Thread() {
            @Override
            public void run() {
                Looper.prepare();
                mLooper = Looper.myLooper();
                mLocationProvider = new LocationProvider(context);
                mLocationProvider.startTracking(interval, fastInterval, duration);
                Looper.loop();
            }
        }.start();

        while (System.currentTimeMillis() - startTime < duration) {

        }

        mLooper.quit();
        mLooper.getThread().join();

        return mLocationProvider.locations;
    }
}

相反,我观察到的是(间隔 3 秒,持续时间 10 秒):

  • 到达mLocationProvider.startTracking(interval, fastInterval, duration);
  • gatherUpdates 在多长时间后返回
  • onLocationChanged 现在才第一次调用

因此,即使位置侦听器已注册,也有明显的东西阻止它接收更新。我不明白为什么我的逻辑没有按照我的预期去做。

有没有办法,即使没有线程,也可以在收集完成后收集一堆位置更新并在onLocationChanged 之外使用它们?

【问题讨论】:

  • 如果反对者可以指出这个问题缺少什么,我可能会解决它。我仍然对这个问题的答案很感兴趣。

标签: android multithreading android-gps on-location-changed


【解决方案1】:

您可以使用IntentBroadcastReceiver 构建您的位置更新请求。然后在位置对象的时间超过您的持续时间时删除更新。

int requestCode = 1;
Intent intent = new Intent(this, LocationReceiver.class); // Request updates to Receiver
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, requestCode, intent, PendingIntent.FLAG_CANCEL_CURRENT);
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, pendingIntent);

在您的广播接收器中:

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

    if(LocationResult.hasResult(intent)){
        LocationResult locResult = LocationResult.extractResult(intent);
        Location location = locResult.getLocations().get(0);
        // Check the location's time and maybe stop location updates
    }
}

【讨论】:

  • 恐怕这似乎对我没有帮助。您所展示的只是如何将我的位置更新传递给 BroadcastReceiver,而我已经可以使用 LocationListener 做到这一点。我的问题是我有一个方法可以做一些事情,然后需要在特定的时间内获取一些位置数据,一旦完成,检索结果并继续其业务。问题是如何让该方法等待而不阻塞更新。
  • @Reti43 我建议使用 BroadcastReceiver,因为它们以及 IntentServices 可以在您的应用程序不在前台的情况下处理位置 Intent。我想说的是,您可以从流程完成的任何地方请求更新,将位置的值存储在数据库中,检查每次更新的时间以查看它是否符合您的标准,如果不符合,您可以停止存储数据,根据需要删除更新,并处理存储的数据。我不会通过调用等待来接近它。我会让一项任务进行定位前处理,另一项进行定位后处理。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-07-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多