简体   繁体   English

GoogleApiClient不得为空[Awareness API]

[英]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. 我试图找出为什么应用程序从诸如设备睡眠或切换其他程序之类的后台状态返回后,Google Play服务为什么会因nullpointerexception崩溃的原因。 Sometimes Google Play Services gives the crash popup on application start. 有时Google Play服务会在应用程序启动时弹出崩溃弹出窗口。 So I assume the problem lies somewhere on the path to the service since there is where the threading occurs with rxjava. 因此,我认为问题出在服务路径上的某个地方,因为rxjava在哪里发生线程。

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

GoogleApiClient is injected as a @Singleton. GoogleApiClient作为@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. 该应用程序继续正常运行,没有任何问题,但是“ Google Play服务弹出窗口”令人讨厌 ,我看到一个对getuserLocAndWeather()的调用返回了与Google Play服务的连接断开,但是在下一个调用中它立即返回了一个有效的结果。

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. MainActivity和GoogleApiService中的实际对象引用永远不会为null,引用始终相同,例如com.google.android.gms.internal.zzqd@a768e13,并且在调用时始终保持连接。

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. 我的服务类别:,无论Google Play服务是否崩溃,客户端在try {}中的输出始终为true。

Client: com.google.android.gms.internal.zzqd@3c738f4e Connected? 客户端:com.google.android.gms.internal.zzqd@3c738f4e是否已连接? :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. 我要做的第一件事是 onStart()中的零件移到onResume()中,以确保它们在用户需要它们时就在那,因为那是在显示App之前调用的最后一个方法。 Same thing with onStop() to onPause(). 与onStop()和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. 我假设Awareness.SnapshotApi.getWeather(client)可能是您的代码开始调用com.google.android.gms:73 ,因此将NPE添加到您的catch语句中实际上是值得的,尤其是因为它是断断续续的。

& now a Note to others: I only suggest this because I see that they're using rxJava with some skill; 现在给其他人的注释:我之所以建议这样做,是因为我发现他们使用rxJava具有一定的技巧; look at the terseness of the two monad declarations in their GoogleApiClient ! 看看他们的GoogleApiClient中两个monad声明的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. 他们所需要做的就是一个retryWhen(Func2<Integer, Throwable, Boolean>)并在给定throwable instanceof NPEthrowable instanceof NPE和计数为1(可能为2 retryWhen(Func2<Integer, Throwable, Boolean>) ,评估所述功能参数中的谓词为true。进一步的NPE(使进一步的异常行为变得明显)可能会满足坚定,受过良好教育的声音,告诉我们永远也不会抓住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; 我要说的是,您可以这样做,因为monad create()方法中没有一堆代码希望它可能是副作用的一部分。 however @buddhabath, I notice those create() s can generate exactly the subscription side effect you are describing--right on the subscription thread, actually: 但是@buddhabath,我注意到那些create()可以完全生成您正在描述的订阅副作用-实际上在订阅线程上:

You "should be" catching whatever comes out of those try s and sending it down the rxChooChoo; 你“应该是” 醒目无论出来的那些try小号和发送下来的rxChooChoo; the extant onError shouldn't be a problem b/c only one will be called per evaluation. 现存的onError不应成为问题b / c,每次评估将只调用一个。 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. 只需将catch的参数指向Subscriber.onError(), 除这些异常外 ,任何Throwable都将保留在轨道中,也许就像我在Kermit上面描述的轨道一样,但是泄漏create()是您的错误。

tl;dr: Manually defining monads with create() deserves one's full attention; tl; dr:用create()手动定义monad值得您全神贯注; 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. 我自己,很高兴能从Emitter中发现新的东西,也很高兴看到Observable.Generate在rxJava 2.0的菜单上。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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