位置服务需要花费大量时间从FusedLocationApi获取粗略位置

时间:2016-08-10 13:24:00

标签: android google-play-services google-api-client google-location-services

我有这个应用程序,我需要在开始显示任何内容之前尽快获得一个粗略位置(我只请求android.permission.ACCESS_COARSE_LOCATION)(除了启动屏幕)给用户。

由于某些原因,我的代码在某些需要请求位置更新的用例中无效(如果它无法找到最后知道的位置)。

  • 如果最近禁用了位置服务并且我重新启用它们然后启动我的应用程序,则可能需要花费大量时间(或不需要)来获取位置修复,并且可能永远不会发生。在这种情况下,我通常必须禁用位置服务,并使用前景中的应用程序通知下拉列表中的快速切换按钮启用它们。而且它也不是直接的,需要几秒钟。
  • 另一个类似的情况是位置服务被禁用,我打开应用程序并且无法修复。我打开设备设置(将应用程序放在后台),重新启用位置服务并将应用程序带回前台。有时需要花很多时间来修复位置。

老实说,我很难描述通常需要花费大量时间来修复位置的用例。我已经尝试了很多东西,在前台/后台打开/关闭应用程序时不断禁用/启用位置服务。很多事情,它只是不能持续发挥作用。

鉴于我的应用程序的性质,我真的需要尽快获得一个位置修复。由于我不需要一个精确的位置(一个非常粗略的估计是好的),我不明白为什么需要这么长的时间......

很抱歉这篇长篇文章,这是我目前的代码:

// BaseActivityLifecycleCallbacks extends Application.ActivityLifecycleCallbacks with default blank methods

public class MyLocation extends BaseActivityLifecycleCallbacks implements GoogleApiClient.ConnectionCallbacks,
    GoogleApiClient.OnConnectionFailedListener, LocationListener {

    private static final int LOCATION_REQUEST_INTERVAL = 1000; // 1 second
    private static final int LOCATION_REQUEST_FASTEST_INTERVAL = 250; // 250 milliseconds

    private static final int LOCATION_REQUEST_UPDATE_TIMEOUT = 15000; // 15 seconds

    private final Handler mMainHandler;
    private final Runnable mExpiredRunnable;
    private final GoogleApiClient mGoogleApiClient;
    private final LocationRequest mLocationRequest;

    private LocationCallback mLocationCallback;

    @DebugLog
    public MyLocation(Context context) {
        mMainHandler = new Handler(Looper.getMainLooper());

        mExpiredRunnable = new Runnable() {

            @DebugLog
            @Override
            public void run() {
                handleNewOrEmptyLocation(null);
            }

        };

        MyApplication.getInstance().registerActivityLifecycleCallbacks(this);

        mGoogleApiClient = new GoogleApiClient.Builder(context)
            .addApi(LocationServices.API)
            .addConnectionCallbacks(this)
            .addOnConnectionFailedListener(this)
            .build();

        mLocationRequest = LocationRequest.create()
            .setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY)
            .setInterval(LOCATION_REQUEST_INTERVAL)
            .setFastestInterval(LOCATION_REQUEST_FASTEST_INTERVAL);
    }

    public void requestFusedLocation(@NonNull LocationCallback callback) {
        mLocationCallback = callback;

        mGoogleApiClient.connect();
    }

    @DebugLog
    @Override
    public void onActivityResumed(Activity activity) {
        super.onActivityResumed(activity);

        if (activity instanceof MainActivity) {
            if (!mGoogleApiClient.isConnected() && !mGoogleApiClient.isConnecting() && mLocationCallback != null) {
                mGoogleApiClient.connect();
            }
        }
    }

    @DebugLog
    @Override
    public void onActivityPaused(Activity activity) {
        super.onActivityPaused(activity);

        if (activity instanceof MainActivity) {
            if (mGoogleApiClient.isConnected()) {
                mMainHandler.removeCallbacks(mExpiredRunnable);

                LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, this);

                mGoogleApiClient.disconnect();
            }
        }
    }

    @DebugLog
    @Override
    // I'm handling permission request some place else...
    @SuppressWarnings("MissingPermission")
    public void onConnected(@Nullable Bundle bundle) {
        Location lastLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);

        if (lastLocation != null) {
            handleNewOrEmptyLocation(lastLocation);
            return;
        }

        // I've disabled this for testing purposes. Sometimes the current 15s timeout is not enough to get a location fix...
        //mMainHandler.postDelayed(mExpiredRunnable, LOCATION_REQUEST_UPDATE_TIMEOUT);

        LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, this);
    }

    @DebugLog
    @Override
    public void onLocationChanged(Location location) {
        mMainHandler.removeCallbacks(mExpiredRunnable);

        handleNewOrEmptyLocation(location);
    }

    @DebugLog
    @Override
    public void onConnectionSuspended(int i) {
        // TODO: Is there something that needs to be done here?
        Timber.e("onConnectionSuspended");
    }

    @DebugLog
    @Override
    public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {
        // TODO: Is there something that needs to be done here?
        Timber.e("onConnectionFailed");
    }

    @DebugLog
    private void handleNewOrEmptyLocation(Location location) {
        MyApplication.getInstance().unregisterActivityLifecycleCallbacks(this);

        mGoogleApiClient.disconnect();

        if (location != null) {
            mLocationCallback.onLocationReceived(location);
        } else {
            mLocationCallback.onEmptyLocation();
        }
    }

    public interface LocationCallback {

        void onLocationReceived(Location location);

        void onEmptyLocation();

    }

}

这就是它目前的使用方式:

public class MAinActivity extends BaseActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);

        MyLocation myLocation = new MyLocation(this);

        myLocation.requestFusedLocation(new MyLocation.LocationCallback() {

            @DebugLog
            @Override
            public void onLocationReceived(Location location) {
                Toast.makeText(MainActivity.this, String.valueOf(location), Toast.LENGTH_SHORT).show();
            }

            @DebugLog
            @Override
            public void onEmptyLocation() {
                Toast.makeText(MainActivity.this, "HUSTON, WE HAVE A PROBLEM!", Toast.LENGTH_SHORT).show();
                finish();
            }

        });
    }

}

完成并作为奖励问题...... onConnectionSuspendedonConnectionFailed在什么情况下被召唤?我应该以某种方式处理这些回调吗?

0 个答案:

没有答案