getLastLocation 返回一个空值

Posted

技术标签:

【中文标题】getLastLocation 返回一个空值【英文标题】:getLastLocation returns a null value 【发布时间】:2015-10-09 21:23:58 【问题描述】:

我已遵循本指南https://developer.android.com/training/location/retrieve-current.html#permissions,但我无法收到最后一个位置。

我只需要一次该位置。

这是我的代码:

public class MainActivity extends ActionBarActivity implements GoogleApiClient.ConnectionCallbacks,
        GoogleApiClient.OnConnectionFailedListener 

    public static final String TAG = MainActivity.class.getSimpleName();
    public static final String DAILY_FORECAST = "DAILY_FORECAST";
    public static final String HOURLY_FORECAST = "HOURLY_FORECAST";

    private Forecast mForecast;
    private GoogleApiClient mGoogleApiClient;
    private Location mLastLocation;
    private double mLatitude;
    private double mLongitude;

    @Bind(R.id.timeLabel) TextView mTimeLabel;
    @Bind(R.id.temperatureLabel) TextView mTemperatureLabel;
    @Bind(R.id.humidityValue) TextView mHumidityValue;
    @Bind(R.id.precipValue) TextView mPrecipValue;
    @Bind(R.id.summaryLabel) TextView mSummaryLabel;
    @Bind(R.id.iconImageView) ImageView mIconImageView;
    @Bind(R.id.refreshImageView) ImageView mRefreshImageView;
    @Bind(R.id.progressBar) ProgressBar mProgressBar;

    @Override
    protected void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ButterKnife.bind(this);

        mProgressBar.setVisibility(View.INVISIBLE);

        buildGoogleApiClient();

        //mLatitude = 37.8267;
        //mLongitude = -122.423;


        mRefreshImageView.setOnClickListener(new View.OnClickListener() 
            @Override
            public void onClick(View v) 
                getForecast(mLatitude, mLongitude);
            
        );

        getForecast(mLatitude, mLongitude);
    

    private void getForecast(double latitude, double longitude) 
        String apiKey = "48fb6c0ca3567d0b17bf99b400ef5606";
        String forecastUrl = "https://api.forecast.io/forecast/" + apiKey +
                "/" + latitude + "," + longitude;
        if (isNetworkAvailable()) 
            toggleRefresh();

            OkHttpClient client = new OkHttpClient();
            Request request = new Request.Builder()
                    .url(forecastUrl)
                    .build();

            Call call = client.newCall(request);
            call.enqueue(new Callback() 
                @Override
                public void onFailure(Request request, IOException e) 
                    runOnUiThread(new Runnable() 
                        @Override
                        public void run() 
                            toggleRefresh();
                        
                    );
                    alertUserAboutError();
                

                @Override
                public void onResponse(Response response) throws IOException 
                    runOnUiThread(new Runnable() 
                        @Override
                        public void run() 
                            toggleRefresh();
                        
                    );

                    try 
                        String jsonData = response.body().string();
                        Log.v(TAG, jsonData);
                        if (response.isSuccessful()) 
                            mForecast = parseForecastDetails(jsonData);
                            runOnUiThread(new Runnable() 
                                @Override
                                public void run() 
                                    updateDisplay();
                                
                            );
                         else 
                            alertUserAboutError();
                        
                     catch (IOException e) 
                        Log.e(TAG, "Exception caught: ", e);
                     catch (JSONException e) 
                        Log.e(TAG, "Exception caught: ", e);
                    
                
            );
        
        else 
            Toast.makeText(this, getString(R.string.network_unavailable_message),
                    Toast.LENGTH_LONG).show();
        
    

    private void toggleRefresh() 
        if (mProgressBar.getVisibility() == View.INVISIBLE) 
            mProgressBar.setVisibility(View.VISIBLE);
            mRefreshImageView.setVisibility(View.INVISIBLE);
        
        else 
            mProgressBar.setVisibility(View.INVISIBLE);
            mRefreshImageView.setVisibility(View.VISIBLE);
        
    

    private void updateDisplay() 
        Current current = mForecast.getCurrent();

        mTemperatureLabel.setText(current.getTemperature() + "");
        mTimeLabel.setText("At " + current.getFormattedTime() + " it will be");
        mHumidityValue.setText(current.getHumidity() + "");
        mPrecipValue.setText(current.getPrecipChance() + "%");
        mSummaryLabel.setText(current.getSummary());

        Drawable drawable = getResources().getDrawable(current.getIconId());
        mIconImageView.setImageDrawable(drawable);
    

    private Forecast parseForecastDetails(String jsonData) throws JSONException 
        Forecast forecast = new Forecast();

        forecast.setCurrent(getCurrentDetails(jsonData));
        forecast.setHourlyForecast(getHourlyForecast(jsonData));
        forecast.setDailyForecast(getDailyForecast(jsonData));

        return forecast;
    

    private Day[] getDailyForecast(String jsonData) throws JSONException JSONObject forecast = new JSONObject(jsonData);
        String timezone = forecast.getString("timezone");
        JSONObject daily = forecast.getJSONObject("daily");
        JSONArray data = daily.getJSONArray("data");

        Day[] days = new Day[data.length()];
        for (int i = 0; i < data.length(); i++) 
            JSONObject jsonDay = data.getJSONObject(i);
            Day day = new Day();

            day.setSummary(jsonDay.getString("summary"));
            day.setIcon(jsonDay.getString("icon"));
            day.setTime(jsonDay.getLong("time"));
            day.setTemperatureMax(jsonDay.getDouble("temperatureMax"));
            day.setTimezone(timezone);

            days[i] = day;
        

        return days;
    

    private Hour[] getHourlyForecast(String jsonData) throws JSONException 
        JSONObject forecast = new JSONObject(jsonData);
        String timezone = forecast.getString("timezone");
        JSONObject hourly = forecast.getJSONObject("hourly");
        JSONArray data = hourly.getJSONArray("data");

        Hour[] hours = new Hour[data.length()];
        for (int i = 0; i < data.length(); i++) 
            JSONObject jsonHour = data.getJSONObject(i);
            Hour hour = new Hour();

            hour.setSummary(jsonHour.getString("summary"));
            hour.setTemperature(jsonHour.getDouble("temperature"));
            hour.setIcon(jsonHour.getString("icon"));
            hour.setTime(jsonHour.getLong("time"));
            hour.setTimezone(timezone);

            hours[i] = hour;
        

        return hours;
    

    private Current getCurrentDetails(String jsonData) throws JSONException 
        JSONObject forecast = new JSONObject(jsonData);
        String timezone = forecast.getString("timezone");

        Log.i(TAG, "From JSON: " + timezone);

        JSONObject currently = forecast.getJSONObject("currently");

        Current current = new Current();
        current.setHumidity(currently.getDouble("humidity"));
        current.setTime(currently.getInt("time"));
        current.setSummary(currently.getString("summary"));
        current.setTemperature(currently.getInt("temperature"));
        current.setIcon(currently.getString("icon"));
        current.setPrecipChance(currently.getDouble("precipProbability"));
        current.setTimeZone(timezone);

        Log.d(TAG, current.getFormattedTime());

        return current;
    

    private boolean isNetworkAvailable() 
        ConnectivityManager manager = (ConnectivityManager)
                getSystemService(Context.CONNECTIVITY_SERVICE);
        NetworkInfo networkInfo = manager.getActiveNetworkInfo();
        boolean isAvailable = false;
        if (networkInfo != null && networkInfo.isConnected()) 
            isAvailable = true;
        
        return isAvailable;
    

    private void alertUserAboutError() 
        AlertDialogFragment dialog = new AlertDialogFragment();
        dialog.show(getFragmentManager(), "error_dialog");
    

    @OnClick (R.id.dailyButton)
    public void startDailyActivity(View view) 
        Intent intent = new Intent(this, DailyForecastActivity.class);
        intent.putExtra(DAILY_FORECAST, mForecast.getDailyForecast());
        startActivity(intent);
    

    @OnClick(R.id.hourlyButton)
    public void startHourlyActivity(View view) 
        Intent intent = new Intent(this, HourlyForecastActivity.class);
        intent.putExtra(HOURLY_FORECAST, mForecast.getHourlyForecast());
        startActivity(intent);
    

    protected synchronized void buildGoogleApiClient() 
        mGoogleApiClient = new GoogleApiClient.Builder(this)
                .addConnectionCallbacks(this)
                .addOnConnectionFailedListener(this)
                .addApi(LocationServices.API)
                .build();
    

    @Override
    public void onConnected(Bundle bundle) 
        mLastLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);

        if (mLastLocation != null) 
            mLatitude = mLastLocation.getLatitude();
            mLongitude = mLastLocation.getLongitude();
        
    

    @Override
    public void onConnectionSuspended(int i) 

    

    @Override
    public void onConnectionFailed(ConnectionResult connectionResult) 

    

`

【问题讨论】:

获取经纬度的代码在哪里??可以分享一下吗 1- 确保您已连接到 Google Play 服务 因为它可以...问了无数次...做一些研究... 【参考方案1】:

getLastLocation() 很容易返回 null。它也不会请求新的位置,所以即使你得到一个位置,它也可能很旧,并且不能反映当前位置。最好注册一个监听器,即使您在收到第一个 onLocationChanged() 回调后取消注册。

这个问题被问了很多,通常被标记为questions like this one的重复

但是,在您的情况下,您似乎也只是忘记致电connect()

 buildGoogleApiClient();
 mGoogleApiClient.connect(); //added

您可以使用this answer中的代码作为注册位置回调的参考,如果您想获得准确的当前位置,建议您这样做。

编辑:由于您只需要一个位置,这里是该代码的略微修改版本,它请求位置更新,然后在第一个位置进入后取消注册位置更新。

public class MainActivity extends Activity implements
        GoogleApiClient.ConnectionCallbacks,
        GoogleApiClient.OnConnectionFailedListener, LocationListener 

    LocationRequest mLocationRequest;
    GoogleApiClient mGoogleApiClient;
    private Location mLastLocation;
    private double mLatitude;
    private double mLongitude;

    @Override
    protected void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        buildGoogleApiClient();
        mGoogleApiClient.connect();
    

    @Override
    protected void onPause()
        super.onPause();
        if (mGoogleApiClient != null) 
            LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, this);
        
    

    protected synchronized void buildGoogleApiClient() 

        mGoogleApiClient = new GoogleApiClient.Builder(this)
                .addConnectionCallbacks(this)
                .addOnConnectionFailedListener(this)
                .addApi(LocationServices.API)
                .build();
    

    @Override
    public void onConnected(Bundle bundle) 

        mLocationRequest = new LocationRequest();
        mLocationRequest.setInterval(1000);
        mLocationRequest.setFastestInterval(1000);
        mLocationRequest.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);

        //mLocationRequest.setSmallestDisplacement(0.1F);

        LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, this);
    

    @Override
    public void onConnectionSuspended(int i) 
        Toast.makeText(this,"onConnectionSuspended",Toast.LENGTH_SHORT).show();
    

    @Override
    public void onConnectionFailed(ConnectionResult connectionResult) 
        Toast.makeText(this,"onConnectionFailed",Toast.LENGTH_SHORT).show();
    

    @Override
    public void onLocationChanged(Location location) 
        mLastLocation = location;
        //no need to do a null check here:
        mLatitude = location.getLatitude();
        mLongitude = location.getLongitude();

        //remove location updates if you just need one location:
        if (mGoogleApiClient != null) 
            LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, this);
        
    

【讨论】:

“getLastLocation() 有很高的返回 null 的倾向。”:在什么情况下即使位置设置为 ON,此 API 也会返回 null? @SantoshSalunke 在这里更好的解释:***.com/a/32291415/4409409 谢谢丹尼尔。在我的 Nexus-5 上,我观察到 getLastLocation 即使在我启动 Google Map 应用程序然后再次启动我的应用程序之后也会返回 null。即使在 Google 地图应用程序中正确检测到位置,getLastLocation API 也会返回 null。我不明白:如果谷歌地图请求了位置,那么为什么缓存的位置没有更新。

以上是关于getLastLocation 返回一个空值的主要内容,如果未能解决你的问题,请参考以下文章

从 Settings Api 对话框打开位置后,getLastLocation() 返回 null

getLastLocation() 返回俄罗斯中部的随机位置

来自 LocationClient 的 getLastLocation() 始终返回 null [重复]

Android studio 不检查 mFusedLocationProviderClient.getLastLocation().addOnSuccessListener 并返回当前位置 null

Android LocationClient.getLastLocation() 返回带有新时间戳的旧且不准确的位置

FusedLocationApi.getLastLocation 总是返回 null(android 6.0,api 23)