[英]GoogleApiClient must not be null [Awareness API]
我试图找出为什么应用程序从诸如设备睡眠或切换其他程序之类的后台状态返回后,Google Play服务为什么会因nullpointerexception崩溃的原因。 有时Google Play服务会在应用程序启动时弹出崩溃弹出窗口。 因此,我认为问题出在服务路径上的某个地方,因为rxjava在哪里发生线程。
Note: I Inject GoogleApiClient in both MainActivity (field injection) and in GoogleApiService (constructor injection).
GoogleApiClient作为@Singleton注入。 我一直在尝试追踪为什么这种情况现在已经发生了几个小时而没有任何进展,感谢任何帮助。
该应用程序继续正常运行,没有任何问题,但是“ Google Play服务弹出窗口”令人讨厌 ,我看到一个对getuserLocAndWeather()的调用返回了与Google Play服务的连接断开,但是在下一个调用中它立即返回了一个有效的结果。
MainActivity和GoogleApiService中的实际对象引用永远不会为null,引用始终相同,例如com.google.android.gms.internal.zzqd@a768e13,并且在调用时始终保持连接。
跟踪:
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)
我的服务类别:,无论Google Play服务是否崩溃,客户端在try {}中的输出始终为true。
客户端:com.google.android.gms.internal.zzqd@3c738f4e是否已连接? :真正
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());
});
}
主持人:
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,"","");}
);
}
用例:
public class GetUserLocationWeatherUseCase implements Usecase<UserCurrentInfo> {
IGoogleApi apihelper;
public GetUserLocationWeatherUseCase(IGoogleApi helper){
this.apihelper = helper;
}
@Override
public Observable<UserCurrentInfo> execute(){
return apihelper.getLocationWeather();
}
主要活动中的用法:
@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()方法中实现。
我要做的第一件事是将 onStart()中的零件移到onResume()中,以确保它们在用户需要它们时就在那,因为那是在显示App之前调用的最后一个方法。 与onStop()和onPause()相同。 但这似乎是一个过于简单的答案。
我假设Awareness.SnapshotApi.getWeather(client)
可能是您的代码开始调用com.google.android.gms:73
,因此将NPE添加到您的catch语句中实际上是值得的,尤其是因为它是断断续续的。
现在给其他人的注释:我之所以只建议这样做,是因为我发现他们使用rxJava具有一定的技巧; 看看他们的GoogleApiClient中两个monad声明的GoogleApiClient
! 他们所需要做的就是一个retryWhen(Func2<Integer, Throwable, Boolean>)
并在给定throwable instanceof NPE
可throwable instanceof NPE
和计数为1(可能为2 retryWhen(Func2<Integer, Throwable, Boolean>)
,评估所述功能参数中的谓词为true。进一步的NPE(使进一步的异常行为变得明显)可能会满足坚定,受过良好教育的声音,告诉我们永远也不会抓住NPE。 ...或者,如果调整那些坚定,受过良好教育的声音的声音听起来像是个好时机,那么他们可以按类型过滤出更多的异常,同时对这种可预测的事件提供适当的下游反应 ...
我要说的是,您可以这样做,因为monad create()
方法中没有一堆代码希望它可能是副作用的一部分。 但是@buddhabath,我注意到那些create()
可以完全生成您正在描述的订阅副作用-实际上在订阅线程上:
你“应该是” 醒目无论出来的那些try
小号和发送下来的rxChooChoo; 现存的onError
不应成为问题b / c,每次评估将只调用一个。 只需将catch的参数指向Subscriber.onError(), 除这些异常外 ,任何Throwable都将保留在轨道中,也许就像我在Kermit上面描述的轨道一样,但是泄漏create()
是您的错误。
tl; dr:用create()
手动定义monad值得您全神贯注; 这是现实世界,非常“势在必行”; 实际上,那里可能发生任何事情。 我自己,很高兴能从Emitter中发现新的东西,也很高兴看到Observable.Generate在rxJava 2.0的菜单上。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.