2

Я пытаюсь выяснить, почему службы Google Play рушится с помощью nullpointerexception после того, как приложение возвращается из состояния фона, такого как спящий режим устройства или для переключения другой программы. Иногда службы Google Play вызывают всплывающее окно при запуске приложения. Поэтому я предполагаю, что проблема лежит где-то на пути к сервису, так как там происходит потоки с rxjava.GoogleApiClient не должен быть нулевым [API осведомленности]

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

GoogleApiClient вводится как @Singleton. Я пытаюсь проследить, почему это происходит в течение нескольких часов без прогресса, любая помощь оценивается.

Приложение продолжает работать без каких-либо проблем, то «Google Play Services всплывающего окна» это раздражает, хотя, я вижу один вызов getuserLocAndWeather() возвращение утраченного подключение к Google Play услуги, но она немедленно возвращает действительный результат следующий звонок.

Фактическая ссылка на объект в MainActivity и GoogleApiService никогда не является нулевой, ссылка всегда такая же, как [email protected] и всегда подключается при вызове.

Трассировка:

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 аварии или нет.

Клиент: [email protected] Подключен? : Правда

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

} 

Использование в 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

что, если вы добавите это на OnCreate() если (GoogleApiClient == NULL) { GoogleApiClient = новый GoogleApiClient.Builder (это) .addConnectionCallbacks (это) .addOnConnectionFailedListener (это) .addApi (LocationServices .API) .build(); } –

+0

@Tony Что уже происходит в инжекторе, сам объект никогда не является нулевым из того, что я мог видеть, он всегда имеет такую ​​же ссылку в MainActivity и GoogleApiService – buddhabath

+0

, когда именно программа сработает? –

ответ

1

В вашем OnStart() метод только подключения объекта в GoogleApiClient и остальные вещи я mplement в методе onCreate().

1

Первое, что я хотел бы сделать, это: move часть в onStart() to onResume(), чтобы убедиться, что они есть там, где пользователь нуждается в них, поскольку это последний метод, который вызывается до того, как приложение будет показано. То же самое с onStop() на onPause(). Но почему-то это казалось бы слишком простым ответом.

+0

Да, это было в onResume(), прежде чем я начал перемещать его, чтобы понять, почему он так поступил, но я просто попытаюсь привязать вызов к кнопке, а не запустить его в onResume(), чтобы увидеть, решает проблему. – buddhabath

+0

Привязка вызова - асинхронно - к кнопке - всегда _ хорошая идея ИМО; если это станет решением yr, buddhabath, подумайте о том, чтобы удалить другую нить в viewDetach. Хорошо, что вы используете DI; любить это. –

1

Я предполагаю, что Awareness.SnapshotApi.getWeather(client), вероятно, там, где ваш код начинает звонок до com.google.android.gms:73, поэтому добавление NPE к вашему заявлению на вылов фактически может стоить, особенно если оно прерывисто.

& теперь примечание для других: I только предлагайте это, потому что я вижу, что они используют rxJava с некоторым умением; посмотрите на краткость двух заявлений монады в их GoogleApiClient! Все, что им нужно сделать, это retryWhen(Func2<Integer, Throwable, Boolean>) и оценить предикат в указанном функциональном параметре, чтобы он был истинным, учитывая значение throwable instanceof NPE и количество 1, может быть 2. До начала zip я думаю, что регистрация и освобождение других NPE - делая дальнейшее аномальное поведение очевидным - может удовлетворить твердые, образованные голоса, которые никогда нам не позволяют поймать NPE. ...или, если настройки носов тех фирмы, образованные голоса звучат как хорошее время, они могли бы отфильтровать дополнительные исключения по типу, обеспечивая соответствующий потоку reactions к этому событию предсказуемого ...

hmmmmm Kermit Sipping Tea

Я собирался сказать, что вы можете это сделать, потому что в монаде не существует куча кода, который может быть частью побочного эффекта; Однако @buddhabath, я замечаю эти create() s может генерировать точно подписки побочный эффект вы описываете - прямо на подписной нить, на самом деле:

Вы «должны быть» catching whatever comes out of those trys и отправить его вниз rxChooChoo; существующий onError не должен быть проблемой. b/c будет вызываться только одна оценка. Просто укажите параметр catch на signer.onError(), и любой Throwable-excepting these Exceptions - будет сохранен в дорожках, возможно, как треки, описанные выше Kermit, но это утечка create() - ваша ошибка.

tl; dr: Вручную определяющие монады с create() заслуживают полного внимания; это реальный мир, очень «императив»; буквально все могло случиться там. Сам я только что получил удовольствие от знакомства с новым издателем, а также рад видеть Observable.Generate в меню для rxJava 2.0.

Смежные вопросы