ユーザーに何か (スプラッシュ画面以外) を表示し始める前に、できるだけ早く単一の大まかな場所 (私は を要求しているだけです) を取得する必要があるこのアプリがあります。android.permission.ACCESS_COARSE_LOCATION
何らかの理由で、場所の更新を要求する必要がある一部のユースケースでコードが機能していません (最後の既知の場所が見つからない場合)。
- 位置情報サービスが最近無効になっていて、再度有効にしてからアプリを起動した場合、位置情報を修正するのに時間がかかる (またはかからない) 可能性があり、それが起こらない可能性があります。この状況では、通常、位置情報サービスを無効にし、アプリをフォアグラウンドにして通知ドロップダウンからクイック スイッチ ボタンを使用して再度有効にする必要があります。また、即時ではなく、数秒かかります。
- もう 1 つの同様のケースは、位置情報サービスが無効になっている場合です。アプリを開いて修正できません。デバイス設定を開き (アプリをバックグラウンドに配置)、位置情報サービスを再度有効にして、アプリをフォアグラウンドに戻します。場所の修正に時間がかかる場合があります。
正直なところ、現場で修正するのに通常多くの時間がかかるユースケースを説明するのは複雑です. フォアグラウンド/バックグラウンドでアプリを開いたり閉じたりして、位置情報サービスを常に無効/有効にして、多くのことを試しました。多くの場合、一貫して機能しません。
また、私のアプリの性質上、1 つの場所をできるだけ早く修正する必要があります。正確な場所は必要ないので (大まかな見積もりで結構です)、なぜそんなに時間がかかるのかわかりません...
長い投稿で申し訳ありませんが、現在のコードは次のとおりです。
// 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
呼び出されますか? これらのコールバックを何らかの方法で処理する必要がありますか?