web-dev-qa-db-ja.com

融合ロケーションプロバイダーはGPS受信機を使用していないようです

Moto GのAndroid 4.3、Nexus 7 2012のAndroid 4.4.2、Nexus 5のAndroid 4.4.2 Android Studio 0.4。

定期的な位置情報の更新を受け取りたくありません。ユーザーがボタンを押したときに正確な位置情報が欲しいだけです。

私はこの例に従いました: https://developer.Android.com/training/location/retrieve-current.html

マニフェストファイル内:

<uses-permission Android:name="Android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission Android:name="Android.permission.ACCESS_FINE_LOCATION" />

GooglePlayServicesUtil.isGooglePlayServicesAvailableを使用してPlayサービスが利用可能であることを確認します

主なアクティビティ:

//in activity onCreate method
mLocationClient = new LocationClient(this, this, this);

@Override
protected void onStart() {
    mLocationClient.connect();
    super.onStart();
}

@Override
protected void onStop() {
    mLocationClient.disconnect();
    super.onStop();
}

//in button onclick method    
mCurrentLocation = mLocationClient.getLastLocation();

SIMカードがありません。 Wifiを有効にすると、正確な場所が取得されることがあります。その他の場合、mCurrentLocationはnullです。

Wifiを無効にすると、mCurrentLocationは常にnullになります。

私は常にいくつかの場所で外をテストし、常に空をはっきりと見ています。私はそれぞれの場所で3分間待ちました。

画面上部のAndroid通知バーにGPSアイコンが表示されません。

これらの場所の設定があります: enter image description here

GPSテストアプリは、Wi-Fiが無効になっている同じデバイスで屋内でGPSを正常に使用するため、GPSが機能します。 enter image description here

https://developer.Android.com/training/location/receive-location-updates.html のように、位置情報の更新の登録も機能しません。登録されたメソッドは呼び出されません。

私は何を間違えていますか?

38
cja

解決しました。問題は、「Googleアプリがあなたの場所にアクセスできるようにする」がオフになっていたことです。 enter image description here

オンにするとGPSの読み取り値が表示され、オフにすると表示されません。

次の2つの理由で中断しました。

  1. 会社の多くのデバイスに使用するアプリを開発していますが、最小限の手動構成が必要です

  2. 画面には、「この設定はGoogleアプリのみに影響します」と明確に表示されます。 Play ServicesはGoogleのソフトウェアであることは知っていますが、Googleがエンドユーザーにそれを理解してくれると期待しているとは思いませんでした。

その後、Android 4.4.2アップデートと位置設定ページが変更されました。GoogleLocation Reportingをオフにしても、融合された位置プロバイダーからGPSの読み取り値を取得できるようです。 enter image description here

そのため、Googleはこの設定が混乱を招き、改善されていることに気付いたのかもしれません。いずれにせよ、数日前に4.4.2があれば、時間を大幅に節約できたでしょう。

16
cja

キャッシュされた場所を使用するため、問題はgetLastLocation()にあります。この単純なアプローチを使用しようとしたのと同じ問題がありました。以来、私はアップデートのリッスンに切り替えました(そして、最初のアップデートが成功すると自動的に停止します)。

これは私のコードです。

最初に、アプリケーションの可用性の確認(必須ではありません。アクティビティを実行し、結果を保持することはできません):

_public class MainApp extends Application {
  public static enum PlayServices {
    NOT_CHECKED, AVAILABLE, UNAVAILABLE
  };
  public static PlayServices mPlayServices = PlayServices.NOT_CHECKED;

  @Override
  public void onCreate() {
    super.onCreate();

    if (GooglePlayServicesUtil.isGooglePlayServicesAvailable(this) == ConnectionResult.SUCCESS) {
      MainApp.mPlayServices = MainApp.PlayServices.AVAILABLE;
    }
  }
}
_

次に、アクティビティに進みます。

_public class MainActivity extends SherlockFragmentActivity implements
  GooglePlayServicesClient.ConnectionCallbacks,
  GooglePlayServicesClient.OnConnectionFailedListener, LocationListener {
_

onCreate()

_if (MainApp.mPlayServices != MainApp.PlayServices.UNAVAILABLE) {
  mLocationClient = new LocationClient(this, this, this);

  mLocationRequest = LocationRequest.create();
  mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
  mLocationRequest.setInterval(5000);
  mLocationRequest.setNumUpdates(1);
  mLocationRequest.setFastestInterval(1000);

  mUpdatesRequested = false;
  MainApp.prefs.edit().putBoolean(MainApp.KEY_LOCATION_UPDATES_REQUESTED, mUpdatesRequested)
      .commit();
}
_

残りのMainActivityクラス:

_@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
  Log.d(this.getClass().getSimpleName(), "onActivityResult(" + requestCode + ", " + resultCode
      + ")");
  // Decide what to do based on the original request code
  switch (requestCode) {
    case MainApp.PLAY_CONNECTION_FAILURE_RESOLUTION_REQUEST:
      /*
       * If the result code is Activity.RESULT_OK, try
       * to connect again
       */
      switch (resultCode) {
        case Activity.RESULT_OK:
          // here we want to initiate location requests!
          mLocationClient = new LocationClient(this, this, this);

          break;
      }
      break;
  }
}

@Override
public void onConnected(Bundle dataBundle) {
  Log.d(this.getClass().getSimpleName(), "onConnected()");

  Log.d(this.getClass().getSimpleName(), "Google Play Services are available.");
  MainApp.mPlayServices = MainApp.PlayServices.AVAILABLE;

  if (!mUpdatesRequested) {

    LocationManager lm = (LocationManager) getSystemService(Context.LOCATION_SERVICE);

    boolean gps_enabled = false;
    try {
      gps_enabled = lm.isProviderEnabled(LocationManager.GPS_PROVIDER);
    } catch (Exception ex) {
    }

    boolean network_enabled = false;
    try {
      network_enabled = lm.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
    } catch (Exception ex) {
    }

    // don't start listeners if no provider is enabled
    MainApp.locEnabled = gps_enabled || network_enabled;

    if (!MainApp.locEnabled) {
      // we have access to PlayServices, but user has disabled location visibility --> alert him
      alertLocationOff();
    } else {
      mLocationClient.requestLocationUpdates(mLocationRequest, this);
      mUpdatesRequested = true;
    }
  }
}

@Override
public void onDisconnected() {
  Log.d(this.getClass().getSimpleName(), "onDisconnected()");
}

@Override
public void onConnectionFailed(ConnectionResult connectionResult) {
  Log.d(this.getClass().getSimpleName(), "onConnectionFailed()");

  Log.d(this.getClass().getSimpleName(), "Google Play Services not available.");
  MainApp.mPlayServices = MainApp.PlayServices.UNAVAILABLE;

  /*
   * Google Play services can resolve some errors it detects.
   * If the error has a resolution, try sending an Intent to
   * start a Google Play services activity that can resolve
   * error.
   */
  if (connectionResult.hasResolution()) {
    try {
      // Start an Activity that tries to resolve the error
      connectionResult.startResolutionForResult(this,
          MainApp.PLAY_CONNECTION_FAILURE_RESOLUTION_REQUEST);
      /*
       * Thrown if Google Play services canceled the original
       * PendingIntent
       */
    } catch (IntentSender.SendIntentException e) {
      // Log the error
      e.printStackTrace();
    }
  } else {
    /*
     * If no resolution is available, display a dialog to the
     * user with the error.
     */
    GooglePlayServicesUtil.getErrorDialog(connectionResult.getErrorCode(), this, 0).show();
  }
}

@SuppressLint("NewApi")
@Override
public void onLocationChanged(Location location) {
  Log.d(this.getClass().getSimpleName(), "onLocationChanged(), location=" + location);

  if (location != null) {
    boolean present = true;
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Gingerbread) {
      present = Geocoder.isPresent();
    }

    if (present) {
      (new ExtractLocationTask(this)).execute(location);
    } else {
      Log.e(this.getClass().getSimpleName(), "Geocoder not present");
      MainApp.mPlayServices = MainApp.PlayServices.UNAVAILABLE;
    }
  }
}


private class ExtractLocationTask extends AsyncTask<Location, Void, Boolean> {
  Context mContext;

  public ExtractLocationTask(Context context) {
    super();
    mContext = context;
  }

  @Override
  protected Boolean doInBackground(Location... params) {
    Log.d(getClass().getSimpleName(), "ExtractLocationTask.onPreExecute()");

    boolean found = false;
    try {
      Geocoder geoCoder_local = new Geocoder(mContext, Locale.getDefault());
      Geocoder geoCoder_en = new Geocoder(mContext, Locale.ENGLISH);

      List<Address> addresses_local = geoCoder_local.getFromLocation(params[0].getLatitude(),
          params[0].getLongitude(), 10);
      List<Address> addresses_en = geoCoder_en.getFromLocation(params[0].getLatitude(),
          params[0].getLongitude(), 10);

      if (addresses_local != null && addresses_local.size() > 0) {

        // do what you want with location info here

        // based on mLocationRequest.setNumUpdates(1), no need to call
        // removeLocationUpdates()

        MainApp.locEnabled = true;

        mUpdatesRequested = false;
        MainApp.prefs.edit()
            .putBoolean(MainApp.KEY_LOCATION_UPDATES_REQUESTED, mUpdatesRequested).commit();

        found = true;
      }
    } catch (IOException e) {
      Log.e(this.getClass().getSimpleName(), "Exception: ", e);
    }

    return found;
  }

  @Override
  protected void onPostExecute(Boolean found) {
    Log.d(getClass().getSimpleName(), "ExtractLocationTask.onPostExecute()");

    if (found) {
      // update UI etc.
    } else if (!mUpdatesReRequested) {
      mLocationClient.requestLocationUpdates(mLocationRequest, (LocationListener) mContext);
      mUpdatesRequested = true;
      mUpdatesReRequested = true;
    }
  }
}
_

これが機能するのに役立つことを願っています!

15
Saran

一部のクライアントが高精度の位置情報を要求する(サブスクライブする)まで、位置情報プロバイダーはGPSをウェイクアップしません(他のユーザーからの例で説明されています)。 GPSテストアプリは、場所プロバイダーを使用しませんが、場所を取得する古い「直接」方法を使用します。

また、有効期限切れのメカニズムもあります。これは、古いと思われる場合、しばらくして最後の場所に関する情報を削除します。

上記のすべてをまとめると、LP(Location Provider)があなたに与えるものが何もないことは本当にあり得ます。

4
Andrew

私はあなたが屋内でアプリケーションをテストしていると思う、それは動作しません..

とコードフロー..

public void setUpLocationClientIfNeeded() {
        createLocReq();
        if (mLocationClient == null) {
            mLocationClient = new LocationClient(getApplicationContext(), this, // ConnectionCallbacks
                    this); // OnConnectionFailedListener
        }
    }

    private void createLocReq() {
        if (mLocationRequest == null) {
            // Create a new global location parameters object
            mLocationRequest = LocationRequest.create();
            // Set the update interval
            mLocationRequest.setInterval(LocationServices.UPDATE_INTERVAL_IN_MILLISECONDS);
            // Use high accuracy
            mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
            // Set the interval ceiling to one minute
            mLocationRequest.setFastestInterval(LocationServices.FAST_INTERVAL_CEILING_IN_MILLISECONDS);

            mLocationClient = new LocationClient(getApplicationContext(), this, this);
            mLocationClient.connect();
        }
    }

    public void updateLocation(Location location) {
        if (lastTrackedLat == 0.0) {
            lastTrackedLat = location.getLatitude();
        }
        if (lastTrackedLng == 0.0) {
            lastTrackedLng = location.getLongitude();
        }

        currentLat = location.getLatitude();
        currentLng = location.getLongitude();
    }

    @Override
    public void onLocationChanged(Location location) {
        if (location != null) {
            this.location = location;
            updateLocation(location);
        }
    }

    public Location getLocation() {
        // mLocationClient.getLastLocation();
        return location;
    }
2
vinay Maneti

ドキュメントによると

このメソッドは、位置を取得する簡単な方法を提供します。 正確な位置情報を必要としないアプリケーションに特に適していますおよび位置情報更新のための追加のロジックを維持したくない場合。

そのため、非常に正確な位置を返す場合と返さない場合があります。

GPSはロックに時間がかかることがあるため、getLastLocationを呼び出すと位置が返される場合と返されない場合があります。

位置情報の更新を要求した後、位置情報を取得した後に位置情報の更新の要求を停止することをお勧めします。

また、提供されたコードを見て、位置を取得しようとする前にLocationClientが接続するのを待っていますか?まだ場所を取得するために接続されていないため、それは確かにあなたにヌルの場所を与えます。

あなたがすべきことはあなたのonConnectedにあり、そこに最後の場所を取得します、例

public void onConnected(Bundle connectionHint) {
    Location location = mLocationClient.getLastLocation();
}

その例で言うように、onConnectedはCalled by Location Services when the request to connect the client finishes successfully. At this point, you can request the current location or start periodic updates

1
tyczj

あなたがする必要があるのは、このようなリクエストオブジェクトにpriorityプロパティを追加することです。

public void onConnected(Bundle arg0)
{
    locationrequest = LocationRequest.create();
    locationrequest.setInterval(1000);
    locationrequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
    locationclient.requestLocationUpdates(locationrequest, this);
}

おそらく、ブール変数を使用して、ユーザーにGPSを強制するオプションを持たせることができます

boolean forceGPS=false;
.
.
.//make the user choose to change the value of the boolean
.
.
public void onConnected(Bundle arg0)
    {
        locationrequest = LocationRequest.create();
        locationrequest.setInterval(1000);
        if(forceGPS==true)
        {
        locationrequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
        }
        locationclient.requestLocationUpdates(locationrequest, this);
    }
1
Sujal Mandal

OnConnectedメソッドには何が含まれていますか?

このメソッドでは、LocationRequestオブジェクトをPRIORITY_HIGH_ACCURACY優先度で作成する必要があります。

@Override
public void onConnected(Bundle dataBundle) {
    mLocationRequest = LocationRequest.create();
    mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
    mLocationClient.requestLocationUpdates(mLocationRequest, fusedListener);
}
1
dan_flo10

Simカードがなければ、coarse location providerは、GoogleによってマップされたWiFiネットワークを見つけることができない限り、大まかな位置を知る方法がありません。

最後の既知の場所を要求すると、場所が古くなる可能性があり、それ自体は役に立たない。これは、あるアプリが位置情報の更新を最後に要求したときに記録された位置だと思います。

次のコードを使用して、最近の場所を取得します。

    Criteria criteria = new Criteria();
    criteria.setAccuracy(Criteria.ACCURACY_COARSE);
    criteria.setAltitudeRequired(false);
    criteria.setSpeedRequired(false);
    criteria.setBearingRequired(false);
    criteria.setCostAllowed(false);

    final LocationManager manager = (LocationManager)getSystemService(Context.LOCATION_SERVICE);

    ....
    LocationListener listener = new LocationListener() {
        @Override
        public void onLocationChanged(Location lastKnownLocation) {
                     ....
        }
        // rest of interface
     }


     manager.requestSingleUpdate(criteria, listener, null);

最後の呼び出しは、前に未知の時間を見つけることができた場所ではなく、currentの場所を要求することを保証します。

GPSを起動するために、Criteria.ACCURACY_FINEに変更してみてください。 GPSがかなり修正されていない場合でも、実際に修正できるようになるまでに数分以上かかる場合があることに注意してください。それまでの間、修正待ちのGPSアイコンが表示されることを期待しています。

1
M. le Rutte

このリンクを誰も共有していないため、これが最も役立つドキュメントであることがわかりました http://developer.Android.com/guide/topics/location/strategies.html

「最新の位置修正が最も正確であると期待するかもしれません。ただし、位置修正の精度はさまざまであるため、最新の修正は常に最良とは限りません。いくつかの基準に基づいて位置修正を選択するロジックを含める必要があります。基準は、アプリケーションの使用例とフィールドテストによっても異なります。」

最善の策は、アクティビティがフォアグラウンドにある限りロケーションリスナを維持し、ボタンが押されたときに最も正確なキャッシュされたロケーションを選択することです。スピナーなどを表示し、正確な測定値が表示されるまでボタンを無効にする必要がある場合があります。

0
Eric Woodruff

これを試して:

public final static int MINACCURACY = 50;

private LocationManager lm;
private LocationListener listener;

private void foundLoc(double x, double y) {
    // do something with x,y
    Log.v("DEBUG", x + "," + y);
}


public void findMe(View v) {
    lm = (LocationManager) getSystemService(LOCATION_SERVICE);
    listener = new LocationListener() {
        @Override
        public void onLocationChanged(Location location) {
            if(location.getAccuracy() < MINACCURACY) {
                foundLoc(location.getLatitude(), location.getLongitude());
                lm.removeUpdates(listener);
            }
        }

        @Override
        public void onStatusChanged(String provider, int status, Bundle extras) {
        }

        @Override
        public void onProviderEnabled(String provider) {
        }

        @Override
        public void onProviderDisabled(String provider) {
        }
    };
    lm.requestLocationUpdates(LocationManager.GPS_PROVIDER, 100, 0, listener);
}

MINACCURACYはメートル単位です。この方法では、ボタンを押すと(findMeメソッドを呼び出します)、GPSが有効になり、位置が最小限の精度で検出され、foundLocメソッドがデータを取得し、リスナーが終了します(GPSが無効になります)。

0
c0m3tx

ここでは、nullを取得する場合と場所を取得する場合があります。

まず、LocationClientメソッドでonClickの新しいインスタンスを作成しています。これは、connect()onStart()を呼び出しているインスタンスとは異なります]。これにより、クライアントがLocationClient.getLastLocation()から結果を返す前に接続するのに十分な時間がある場合とそうでない場合がある予測不可能な動作が作成されます。

次に、LocationClient.getLastLocation()への呼び出しでLocationClient.isConnected()への呼び出しを保護する必要があります。 LocationClient.isConnected()ドキュメントで次のように書かれています: https://developer.Android.com/reference/com/google/Android/gms/location/LocationClient.html#isConnected()

他のメソッドへのリクエストが成功するように、クライアントが現在サービスに接続されているかどうかを確認します。アプリケーションは、このメソッドの呼び出しでユーザーが引き起こしたクライアントアクションを保護する必要があります。

ユーザーはボタンをタップしてonClick()コードをトリガーするため、最後の場所を取得する前にこのメソッドを呼び出す必要があります。

したがって、コードは次のようになります。

LocationClient mLocationClient;
Location mCurrentLocation;

@Override
protected void onCreate() {
    ...
    mLocationClient = new LocationClient(this, this, this);
    ...
}

@Override
protected void onStart() {
    mLocationClient.connect();
    super.onStart();
}

@Override
protected void onStop() {
    mLocationClient.disconnect();
    super.onStop();
}

public void onClick(View v) {
    ...
    if (mLocationClient.isConnected()) {
        // You should get a valid location here
        mCurrentLocation = mLocationClient.getLastLocation();
    }
}

これにより、LocationClientに接続するのに十分な時間が与えられ、有効な場所が提供されます。これには、GPSデータが含まれていることが望まれます。

0
Sean Barbeau

現在のほぼ正確な位置を取得するには、LocationListenerを実装するサービスを使用することを好みます。私は通常、次の手順を実行します。

  1. onCreate()GPS_PROVIDERNETWORK_PROVIDERの両方に対してLocationManagerを初期化し、requestLocationUpdatesを呼び出します
  2. GPS_PROVIDERNETWORK_PROVIDERの両方に対してgetLastKnownLocationを呼び出し、getTime()を使用して最後の新しい場所を確認します。
  3. 最後の場所をブロードキャストする(30秒未満の場合)(オプション)
  4. その間、onLocationChangedが呼び出されると、新しく更新された場所と最後の最適な場所(ある場合)とを比較し、精度レベルを確認します。
  5. 精度のデルタ<MIN_ACCURACY(ユーザー変数)の場合、それを最適な場所として使用します
  6. 現在の最適な場所をブロードキャストする
  7. LocationManager locationManager.removeUpdates(this);を削除する必要があります
  8. StopSelf()を呼び出します。 (アクティビティのonDestroyからサービスを停止することもできます)

編集:

OK ... AboveメソッドはLocation APIを使用していましたが、以下ではFused Provider(GooglePlayServices)を使用してコーディングしています。 Nexus 5(Android 4.4.2)、SIMなし、WIFIなしでテストしました...結果が得られました。

編集2:Android 2.3.3 LG Optimus(SIMとWifiなし)でテストしました。ロックを取得するには約5分かかりました(Fusedを使用して提供)、しかし、私は即座に位置アイコンを得ていました。

public class HomeActivity extends FragmentActivity implements
        ActionBar.OnNavigationListener,
        GooglePlayServicesClient.ConnectionCallbacks,
        GooglePlayServicesClient.OnConnectionFailedListener, LocationListener {

    private LocationClient locationClient;
    private LocationRequest locationRequest;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_home);
            // ...
            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 onConnected(Bundle connectionHint) {
        if (locationClient != null && locationClient.isConnected()) {

            locationRequest = LocationRequest.create();
            locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
            locationRequest.setInterval(100);
            locationClient.requestLocationUpdates(locationRequest, this);

        }
    }

    @Override
    public void onLocationChanged(Location location) {

        try {
            if (location != null) {
                LatLng gps = new LatLng(location.getLatitude(), location.getLongitude());
                Log.v("JD", "My Location: " + gps.toString());
            }
        } catch (Exception e) {
            Log.d("JD",
                    "onLocationChanged", e);

        }       
    }
}
0
Tamal