Reputation: 14179
This is my activity and I'd like to get into it the location. I have decoupled the Activity and the geolocation function
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);
}
}
Here is the geolocation function:
package 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;
}
}
The class CurrentGeolocationEntity
is a simple POJO where I store the Location representing the last location known.
Unforuntately I get the error:
Attempt to invoke virtual method 'double android.location.Location.getLatitude()' on a null object reference
I don't know how to figure out it. Do you have any advice on regard?
Upvotes: 1
Views: 365
Reputation: 43322
It looks like you have a race-condition, and you're requesting a location from your CurrentGeolocation
class before the SDK has had time to connect.
You could add a isConnected()
method to your CurrentGeolocation
class, and set a boolean value in the onConnected()
callback.
Then, always call isConnected()
before you call mCurrentGeolocation.getmCurrentGeolocationEntity().getmLastLocation()
.
Another thing to mention is that getLastLocation()
has a high probability of returning null, since it does not explicitly make a location request. The location that you get from this method can also be very old, and might not reflect the current location at all.
The first fix you should make is this, do a null check on the Location object before you use it:
@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()));
}
}
The next change you should make is to register a location listener in your CurrentGeolocation
class, which will explicitly request a new location from the system.
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);
Then add a onLocationChanged()
callback:
@Override
public void onLocationChanged(Location mLastLocation) {
mCurrentGeolocationEntity.setmLastLocation(mLastLocation);
}
For more info, take a look at the code in this answer.
Note that you should un-register the location listener as soon as possible to minimize battery drain of your app:
LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, this);
Upvotes: 1
Reputation: 2260
Your problem is in onStart()
in your Activity, at this line:
Log.i(TAG, String.valueOf(mCurrentGeolocation.getmCurrentGeolocationEntity().getmLastLocation().getLatitude()));
The problem is that the following line:
mCurrentGeolocation.getmCurrentGeolocationEntity().getmLastLocation()
returns null. I can only guess now, but I think that when your activity first starts you have no last location and so that method returns null. Try the following code:
@Override
protected void onStart() {
super.onStart();
mGoogleApiClient.connect();
if (mCurrentGeolocation.getmCurrentGeolocationEntity().getmLastLocation() != null)
Log.i(TAG, String.valueOf(mCurrentGeolocation.getmCurrentGeolocationEntity().getmLastLocation().getLatitude()));
}
Upvotes: 0