I'm trying to find out why the Google Play Services is crashing with a nullpointerexception after the application is coming back from a background state such as device sleep or toggle other program. Sometimes Google Play Services gives the crash popup on application start. So I assume the problem lies somewhere on the path to the service since there is where the threading occurs with rxjava.
Note: I Inject GoogleApiClient in both MainActivity (field injection) and in GoogleApiService (constructor injection).
GoogleApiClient is injected as a @Singleton. I've been trying to trace why this is happening for hours now without progress, any help appreciated.
The Application continues to work without any issues, the "Google Play Services popup" is annoying though, I see one call to getuserLocAndWeather() return lost connection to google play services, but it immediatly returns a valid result in the next call.
The actual object reference in MainActivity and GoogleApiService is never null, the reference is always the same, like com.google.android.gms.internal.zzqd@a768e13 and always connected when the call is made.
Trace:
FATAL EXCEPTION: lowpool[3]
Process: com.google.android.gms.persistent, PID: 12828
java.lang.NullPointerException: GoogleApiClient must not be null
at ilk.a(:com.google.android.gms:73)
at hys.<init>(:com.google.android.gms:115)
at pof.<init>(:com.google.android.gms:86)
at ppz.<init>(:com.google.android.gms:35)
at ppx.<init>(:com.google.android.gms:179)
at ppp.a(:com.google.android.gms:179)
at buc.a(:com.google.android.gms:381)
at jfo.run(:com.google.android.gms:1087)
at itt.run(:com.google.android.gms:453)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
at iyg.run(:com.google.android.gms:17)
at java.lang.Thread.run(Thread.java:818)
My Service class:, the print out in the try{} for the client is always : true, regardless if google play services crashes or not.
Client: com.google.android.gms.internal.zzqd@3c738f4e Connected? :true
public class GoogleApiService implements IGoogleApi{
private GoogleApiClient client;
private static final String TAG = "GoogleApiClient";
@Inject
public GoogleApiService(GoogleApiClient client){
this.client = client;
}
public Observable<UserCurrentInfo> getLocationWeather(){
Observable<WeatherResult> weatherObservable = Observable.create(subscriber -> {
try {
Log.d(TAG,"Trying to get some Weather");
Log.d(TAG,"Client: " + client.toString() + " Connected? :" + client.isConnected());
Awareness.SnapshotApi.getWeather(client)
.setResultCallback(weather -> {
if (!weather.getStatus().isSuccess()) {
subscriber.onError(new Throwable("could not get weather"));
Log.d(TAG," Error getting weather" + weather.getStatus().toString());
} else {
Log.d(TAG,"Getting dem weathers");
subscriber.onNext(weather);
subscriber.onCompleted();
}
});
}catch (SecurityException e){
throw new SecurityException("No permission: " + e);
}
});
Observable<LocationResult> locationObservable = Observable.create(subscriber -> {
try {
Awareness.SnapshotApi.getLocation(client)
.setResultCallback(retrievedLocation -> {
if (!retrievedLocation.getStatus().isSuccess()) {
subscriber.onError(new Throwable("Could not get location."));
Log.d(TAG," Error getting location");
} else {
subscriber.onNext(retrievedLocation);
subscriber.onCompleted();
}
});
}catch (SecurityException e){
throw new SecurityException("No permission: " + e);
}
});
return Observable.zip(weatherObservable, locationObservable,
(weather, location) -> {
return new UserCurrentInfo(weather.getWeather(),location.getLocation());
});
}
Presenter:
public class FavouritesPresenter implements BasePresenter<IFavouriteView>{
private IFavouriteView favView;
private String TAG = "FavPresenter";
private Subscription subscription;
private GetUserLocationWeatherUseCase useCase;
@Inject
FavouritesPresenter(GetUserLocationWeatherUseCase wlUseCase){
this.useCase = wlUseCase;
}
@Override
public void onCreate() {
}
@Override
public void onStop(){
if(subscription != null){
subscription.unsubscribe();
}
}
public void getUserLocAndWeather(){
subscription = useCase.execute().subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(info -> {
favView.showText(
formatStringDecimals(info.getWeather().getTemperature(Weather.CELSIUS)+"",2),
info.getWeather().getConditions()[0],
formatStringDecimals(""+info.getLocation().getLatitude(),3),
formatStringDecimals("" + info.getLocation().getLongitude(),3)
);},
err ->{favView.showText("??",0,"","");}
);
}
Usecase:
public class GetUserLocationWeatherUseCase implements Usecase<UserCurrentInfo> {
IGoogleApi apihelper;
public GetUserLocationWeatherUseCase(IGoogleApi helper){
this.apihelper = helper;
}
@Override
public Observable<UserCurrentInfo> execute(){
return apihelper.getLocationWeather();
}
Usage in mainactivity:
@Inject
FavouritesPresenter favouritesPresenter;
GoogleApiClient.ConnectionCallbacks connectionCallbacks;
GoogleApiClient.OnConnectionFailedListener connectionFailedListener;
@Inject
GoogleApiClient mGoogleApiClient;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.bind(this);
initInjector();
favouritesPresenter.attachView(this);
favouritesPresenter.onCreate();
registerReceiverGPS();
}
@Override
protected void onStart() {
super.onStart();
if (mGoogleApiClient != null){
registerCallbacks(this.mGoogleApiClient);
registerFailedToConnect(this.mGoogleApiClient);
mGoogleApiClient.connect();
}
}
@Override
protected void onStop() {
favouritesPresenter.onStop();
if (mGoogleApiClient != null) {
mGoogleApiClient.unregisterConnectionCallbacks(this.connectionCallbacks);
mGoogleApiClient.unregisterConnectionFailedListener(this.connectionFailedListener);
mGoogleApiClient.disconnect();
}
}
@Override
public void registerCallbacks(GoogleApiClient client){
this.connectionCallbacks = new GoogleApiClient.ConnectionCallbacks() {
@Override
public void onConnected(@Nullable Bundle bundle)
favouritesPresenter.getUserLocAndWeather(); //Call to presenter that initiates the observable chain, actually this comes later after some GPS checks and such, but for easier cohesion
}
@Override
public void onConnectionSuspended(int i) {}
};
client.registerConnectionCallbacks(this.connectionCallbacks);
}