2

我有这个应用程序,在开始向用户显示任何内容(除了启动屏幕)之前,我需要尽快获得一个粗略的位置(我只请求)。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();
            }

        });
    }

}

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

4

0 回答 0