【问题标题】:Getting NullPointerException when call Location from Activity从 Activity 调用 Location 时获取 NullPointerException
【发布时间】:2015-08-13 12:28:03
【问题描述】:

这是我的活动,我想进入它的位置。我已经解耦了Activity和geolocation函数

package com.salvo.weather.android.activity;

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;


import com.google.android.gms.common.api.GoogleApiClient;
import com.salvo.weather.android.R;
import com.salvo.weather.android.geolocation.CurrentGeolocation;


public class TodayActivity extends Activity {

    public static final String TAG = TodayActivity.class.getSimpleName();

    protected GoogleApiClient mGoogleApiClient;

    protected CurrentGeolocation mCurrentGeolocation;

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

        mCurrentGeolocation = new CurrentGeolocation(this);
        mGoogleApiClient = mCurrentGeolocation.getmGoogleApiClient();
    }

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

        Log.i(TAG, String.valueOf(mCurrentGeolocation.getmCurrentGeolocationEntity().getmLastLocation().getLatitude()));
    }

    @Override
    protected void onStop() {
        super.onStop();
        if (mGoogleApiClient.isConnected()) {
            mGoogleApiClient.disconnect();
        }
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_today, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {
            return true;
        }

        return super.onOptionsItemSelected(item);
    }
}

这是地理定位功能:

包 com.salvo.weather.android.geolocation;

import android.content.Context;
import android.location.Location;
import android.os.Bundle;
import android.util.Log;
import android.widget.Toast;


import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.common.api.GoogleApiClient.ConnectionCallbacks;
import com.google.android.gms.common.api.GoogleApiClient.OnConnectionFailedListener;
import com.google.android.gms.location.LocationServices;
import com.salvo.weather.android.entity.CurrentGeolocationEntity;

/**
 * Created by mazzy on 30/05/15.
 */
public class CurrentGeolocation
        implements ConnectionCallbacks, OnConnectionFailedListener {

    private Context mcontext;

    private GoogleApiClient mGoogleApiClient;
    private CurrentGeolocationEntity mCurrentGeolocationEntity;

    public CurrentGeolocation(Context context) {
        mcontext = context;
        mCurrentGeolocationEntity = new CurrentGeolocationEntity();
        buildGoogleApiClient();
    }

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

    @Override
    public void onConnected(Bundle bundle) {

        Location mLastLocation = LocationServices
                .FusedLocationApi
                .getLastLocation(this.mGoogleApiClient);

        if (mLastLocation != null) {
            mCurrentGeolocationEntity.setmLastLocation(mLastLocation);
        } else {
            Toast.makeText(this.mcontext, "No location detected", Toast.LENGTH_LONG).show();
        }
    }

    @Override
    public void onConnectionSuspended(int i) {
        // The connection to Google Play services was lost for some reason. We call connect() to
        // attempt to re-establish the connection.
        // TODO: add some verbose message
    }

    @Override
    public void onConnectionFailed(ConnectionResult connectionResult) {
        // Refer to the javadoc for ConnectionResult to see what error codes might be returned in
        // onConnectionFailed.
    }

    public GoogleApiClient getmGoogleApiClient() {
        return mGoogleApiClient;
    }

    public CurrentGeolocationEntity getmCurrentGeolocationEntity() {
        return mCurrentGeolocationEntity;
    }
}

CurrentGeolocationEntity 类是一个简单的 POJO,我在其中存储表示最后一个已知位置的 Location。

不幸的是我得到了错误:

Attempt to invoke virtual method 'double android.location.Location.getLatitude()' on a null object reference

我不知道如何弄清楚。你对这方面有什么建议吗?

【问题讨论】:

    标签: java android geolocation


    【解决方案1】:

    您似乎有竞争条件,并且您在 SDK 有时间连接之前从您的 CurrentGeolocation 类请求位置。

    您可以向您的CurrentGeolocation 类添加一个isConnected() 方法,并在onConnected() 回调中设置一个布尔值。

    那么,在拨打mCurrentGeolocation.getmCurrentGeolocationEntity().getmLastLocation()之前,请始终拨打isConnected()

    另外要提到的是getLastLocation() 很有可能返回 null,因为它没有明确地发出位置请求。您通过此方法获得的位置也可能很旧,并且可能根本无法反映当前位置。

    您应该做的第一个修复是,在使用 Location 对象之前对其进行空检查:

    @Override
    protected void onStart() {
        super.onStart();
        mGoogleApiClient.connect();
    
        //use a temp Location object:
        Location loc = mCurrentGeolocation.getmCurrentGeolocationEntity().getmLastLocation();
        //null check:
        if (loc != null){
    
           Log.i(TAG, String.valueOf(loc.getLatitude()));
        }
    }
    

    您应该进行的下一个更改是在您的 CurrentGeolocation 类中注册一个位置侦听器,这将明确地从系统请求一个新位置。

        mLocationRequest = new LocationRequest();
        mLocationRequest.setInterval(10);
        mLocationRequest.setFastestInterval(10);
        mLocationRequest.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);
    
        mLocationRequest.setSmallestDisplacement(0.1F);
    
        LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, this);
    

    然后添加onLocationChanged()回调:

    @Override
    public void onLocationChanged(Location mLastLocation) {
    
        mCurrentGeolocationEntity.setmLastLocation(mLastLocation);
    
    }
    

    更多信息,请查看this answer中的代码。

    请注意,您应尽快取消注册位置侦听器,以尽量减少应用的电池消耗:

     LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, this);
    

    【讨论】:

    • 谢谢丹尼尔的回答。我的问题是我不知道何时取消注册回调。在我的应用程序中,我没有任何按钮来控制更新位置。这是一个天气应用程序
    【解决方案2】:

    您的问题在于您的活动中的onStart(),在这一行:

    Log.i(TAG, String.valueOf(mCurrentGeolocation.getmCurrentGeolocationEntity().getmLastLocation().getLatitude()));
    

    问题在于以下行:

    mCurrentGeolocation.getmCurrentGeolocationEntity().getmLastLocation()
    

    返回空值。我现在只能猜测,但我认为当您的活动第一次开始时,您没有最后一个位置,因此该方法返回 null。试试下面的代码:

    @Override
    protected void onStart() {
        super.onStart();
        mGoogleApiClient.connect();
        if (mCurrentGeolocation.getmCurrentGeolocationEntity().getmLastLocation() != null)
            Log.i(TAG, String.valueOf(mCurrentGeolocation.getmCurrentGeolocationEntity().getmLastLocation().getLatitude()));
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-10-22
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多