位置 returns 空 google API 客户端

location returns null by google API client

我试图创建一个简单的应用程序来标记当前位置并添加到列表中。

我正在按照 android 教程使用 google 播放服务 API 获取位置。但是,当我尝试启动位置服务以获取位置更新时,位置 returns 为空并给出空指针异常。

下面是 MainActivity 代码:

public class MainActivity extends AppCompatActivity implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, LocationListener {

private GoogleApiClient mGoogleApiClient;
private Location mLastLocation, mCurrentLocation;
private double currentLatitude, currentLongitude;
private String lastUpdateTime, addressMessage = null;
private AddressResultReceiver resultReceiver;
private MainList listFragment = new MainList();
private MaterialDialog dialog;
boolean mHasLastLocation = false, mAddressRequested = false;
private FragmentManager mFragmentManager;

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

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

    mFragmentManager = getFragmentManager();
    FragmentTransaction fragmentTransaction = mFragmentManager.beginTransaction();
    fragmentTransaction.add(R.id.fragment,listFragment);
    fragmentTransaction.commit();

    dialog = new MaterialDialog(this)
            .setTitle("Select an address")
            .setMessage(addressMessage)
            .setPositiveButton("SELECT", new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    dialog.dismiss();
                    listFragment.list.add(addressMessage);
                    listFragment.mAdapter.notifyDataSetChanged();
                }
            })
            .setNegativeButton("CANCEL", new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    dialog.dismiss();
                }
            });

    Toolbar toolbar = (Toolbar) findViewById(R.id.tool_bar);
    setSupportActionBar(toolbar);

    FloatingActionButton floatingActionButton = (FloatingActionButton) findViewById(R.id.fab_button);

    LayoutInflater inflater = LayoutInflater.from(getApplicationContext());

    floatingActionButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            startAddressLookUp();
            mAddressRequested = true;
            dialog.setMessage(addressMessage);
            dialog.show();
        }
    });

}

@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_main, 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);
}

@Override
protected void onPause() {
    super.onPause();
    LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, this);
}

@Override
public void onResume() {
    super.onResume();
    if(mGoogleApiClient.isConnected()) {
        LocationRequest locationRequest = createLocationRequest();
        startLocationUpdates(locationRequest);
    }
}

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

    if (mLastLocation != null) {
        mHasLastLocation = true;
        String toastText = "lastLocation exists!";
        Toast.makeText(getApplicationContext(), toastText, Toast.LENGTH_LONG).show();
    }

    LocationRequest locationRequest = createLocationRequest();

    if (locationRequest != null) {
        startLocationUpdates(locationRequest);
    }

    if (mAddressRequested) {
        startAddressLookUp();
    }
}

@Override
public void onConnectionFailed(ConnectionResult connectionResult) {

}

@Override
public void onConnectionSuspended(int i) {

}

@Override
public void onLocationChanged(Location location) {
    mCurrentLocation = location;
    currentLatitude = mCurrentLocation.getLatitude();
    currentLongitude = mCurrentLocation.getLongitude();
    lastUpdateTime = DateFormat.getDateTimeInstance().format(new Date());
}


protected LocationRequest createLocationRequest() {
    LocationRequest mLocationRequest = new LocationRequest();
    mLocationRequest.setInterval(8000);
    mLocationRequest.setFastestInterval(5000);
    mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
    return mLocationRequest;
}

protected void startLocationUpdates(LocationRequest request) {
    LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, request, this);
}

protected void startAddressLookUp() {
    Intent intent = new Intent(this,AddressLookUpService.class);
    intent.putExtra(AddressLookUpService.Constants.RECEIVER, resultReceiver);
    intent.putExtra(AddressLookUpService.Constants.LOCATION_DATA_EXTRA, mCurrentLocation);
    startService(intent);
}

class AddressResultReceiver extends ResultReceiver {
    public AddressResultReceiver(Handler handler) {
        super(handler);
    }

    @Override
    protected void onReceiveResult(int resultCode, Bundle result) {
        if (resultCode == AddressLookUpService.Constants.SUCCESS) {
            addressMessage = result.getString(AddressLookUpService.Constants.RESULT_DATA_KEY);
        }
    }
}
}

按照教程的建议,我还创建了一个地址查询服务来获取地理编码地址,如下所示:

public class AddressLookUpService extends IntentService {

private Location location;
private ResultReceiver receiver;
private Geocoder geocoder;
public static final String TAG = "AddressLookUpService";

public AddressLookUpService() {
    super("AddressLookUpService");
}

@Override
protected void onHandleIntent (Intent intent) {
    geocoder = new Geocoder(this, Locale.getDefault());
    String errorMsg = "";

    location = intent.getParcelableExtra(Constants.LOCATION_DATA_EXTRA);

    List<Address> addressList = null;

    try{
        addressList = geocoder.getFromLocation(location.getLatitude(), location.getLongitude(), 1);
    }
    catch (IOException ioException) {
        errorMsg = getString(R.string.service_not_available);
        Log.e(TAG, errorMsg, ioException);
    }
    catch (IllegalArgumentException illegalArgumentException) {
        errorMsg = getString(R.string.invalid_lat_long);
        Log.e(TAG, errorMsg + ". " +
                "Latitude = " + location.getLatitude() +
                ", Longitude = " +
                location.getLongitude(), illegalArgumentException);
    }

    if (addressList == null || addressList.size() == 0) {
        if (errorMsg.isEmpty()) {
            errorMsg = getString(R.string.no_address_found);
            Log.e(TAG, errorMsg);
        }

    if (location == null) {
        if (errorMsg.isEmpty()) {
            errorMsg = "Location is null";
            Log.e(TAG, errorMsg);
        }
    }

        deliverResultToReceiver(Constants.FAIL, errorMsg);
    }
    else {
        ArrayList<String> addressFragments = new ArrayList<String>();

        /*for (Address address : addressList) {
            for (int i=0; i<address.getMaxAddressLineIndex(); i++) {
                addressFragments.add(address.getAddressLine(i));
            }
        }*/

        Address address = addressList.get(0);

        for (int i=0; i<address.getMaxAddressLineIndex(); i++) {
            addressFragments.add(address.getAddressLine(i));
        }

        Log.i(TAG, getString(R.string.address_found));
        deliverResultToReceiver(Constants.SUCCESS, TextUtils.join(System.getProperty("line.separator"), addressFragments));
    }
}

public final class Constants {
    public static final int SUCCESS = 0;
    public static final int FAIL = 1;
    public static final String PACKAGE_NAME = "com.pyason.heremark";
    public static final String RECEIVER = PACKAGE_NAME + ".RECEIVER";
    public static final String RESULT_DATA_KEY = PACKAGE_NAME + ".RESULT_DATA_KEY";
    public static final String LOCATION_DATA_EXTRA = PACKAGE_NAME + ".LOCATION_DATA_EXTRA";
}

private void deliverResultToReceiver(int resultCode, String message) {
    Bundle bundle = new Bundle();
    bundle.putString(Constants.RESULT_DATA_KEY, message);
    receiver.send(resultCode, bundle);
}

}

所以当我尝试获取新地址时,应用程序抛出以下异常:

07-31 00:35:13.538  28055-28519/? E/AndroidRuntime﹕ FATAL EXCEPTION: IntentService[AddressLookUpService]
Process: com.pyason.heremark, PID: 28055
java.lang.NullPointerException: Attempt to invoke virtual method 'double android.location.Location.getLatitude()' on a null object reference
        at com.pyason.heremark.AddressLookUpService.onHandleIntent(AddressLookUpService.java:45)
        at android.app.IntentService$ServiceHandler.handleMessage(IntentService.java:65)

它只是说 AddressLookupService 中的位置 returns null,我想我已经开始位置更新了。

有人可以帮忙吗?感谢您的帮助:)

谢谢, 保罗

你设置了吗<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> ?

Returns 一个位置,表示从给定提供者处获得的最后一个已知位置定位的数据。

这可以在不启动提供程序的情况下完成。请注意,此位置可能已过时,例如,如果设备已关闭并移至其他位置。

如果提供程序当前被禁用,则返回 null。

更改您的代码

 @Override
    public void onLocationChanged(Location location) {
        mCurrentLocation = location;
if(mCurrentLocation !=null){      
 currentLatitude = mCurrentLocation.getLatitude();
        currentLongitude = mCurrentLocation.getLongitude();
        lastUpdateTime = DateFormat.getDateTimeInstance().format(new Date());

}
  }

看起来主要问题是你没有调用 mGoogleApiClient.connect(),所以 onConnected() 没有被调用,而 mGoogleApiClient.isConnected() 总是 return false,所以结果,startLocationUpdates() 永远不会被调用。

构建 GoogleApiClient 后调用 connect()

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

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

    //add this here:
    mGoogleApiClient.connect();

此外,您似乎应该禁用 floatingActionButton,直到您获得第一个非空位置,否则当用户单击该按钮时,AddressLookUpService 将获得一个空位置。

此外,为了安全起见,请在 AddressLookUpService 中进行空检查,以防它传递空位置:

@Override
protected void onHandleIntent (Intent intent) {
    geocoder = new Geocoder(this, Locale.getDefault());
    String errorMsg = "";

    location = intent.getParcelableExtra(Constants.LOCATION_DATA_EXTRA);

    //Just exit if location is null:
    if (location == null) return; 

    //..................