GoogleApiClient must not be null [Awareness API]

I’m trying to find out why the Google Play service crashes with a nullpointerexception error after the application returns from a background state such as device hibernation or to switch another program. Sometimes Google Play services pop up when the application starts. Therefore, I suppose that the problem lies somewhere on the way to the service, since there flows with rxjava there.

Note: I Inject GoogleApiClient in both MainActivity (field injection) and in GoogleApiService (constructor injection). 

GoogleApiClient is introduced as @Singleton. I tried to trace why this happens for several hours without progress, any help was appreciated.

The application continues to work without any problems, the "Google Play Apps pop-up" is annoying, but . I see that one call to getuserLocAndWeather () returns a lost connection to Google Play services, but it immediately returns a valid result on the next call.

The actual link to the object in MainActivity and GoogleApiService is never null, the link is always the same as com.google.android.gms.internal.zzqd@a768e13 and is always connected when called.

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 class of service: printout in try {} for the client always: true, regardless of whether the google play services failed 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()); }); } 

Leading:

 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); } 
+2
source share
3 answers

In your onStart () method, only connect the googleApiClient object, and the rest of the things are implemented in the onCreate () method.

+1
source

The first thing I would like to do is move the part in onStart () to onResume () to make sure they are there when the user needs them, since this is the last method that is called before the application is shown. Same thing with onStop () on onPause (). But for some reason this would seem to be too simple an answer.

+1
source

I assume that Awareness.SnapshotApi.getWeather(client) is probably where your code starts calling com.google.android.gms:73 , so adding NPE to your catch statement may actually be worth it, especially if it is interrupted.

& now a note for others: I offer this only because I see that they use rxJava with some skill; look at the brevity of the two monad statements in their GoogleApiClient ! All they need to do is retryWhen(Func2<Integer, Throwable, Boolean>) and evaluate the predicate in the specified function parameter as true, given the throwable instanceof NPE and quantity 1, maybe 2. Before zip, I think that registering and releasing others NPE - further abnormal behavior obviously can satisfy solid, educated voices that will never let us catch NPE .... or, if tuning the noses of these solid, educated voices sounds like a good time, they can filter out additional exceptions by type, providing for this accordingly Relevant reactions to this predictable event ...

hmmmmm Kermit Sipping Tea

I was going to say that you can do this because there is no heap of code in the create() monad methods, wanting this to be part of a side effect; however @buddhabath, I notice that those create() can generate exactly the side effect of the subscription you are describing, right on the subscription stream:

You should " catch everything that comes out of these try s and send it to rxChooChoo; the existing onError should not be a b / c problem, only one will be called for each evaluation. Just point the catch parameter to subscriber.onError () and any Throwable - with the exception of these exceptions, it will be saved in tracks, possibly like the tracks that I described above Kermit, but this create() leak is your mistake.

tl; dr: Manually defining monads with create() deserve one full attention; it is a real world, very "imperative"; literally anything could happen there. I myself have just enjoyed meeting the new publisher, and am also glad to see Observable.Generate in the menu for rxJava 2.0.

+1
source

Source: https://habr.com/ru/post/1257982/


All Articles