Android:从最佳可用提供商处获取当前位置

AP2*_*257 19 android

我有一些Android代码,需要从GPS,网络或任何可用的地方快速获得最佳可用位置.准确性不如速度重要.

获得最佳可用位置肯定是一项非常标准的任务.然而,我找不到任何代码来证明它.Android位置代码要求您指定条件,注册更新和等待 - 如果您有详细的标准并且不介意等待,这很好.

但我的应用程序需要更多地工作,就像地图应用程序第一次找到你时 - 从任何可用的提供程序工作,只需检查位置是不是过时或过时.

我试图推出自己的代码来做到这一点,但我遇到了问题.(它在IntentService内部发生上传,如果这有任何区别.我已经包含了所有信息代码.)这段代码出了什么问题?

@Override
protected void onHandleIntent(Intent arg0) {
    testProviders();
    doUpload();
}
private boolean doUpload() {
       int j = 0;
       // check if we have accurate location data yet - wait up to 30 seconds
       while (j < 30) {
           if ((latString == "") || (lonString == "")) {
               Log.d(LOG_TAG, "latlng null");
               Thread.sleep(1000);
               j++;
       } else {
                Log.d(LOG_TAG, "found lat " + latString + " and lon " + lonString);
            break;
       }
       //do the upload here anyway, with or without location data
       //[code removed for brevity]
}
public boolean testProviders() {
    Log.e(LOG_TAG, "testProviders");
    String location_context = Context.LOCATION_SERVICE;
    locationmanager = (LocationManager) getSystemService(location_context);
    List<String> providers = locationmanager.getProviders(true);
    for (String provider : providers) {
        Log.e(LOG_TAG, "registering provider " + provider);
        listener = new LocationListener() {
            public void onLocationChanged(Location location) {
                // keep checking the location - until we have
                // what we need
                //if (!checkLoc(location)) {
                Log.e(LOG_TAG, "onLocationChanged");
                locationDetermined = checkLoc(location);
                //}
            }
            public void onProviderDisabled(String provider) {
            }
            public void onProviderEnabled(String provider) {
            }
            public void onStatusChanged(String provider, int status,
                    Bundle extras) {
            }
        };
        locationmanager.requestLocationUpdates(provider, 0,
                0, listener);
    }
    Log.e(LOG_TAG, "getting updates");
    return true;
}
private boolean checkLoc(Location location) {
    float tempAccuracy = location.getAccuracy();
    int locAccuracy = (int) tempAccuracy;
    Log.d(LOG_TAG, "locAccuracy = " + locAccuracy);
    if ((locAccuracy != 0) && (locAccuracy < LOCATION_ACCURACY)) {
        latitude = location.getLatitude();
        longitude = location.getLongitude();
        latString = latitude.toString();
        lonString = longitude.toString();
        return true;
    }
    return false;
}
public void removeListeners() {
    // Log.e(LOG_TAG, "removeListeners");
    if ((locationmanager != null) && (listener != null)) {
        locationmanager.removeUpdates(listener);
    }
    locationmanager = null;
    // Log.d(LOG_TAG, "Removed " + listener.toString());
}
@Override
public void onDestroy() {
    super.onDestroy();
    removeListeners();
}
Run Code Online (Sandbox Code Playgroud)

不幸的是,这找到了网络提供商,但只输出了latlng null30次 - 它似乎永远不会得到一个位置.我甚至都没有得到日志声明locationChanged.

这很有趣,因为从ddms我可以看到输出如下:

NetworkLocationProvider: onCellLocationChanged [305,8580]
NetworkLocationProvider: getNetworkLocation(): returning cache location with accuracy 75.0
Run Code Online (Sandbox Code Playgroud)

似乎暗示网络提供商确实有一些位置信息,我只是没有得到它.

有人可以帮忙吗?我认为工作示例代码对于Android/StackOverflow社区来说是一个有用的资源.

jop*_*hde 6

你肯定是在努力做到这一点.以下是我正在开发的新应用程序的一些片段.它使用Criteria使所有提供商能够在不付出任何成本的情况下返回精确的准确度.

如果未启用任何提供程序,则会显示一个对话框,提示用户打开其位置设置.如果用户点击确定,则实际触发了Intent,将其发送到手机上的设置.如果启用了提供程序,则应用程序将从任何已启用的提供程序中获取最近的最后一个已知位置.对于我的应用程序,我只需要知道用户所处的一般区域,并且最后一个已知位置可能来自他们的家庭区域.

如果启用了提供程序,则循环还会尽快请求位置更新.这对我的应用程序来说是理想的,但您可以通过修改requestLocationUpdates方法的参数来更改此节省电池.

此代码所具有的优化是Android应用程序上的示例未真正显示的是所有已启用的提供程序是同时启动的.所有提供程序都将返回onLocationChanged方法的单独更新.在我的应用程序中,我删除位置监听器后,其中一个提供程序返回一个具有足够精确的位置.

开始位置更新:

void getCurrentLocation() {
    List<String> providers = locationManager.getProviders(criteria, true);
    if (providers != null) {
        Location newestLocation = null;
        for (String provider : providers) {
            Location location = locationManager.getLastKnownLocation(provider);
            if (location != null) {
                if (newestLocation == null) {
                    newestLocation = location;
                } else {
                    if (location.getTime() > newestLocation.getTime()) {
                        newestLocation = location;
                    }
                }
                locationManager.requestLocationUpdates(provider, 0, 0, this);
            }
        }
    } else {
        LocationDialogFragment dialog = new LocationDialogFragment();
        dialog.show(getSupportFragmentManager(),
            LocationDialogFragment.class.getName());
    }
}
Run Code Online (Sandbox Code Playgroud)

接收位置更新:

@Override
public void onLocationChanged(Location location) {
    float bestAccuracy = -1f;
    if (location.getAccuracy() != 0.0f
        && (location.getAccuracy() < bestAccuracy) || bestAccuracy == -1f) {
        if (location.getAccuracy() < Const.MIN_ACCURACY) {
            locationManager.removeUpdates(this);
        }
    }
    bestAccuracy = location.getAccuracy();
}
Run Code Online (Sandbox Code Playgroud)

位置设置对话框:

public class LocationDialogFragment extends DialogFragment {

    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
        builder.setMessage(R.string.location_dialog_message)
                .setPositiveButton(R.string.location_dialog_positive_button,
                    new OnClickListener() {

                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            Intent settingsIntent = new Intent(
                                    Settings.ACTION_LOCATION_SOURCE_SETTINGS);
                            startActivity(settingsIntent);
                        }
                    })
                .setNegativeButton(R.string.location_dialog_negative_button,
                    new OnClickListener() {

                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            Toast.makeText(getActivity(),
                                R.string.no_location_message, Toast.LENGTH_LONG)
                                    .show();
                        }
                    });
        return builder.create();
    }
}
Run Code Online (Sandbox Code Playgroud)


Com*_*are 5

Thread.sleep()在生产代码是一个严重的代码味道恕我直言.如果你发现你必须这样做,你可能正在做一些不应该那样工作的事情.在这种情况下,我认为这是您问题的根源 - 您不会让Android返回处理此线程的消息队列以分派它找到的任何位置更新.我怀疑一个IntentService不适合你的场景.