2

Ich versuche herauszufinden, warum die Google Play-Dienste mit einer Null-Null-Erkennung abstürzen, nachdem die Anwendung aus einem Hintergrundzustand wie Ruhezustand des Geräts oder anderen Programmen zurückkehrt. Manchmal gibt Google Play-Dienste das Crash-Popup beim Start der Anwendung. Ich nehme also an, dass das Problem irgendwo auf dem Pfad zum Dienst liegt, da dort das Threading mit rxjava stattfindet.GoogleApiClient muss nicht null sein [Awareness-API]

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

GoogleApiClient wird als @Singleton injiziert. Ich habe versucht herauszufinden, warum das jetzt stundenlang ohne Fortschritt geschieht, jede Hilfe wird geschätzt.

Die Anwendung weiterhin ohne Probleme arbeiten, die „Google Play-Dienste Pop-up“ ist ärgerlich, wenn, ich einen Anruf zu getuserLocAndWeather sehen() return Verbindung verloren Play-Dienste Google, aber es gibt sofort ein gültiges Ergebnis in der nächste Anruf.

Der eigentliche Objektreferenz in MainActivity und GoogleApiService ist nie Null, die Referenz ist immer die gleiche, wie [email protected] und immer verbunden, wenn der Anruf getätigt wird.

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) 

Meine Service-Klasse :, der Druck im try out {} für die Kunden immer ist: true, unabhängig davon, ob Google-Dienste Abstürze spielen oder nicht.

Kunde: [email protected] Verbunden? wahr

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

Moderator:

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

} 

Verwendung 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); 
} 
+0

was, wenn Sie diese auf Ihrem onCreate() hinzufügen if (GoogleApiClient == null) { GoogleApiClient = new GoogleApiClient.Builder (this) .addConnectionCallbacks (this) .addOnConnectionFailedListener (this) .addApi (LocationServices .API) .build(); } –

+0

@Tony Das passiert schon im Injektor, das Objekt selbst ist eigentlich nie Null von dem, was ich sehen konnte, es hat immer die gleiche Referenz in MainActivity und GoogleApiService – buddhabath

+0

, wenn genau das Programm abstürzt? –

Antwort

1

In Ihrem onStart() -Methode nur das Objekt googleApiClient verbinden und die übrigen dinge ich mplement in der Methode onCreate().

1

Das erste, was ich gehen würde, ist move der Teil in onStart() zu onResume(), um sicherzustellen, dass sie da sind, wenn der Benutzer sie benötigt, da das die letzte Methode ist, bevor die App angezeigt wird. Das Gleiche gilt für onStop() zu onPause(). Aber irgendwie scheint das eine zu einfache Antwort zu sein.

+0

Ja, es war in onResume(), bevor ich anfing, es zu verschieben, um zu sehen, warum es sich so verhielt, aber ich werde nur versuchen, den Aufruf an eine Schaltfläche zu binden, anstatt es in onResume() auszuführen, um zu sehen, ob löst das Problem. – buddhabath

+0

Verbinde den Anruf - asynchron - zu einer Schaltfläche ist _always_ eine gute Idee IMO; Wenn das zu einer Lösung wird, buddhabath, ziehe in Betracht, den anderen Thread auf viewDetach zu löschen. Gut für dich, wenn du DI benutzt; Liebe es. –

1

Ich nehme an, dass Awareness.SnapshotApi.getWeather(client) ist wahrscheinlich, wo Ihr Code beginnt den Aufruf an com.google.android.gms:73, so das Hinzufügen der NPE zu Ihrem catch-Anweisung tatsächlich wert sein könnte, insbesondere da es intermittierend ist.

& nun ein Hinweis auf andere: Ich nur vorschlagen, weil ich sehe, dass sie verwenden rxJava mit etwas Geschick; Schau dir die Kürze der beiden Monad-Deklarationen in ihrer GoogleApiClient an! Alles, was sie tun müssen, ist ein retryWhen(Func2<Integer, Throwable, Boolean>) und bewerten Sie das Prädikat in diesem funktionalen Parameter als gegeben throwable instanceof NPE und zählen von 1, vielleicht 2. Vor der Zip denke ich Protokollierung und Freigabe weiterer NPEs - weitere anomale Verhalten offensichtlich machen - könnte Befriedigen Sie die Firma, gebildete Stimmen, die uns sagen, niemals eine NPE zu fangen. ...oder, wenn die Nasen jener Firma zwicken, gebildeten Stimmen wie eine gute Zeit klingt, könnten sie weitere Ausnahmen nach Art herauszufiltern, während entsprechende Downstream reactions auf diese vorhersehbare Ereignis bietet ...

hmmmmm Kermit Sipping Tea

Ich wollte zu sagen, dass Sie das tun können, weil es nicht einen Haufen Code gibt, der in den Monaden create() Methoden sich wünscht, könnte es ein Teil eines Nebeneffektes sein; jedoch @buddhabath, merke ich diese create() s genau Wirkung des Bezugs Seite generieren können Sie beschreiben - direkt am Abonnement-Thread, eigentlich:

Sie „sollte“ catching whatever comes out of those trys und es auf die rxChooChoo zu senden; die vorhandene onError sollte kein Problem sein, b/c wird nur eine pro Auswertung aufgerufen. Zeigen Sie einfach den Parameter des Catch bei subscriber.onError() und alle Throwable-excepting these Exceptions -wird in den Spuren gehalten werden, vielleicht wie die Spuren, die ich oben über die Kermit beschrieben, aber das Leck create() ist Ihr Fehler.

tl; dr: Manuelles Definieren von Monaden mit create() verdient die volle Aufmerksamkeit; es ist die reale Welt, sehr "Imperativ"; dort könnte buchstäblich alles passieren. Ich selbst hatte gerade das Vergnügen, den neuen fromEmitter zu entdecken und freue mich auch, Observable.Generate auf der Speisekarte für rxJava 2.0 zu sehen.

Verwandte Themen