简体   繁体   中英

GoogleApiClient must not be null [Awareness API]

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);
}

在您的onStart()方法中,仅连接googleApiClient的对象,其余的东西将在onCreate()方法中实现。

First thing I'd go for is move the part in onStart() to onResume(), to make sure they are there when the user needs them, as that is the last method called before the App is shown. Same thing with onStop() to onPause(). But somehow that would seem like a too simple an answer.

I assume that Awareness.SnapshotApi.getWeather(client) is probably where your code begins the call to com.google.android.gms:73 , so adding the NPE to your catch statement actually might be worth, particularly as it's intermittent.

& now a Note to others: I only suggest this because I see that they're using rxJava with some skill; look at the terseness of the two monad declarations in their GoogleApiClient ! All they need to do is a retryWhen(Func2<Integer, Throwable, Boolean>) and evaluate the predicate in said functional parameter to be true given throwable instanceof NPE and count of 1, maybe 2. Before the zip, I think logging and releasing further NPEs--making further anomalous behavior apparent--might satisfy the firm, educated voices telling us never, ever to catch an NPE. ...or, if tweaking the noses of those firm, educated voices sounds like a good time, they could filter out further Exceptions by type while providing appropriate downstream reactions to this predictable event...

hmmmmm柯密特S饮茶

I was about to say that you can do that because there isn't a bunch of code hanging around in the monad create() methods wishing it could be part of a side effect; however @buddhabath, I notice those create() s can generate exactly the subscription side effect you are describing--right on the subscription thread, actually:

You "should be" catching whatever comes out of those try s and sending it down the rxChooChoo; the extant onError shouldn't be a problem b/c only one will be called per evaluation. Just point the parameter of the catch at subscriber.onError() and any Throwable- excepting these Exceptions -will be kept within the tracks, perhaps like the tracks I described above the Kermit, but that leaking create() is your bug.

tl;dr: Manually defining monads with create() deserves one's full attention; it's the real world, very "imperative"; literally anything could happen in there. Myself, I just now had the pleasure of discovering the new fromEmitter and also am glad to see Observable.Generate on the menu for rxJava 2.0.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM