我正在尝试创建一个标记当前位置的简单应用并添加到列表中。
我使用Google Play服务API获取位置,按照Android教程。但是,当我尝试启动位置服务以获取位置更新时,该位置返回null并给出空指针异常。
以下是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中的位置返回null,我认为我已经开始了位置更新。
任何人都可以帮忙吗?感谢您的帮助:)。
谢谢, 保罗
答案 0 :(得分:1)
看起来主要问题是您没有调用mGoogleApiClient.connect()
,因此onConnected()
未被调用,mGoogleApiClient.isConnected()
将始终返回false,因此startLocationUpdates()
1}}永远不会被调用。
在构建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;
//..................
答案 1 :(得分:0)
您是否设置了<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> ?
返回一个位置,指示从给定提供程序获取的上次已知位置修复的数据。
这可以在不启动提供程序的情况下完成。请注意,此位置可能已过期,例如,如果设备已关闭并移至其他位置。
如果当前禁用了提供程序,则返回null。
更改您的代码
@Override
public void onLocationChanged(Location location) {
mCurrentLocation = location;
if(mCurrentLocation !=null){
currentLatitude = mCurrentLocation.getLatitude();
currentLongitude = mCurrentLocation.getLongitude();
lastUpdateTime = DateFormat.getDateTimeInstance().format(new Date());
}
}