【问题标题】:Android locationManager requestLocationUpdates doesn't workAndroid locationManager requestLocationUpdates 不起作用
【发布时间】:2017-01-14 14:31:23
【问题描述】:

我正在开发一个列出离用户最近的餐馆的应用程序。单击刷新按钮时,它会列出用户当前位置的餐馆。我正在使用位置管理器并仅在活动进入前台(onResume)时才请求更新,以避免持续使用电池。当应用程序进入 onPause() 时,位置更新将停止。当我通过终端传递更新时,它在模拟器上运行良好。

问题: 当我实际更改我的位置(比如开车 5 英里)并打开我的应用程序和活动以显示最近的餐馆时,刷新位置需要很长时间(4-5 分钟),然后应用程序继续显示以前位置的餐厅。但是,如果我实际更改我的位置并访问 Google 地图,然后打开我的餐厅应用程序,那么它会立即运行。我已确保 GPS 已打开。我可以做些什么来让位置管理器在我打开我的活动后立即启动并刷新位置? 提前谢谢!

package com.mortley.android.restaurantsaver;

public class NearbyRestaurantActivity extends ListActivity implements OnClickListener, LocationListener{
    private Button refreshButton, searchRestaurants; 
    ImageButton goToSearch;
    private double[] lastKnownLocation;
    private EditText locationEditText;
    private LocationManager locManager;
    private LocationListener locListener;
    private boolean gps_enabled = false;
    private boolean network_enabled = false;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.nearbyrestaurants);
        refreshButton = (Button)findViewById(R.id.reloadButton);
        refreshButton.setOnClickListener(this);

        searchRestaurants = (Button)findViewById(R.id.searchButton);
        searchRestaurants.setOnClickListener(this);
        goToSearch = (ImageButton)findViewById(R.id.goLocationButton);
        goToSearch.setOnClickListener(this);
        locationEditText = (EditText)findViewById(R.id.addressTextBox);
        locationEditText.setVisibility(View.GONE);
        goToSearch.setVisibility(View.GONE);

        locManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);//??


        locManager.requestLocationUpdates( LocationManager.GPS_PROVIDER, 1000, 100, this);

        //checks network connectivity
        boolean checkConnection = isNetworkAvailable();
        if(!checkConnection){
            Toast.makeText(getApplicationContext(), "Check your Network Connectivity", Toast.LENGTH_LONG).show();
        }

        if(checkConnection){
            //sets current location parameters for the user
            lastKnownLocation = RestaurantHelper.getLastKnownLocation(this);
            //Log.v("NearbyRestaurantActivity", "This"+this);

            RestaurantApplication application = (RestaurantApplication) this.getApplication();
            RestaurantAdapter restaurantAdapter = new RestaurantAdapter(this, R.layout.restaurantrow,  R.id.label,new ArrayList<RestaurantReference>());
            restaurantAdapter.setLastKnownLocation(lastKnownLocation);  


            //set a global variable for the RestaurantAdapter in the RestaurantApplication class.
            application.setRestaurantAdapter(restaurantAdapter);
            //Set the adapter first and then update it when the RestaurantHttpAsyncTask makes a web service call.
            setListAdapter(restaurantAdapter);
            //Make a webservice call in a different thread passing Keyword for URL as a string array.
            RestaurantHttpAsyncTask m_progressTask;
            String[] keywords = {"", "american", "asian", "italian","mexican"};
            //String[] keywords = {"indian"};
            m_progressTask = new RestaurantHttpAsyncTask(NearbyRestaurantActivity.this, keywords);
            m_progressTask.setRestaurantAdapter(restaurantAdapter);
            m_progressTask.execute();
        }
    }

    @Override
    public void onClick(View v) {   
        //Refresh button helps to refresh the restaurant list on location change. Again it makes a call to the webservice using Async Task
        if(v.getId() == refreshButton.getId() ){


            try {
                gps_enabled = locManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
            } catch (Exception ex) {
                ex.printStackTrace();
            }
            try {
                network_enabled = locManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
            } catch (Exception ex) {
                ex.printStackTrace();
            }

            // don't start listeners if no provider is enabled
            if (!gps_enabled && !network_enabled) {
                Toast.makeText(getApplicationContext(), "Sorry, Location is not determined. Please enable your Network Providers.", Toast.LENGTH_LONG).show();


            }

            //check network connectivity before refresh
            boolean checkConnection = isNetworkAvailable();
            if(!checkConnection){
                Toast.makeText(getApplicationContext(), "Check your Network Connectivity", Toast.LENGTH_LONG).show();
            }
            if(checkConnection){

                RestaurantApplication application = (RestaurantApplication) this.getApplication();
                RestaurantAdapter restaurantAdapter = new RestaurantAdapter(this, R.layout.restaurantrow,  R.id.label, new ArrayList<RestaurantReference>());
                restaurantAdapter.setLastKnownLocation(lastKnownLocation);  
                //set a global variable for the RestaurantAdapter in the RestaurantApplication class.
                application.setRestaurantAdapter(restaurantAdapter);
                //Set the adapter first and then update it when the RestaurantHttpAsyncTask makes a web service call.
                setListAdapter(restaurantAdapter);
                //Make a webservice call in a different thread passing Keyword for URL as a string array.
                RestaurantHttpAsyncTask m_progressTask, m_progressTask1;
                String[] keywords = {"", "american", "asian", "italian","mexican", "chinese", "indian"};
                //String[] keywords = {"Chinese"};
                m_progressTask = new RestaurantHttpAsyncTask(NearbyRestaurantActivity.this, keywords);
                m_progressTask.setRestaurantAdapter(restaurantAdapter);
                m_progressTask.execute();
            }
        }

        if(v.getId() == goToSearch.getId() ){

            Activity child = this;
            while(child.getParent() != null){
                child = child.getParent();
            }
            TabGroup1Activity parent = (TabGroup1Activity)getParent();


            InputMethodManager imm = (InputMethodManager)getSystemService(
                    Context.INPUT_METHOD_SERVICE);
            imm.hideSoftInputFromWindow(locationEditText.getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);

            //changes ** restaurantAdapter to RestaurantAdapter1 to test & application to application1  
            RestaurantApplication application1 = (RestaurantApplication) this.getApplication();
            RestaurantAdapter restaurantAdapter1 = new RestaurantAdapter(this, R.layout.restaurantrow,  R.id.label, new ArrayList<RestaurantReference>());
            restaurantAdapter1.setLastKnownLocation(lastKnownLocation);  
            //set a global variable for the RestaurantAdapter in the RestaurantApplication class.
            application1.setRestaurantAdapter(restaurantAdapter1);
            //Set the adapter first and then update it when the RestaurantHttpAsyncTask makes a web service call.
            setListAdapter(restaurantAdapter1);
            //Make a webservice call in a different thread passing Keyword for URL as a string array.
            RestaurantHttpAsyncTaskTextSearch m_progressTask, m_progressTask1;
            String keywords = locationEditText.getText().toString();
            if(keywords.equals("")){
                keywords = "Pizza in Palo Alto";
            }
            keywords = keywords.replaceAll(" ", "%20");
            keywords = keywords.replaceAll(",", "%20");
            m_progressTask = new RestaurantHttpAsyncTaskTextSearch (NearbyRestaurantActivity.this, keywords);
            m_progressTask.setRestaurantAdapter(restaurantAdapter1);
            m_progressTask.execute();

            locationEditText.setVisibility(View.GONE);
            goToSearch.setVisibility(View.GONE);
        }
        if(v.getId() == searchRestaurants.getId() ){
            if(goToSearch.isShown() == true){
                goToSearch.setVisibility(View.GONE);
                locationEditText.setVisibility(View.GONE);
            }
            else if(goToSearch.isShown() == false){
                //check network connectivity before refresh
                boolean checkConnection = isNetworkAvailable();
                if(!checkConnection){
                    Toast.makeText(getApplicationContext(), "Check your Network Connectivity", Toast.LENGTH_LONG).show();
                }
                if(checkConnection){
                    goToSearch.setVisibility(View.VISIBLE);
                    locationEditText.setVisibility(View.VISIBLE);

                }
            }
        }

    }
    //Method to check network connectivity
    public boolean isNetworkAvailable() {
        ConnectivityManager connectivityManager 
        = (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);
        NetworkInfo activeNetworkInfo = connectivityManager.getActiveNetworkInfo();
        if (activeNetworkInfo != null && activeNetworkInfo.isConnectedOrConnecting()) {
            //Log.d("network", "Network available:true");
            return true;
        } else {
            //Log.d("network", "Network available:false");
            return false;
        }
    }

    @Override
    protected void onResume() {
        super.onResume();
        locManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 50, 100, this); 
        //Log.v("NearbyRestaurantActivity", "In OnResume()");
    }

    @Override
    protected void onPause() {
        super.onPause();
        locManager.removeUpdates(this); 
        //Log.v("NearbyRestaurantActivity", "In onPause()");

    }

    @Override
    public void onLocationChanged(Location location) {
        // TODO Auto-generated method stub

    }

    @Override
    public void onProviderDisabled(String provider) {
        // TODO Auto-generated method stub

    }

    @Override
    public void onProviderEnabled(String provider) {
        // TODO Auto-generated method stub

    }

    @Override
    public void onStatusChanged(String provider, int status, Bundle extras) {
        // TODO Auto-generated method stub

    }
}






public class RestaurantHelper {

public static double[] getLastKnownLocation(Activity activity){
    double lat = 0.0;
    double lon = 0.0;
    LocationManager lm = (LocationManager) activity.getSystemService(Context.LOCATION_SERVICE);    
    Location location = lm.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);  

    if(location == null){
        lat = 0.0;
        lon = 0.0;
    }
    else{
        //Log.v("Latitude", Double.toString(location.getLatitude()));
        //Log.v("Longitude", Double.toString(location.getLongitude()));

        lat = location.getLatitude();
        lon = location.getLongitude();
    }
    return new double[]{lat,lon};
}
}

【问题讨论】:

  • 您似乎遗漏了一些代码 - 什么是“RestaurantHelper.getLastKnownLocation(this)”,它有什么作用?此外,“onLocationChanged()”中没有代码,这是来自 locManager.requestLocationUpdates() 的更新在新位置中传递的地方。最后,您没有显示 OnClickListener 代码。
  • 抱歉,我已经为 RestaurantHelper 类添加了代码。
  • android-developers.blogspot.com/2011/06/…(并查看新内容,例如融合的位置提供程序。)
  • 我不希望餐厅在位置更改时自动更新。只有位置坐标需要在后台更新。我应该使用 {Latitude = location.getLatitude(); Longitude = location.getLongitude();} 在 onLocationChanged() 中更新位置?我认为 requestLocationUpdates() 更新会在内部兑现最新位置,而 getLastKnownLocation() 根据兑现结果提供最新位置。
  • 谢谢查理!我会看看这个帖子。

标签: android


【解决方案1】:

您没有快速获取更新位置信息的主要原因是您依赖于RestaurantHelper.getLastKnownLocation() 方法中的NETWORK_PROVIDER,但在onCreate() 中为GPS_PROVIDER 注册了LocationListener。

所以,这段代码在RestaurantHelper.getLastKnownLocation():

Location location = lm.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);

...应该改为:

Location location = lm.getLastKnownLocation(LocationManager.GPS_PROVIDER);

理论上,这应该会为您提供最新的 GPS 位置,在您注册侦听器时应该已刷新。相反,您也可以更改为收听onCreate() 中的NETWORK_PROVIDER 并保持RestaurantHelper.getLastKnownLocation() 不变。这取决于您的精度要求 - 如果您希望高精度位置将最近的位置返回到最近的建筑物级别(例如,5-30m),您应该使用GPS_PROVIDER。但是,如果您可以使用较粗略的精度,NETWORK_PROVIDER 通常会比 GPS 更快地返回一个新位置,尤其是当您在室内时,如果从 WiFi 获取,有时这可以相当准确。

另一种方法是通过onCreate() 中的两条requestLocationUpdates() 行同时注册GPS_PROVIDERNETWORK_PROVIDER,然后查看来自lm.getLastKnownLocation(LocationManager.GPS_PROVIDER); 和@987654341 的位置上的最新时间戳@,并使用最近更新的那个。

我还建议进行以下更改,以使您的代码在大量 Android 设备上可靠:

  1. 在侦听 GPS 或 NETWORK 位置更新时将 requestLocationUpdates() minDistance 参数指定为 0 - 在 Android 4.1 之前,minDistance 参数在 OEM 解释的方式上一直不可靠且不可预测。李>
  2. 切换到新的Fused Location Provider - 这在调用getLastKnownLocation() 方法时应该比Android 框架位置API 更可靠,并且在不同设备之间更加一致。请注意,这依赖于仅适用于 Android 2.2 及更高版本的 Google Play Services SDK。

【讨论】:

  • 你说的这个 Fused Location Provider 在哪里?该链接转到“接收位置更新”的 Android 文档。那里没有提到任何“融合”的提供者。
  • 如果您使用的是 Google Play 服务位置(即 LocationClient,现在已弃用,或 LocationServices),则您使用的是 fused 提供程序。 Fused 提供程序是通过这些实现唯一可用的提供程序。
  • 感谢 Fused Location Provider。
【解决方案2】:

我有 2 条建议给你

  1. LocationClient video,是处理位置信息的新方法。它对 LocationManager 进行了改进,但管理和开发可能会很麻烦。

  2. 如果你需要使用LocationManager,你必须知道requestLocationUpdates是有bug的(非常bug)。由于它在定制硬件上的所有实现都不同。有一个可行的破解/解决方法。在调用 requestLocationUpdates 之前,只需使用以下命令启动它

代码:

 HomeScreen.getLocationManager().requestLocationUpdates(
    LocationManager.NETWORK_PROVIDER, 0, 0, new LocationListener() {
        @Override
        public void onStatusChanged(String provider, int status, Bundle extras) {
        }
        @Override
        public void onProviderEnabled(String provider) {
        }
        @Override
        public void onProviderDisabled(String provider) {
        }
        @Override
        public void onLocationChanged(final Location location) {
        }
    });

【讨论】:

  • 这个启动的东西对Android Bug 57707 没有帮助,它至少会影响到网络提供商。
  • 把我的答案放在那里。让我们等着听他们的回音。
【解决方案3】:

requestLocationUpdates 有问题。始终使用网络提供商触发 onLocationChanged(...)

locManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 1000, 100, this)

只有在使用网络提供商后才使用 gps 提供商:

locManager.requestLocationUpdates( LocationManager.GPS_PROVIDER, 1000, 100, this)

在通过 gps 请求位置更新之前,不要忘记检查 gps 是否启用。

【讨论】:

    猜你喜欢
    • 2012-06-10
    • 1970-01-01
    • 2019-06-29
    • 2013-06-14
    • 1970-01-01
    • 1970-01-01
    • 2014-04-03
    • 1970-01-01
    • 2010-10-28
    相关资源
    最近更新 更多