[英]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.