Moto G 上的 Android 4.3、Nexus 7 2012 上的 Android 4.4.2、Nexus 5 上的 Android 4.4.2。安卓工作室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 为空。

如果我禁用 Wifi,则 mCurrentLocation 始终为 null。

我在室外的几个地点进行测试,天空视野始终清晰。我在每个地点等了三分钟。

我从未在屏幕顶部的 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, ,也不行。注册的方法从未被调用。

我究竟做错了什么?

有帮助吗?

解决方案

我解决了它。问题是“让谷歌应用程序访问您的位置”已关闭:

当我打开它时,我得到gps读数,当它关闭时,我没有。

我已经离开了两个原因:

  1. 我正在开发一个应用程序,用于公司的大量设备,我希望最小的手动配置是必要的

  2. 屏幕清楚地说:“此设置仅影响Google Apps。”我知道播放服务是谷歌软件,但我不认为谷歌会期望最终用户了解这一点。

  3. 然后我收到了Android 4.4.2更新,位置设置页面已更改。看来我可以让谷歌位置报告关闭,仍然从融合位置提供商获取GPS读数:

    所以也许谷歌意识到该设置令人困惑和改进。无论哪种方式,如果我在几天前有4.4.2点,我会救了很多时间。

其他提示

问题是具有getLastLocation(),因为它使用缓存的位置。我有同样的问题,因为我也试图使用这种简单的方法。因为,我已经切换到倾听更新(并在第1次成功后停止自动更新)。

这是我的代码。

首先,检查应用程序中的可用性(不是必需的,可以在活动中且不保持结果):

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();
}
.

生成的其余内测码类:

@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;
    }
  }
}
.

我希望这将有助于您完成工作!

位置提供商不会唤醒GPS,直到一些客户端(订阅)用于高精度位置(如其他用户给出的示例中所述)。 GPS测试应用程序不使用位置提供程序,但使用旧的“直接”获取位置的方式。

也有到期机制,如果据信陈旧,则会在一段时间后去除关于最后一个位置的信息。

在上面的全部总结它真的可能是LP(位置提供商)没有什么可以给您的。

我认为你正在在室内测试你的应用程序,它不起作用..

和代码流。

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;
    }
.

根据文档

此方法提供了一种可获取位置的简化方法。它特别适用于不需要准确的位置的应用程序,并且不希望为位置更新维护额外的逻辑。

所以它可能会或可能不会返回高度准确的位置。

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

您需要做的只是将优先级属性添加到这样的请求对象。

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);
    }
.

没有SIM卡的情况下 coarse location provider 没有办法知道粗略位置,除非能够找到谷歌映射的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);

最后一次调用确保我们请求 当前的 位置,而不是它之前未知时间找到的位置。

您可以尝试将其更改为 Criteria.ACCURACY_FINE 为了启动 GPS。请注意,如果 GPS 很长一段时间没有修复,则可能需要几分钟以上才能真正修复。我预计您会同时看到 GPS 图标,表明它正在等待修复。

里面有什么 OnConnected 方法?

在此方法中,您应该创建 LocationRequest 对象与 PRIORITY_HIGH_ACCURACY 优先事项。

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

试试:

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)。

这里发生的两件事有时会导致你 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 数据。

因为没有人共享这个链接,我发现这是最有用的文档 http://developer.android.com/guide/topics/location/strategies.html

“您可能希望最近的位置修复是最准确的。但是,由于位置修复的准确性变化,最新的修复并不总是最好的。您应该包括基于几个选择位置修复的逻辑标准。标准也取决于应用和现场测试的使用情况。“

您的最佳选择是为了保持位置侦听器,只要活动位于前台,按下按钮时选择最精确的缓存位置。您可能需要显示旋转器或其他东西,并在等待准确测量以显示时禁用按钮。

我更喜欢使用实现的服务 LocationListener 获得当前接近准确的位置。我通常采取以下步骤:

  1. 初始化 LocationManager 并打电话 requestLocationUpdates 对彼此而言 GPS_PROVIDERNETWORK_PROVIDERonCreate()
  2. 称呼 getLastKnownLocation 对彼此而言 GPS_PROVIDERNETWORK_PROVIDER 并使用 getTime() 了解最后一个较新的位置。
  3. 广播最后一个位置(如果是 <30 秒)(可选)
  4. 与此同时,当 onLocationChanged 称为“我将新更新的位置与最后的最佳位置(如果有)进行比较并检查准确性级别”。
  5. 如果精度增量 < MIN_ACCURACY(用户变量),则将其用作最佳位置
  6. 广播当前最佳位置
  7. 必须删除位置管理器 locationManager.removeUpdates(this);
  8. 调用 stopSelf();(您也可以从活动的服务停止 onDestroy)

编辑:

好的...上面的方法使用 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);

        }       
    }
}
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top