从 Activity 调用 Location 时获取 NullPointerException
Posted
技术标签:
【中文标题】从 Activity 调用 Location 时获取 NullPointerException【英文标题】:Getting NullPointerException when call Location from Activity 【发布时间】: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
我不知道如何弄清楚。你对这方面有什么建议吗?
【问题讨论】:
【参考方案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()));
【讨论】:
以上是关于从 Activity 调用 Location 时获取 NullPointerException的主要内容,如果未能解决你的问题,请参考以下文章
如何从 HomeScreen Widget 调用 Activity 中的函数
从 asyncTask doInBackground 调用 Activity