【问题标题】:GoogleApiClient must not be null [Awareness API]GoogleApiClient 不能为空 [Awareness API]
【发布时间】:2016-07-07 11:45:40
【问题描述】:

我试图找出为什么在应用程序从设备睡眠或切换其他程序等后台状态返回后,Google Play 服务会因空指针异常而崩溃。有时 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 中的实际对象引用永远不会为空,引用始终相同,如 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)

我的服务类:,客户端的 try{} 中的打印输出始终为:true,无论 google play 服务是否崩溃。

客户端: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();

}

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

【问题讨论】:

  • 如果你在你的 onCreate() 上添加它会怎么样 if (GoogleApiClient== null) { GoogleApiClient= new GoogleApiClient.Builder(this) .addConnectionCallbacks(this) .addOnConnectionFailedListener(this) .addApi(LocationServices. API) .build(); }
  • @Tony 这已经在注入器中发生了,从我所看到的来看,对象本身实际上永远不会为空,它在 MainActivity 和 GoogleApiService 中始终具有相同的引用
  • 程序究竟什么时候崩溃?在哪个函数上?
  • @Tony 程序本身永远不会崩溃,只有堆栈跟踪中提供的 Google Play 服务,这就是为什么我在修复它时遇到了这么多麻烦。然而,崩溃很可能发生在从 GoogleApiService 获取数据的过程中。它的模式也很随机,有时播放服务在应用程序启动时崩溃,但最常见的是在后台运行之后。有时它不会在进入后台后第一次崩溃,这使得它很难定位。
  • 从来没有注射过,所以我帮不了你,你试过不注射吗?

标签: android dependency-injection rx-java google-api-client dagger-2


【解决方案1】:

在你的 onStart() 方法中只连接 googleApiClient 的对象,其余的东西在 onCreate() 方法中实现。

【讨论】:

    【解决方案2】:

    我首先要做的是move onStart() 到 onResume() 中的部分,以确保当用户需要它们时它们就在那里,因为这是显示应用程序之前调用的最后一个方法。与 onStop() 到 onPause() 相同。但不知何故,这似乎是一个过于简单的答案。

    【讨论】:

    • 是的,它在 onResume() 中开始,然后我开始移动它以查看它为什么会这样,但是我只是尝试将调用绑定到一个按钮而不是运行它onResume() 看看是否能解决问题。
    • 将调用(异步)绑定到按钮始终是 IMO 的好主意;如果这成为您的解决方案,buddhabath,请考虑将另一个线程放在 viewDetach 上。使用 DI 对你有好处;喜欢它。
    【解决方案3】:

    我认为Awareness.SnapshotApi.getWeather(client) 可能是您的代码开始调用com.google.android.gms:73 的地方,因此将 NPE 添加到您的 catch 语句实际上可能是值得的,尤其是因为它是间歇性的。

    & 现在给其他人的注意事项:我建议这样做,因为我看到他们使用 rxJava 有一定的技巧;看看GoogleApiClient 中两个 monad 声明的简洁性!他们需要做的只是retryWhen(Func2&lt;Integer, Throwable, Boolean&gt;) 并在给定throwable instanceof NPE 和计数为 1,可能为 2 的情况下评估所述功能参数中的谓词为真。在 zip 之前,我认为记录和释放进一步的 NPE——使进一步的异常行为显然——可能会满足那些坚定、有教养的声音,告诉我们永远、永远不要抓住 NPE。 ...或者,如果调整那些坚定、受过教育的声音听起来不错,他们可以按类型过滤更多的异常,同时为这个可预测的事件提供适当的下游reactions...

    我正要说你可以这样做,因为 monad create() 方法中没有一堆代码希望它可能是副作用的一部分;但是@buddhabath,我注意到那些create()s 可以生成您所描述的订阅副作用——实际上就在订阅线程上:

    你“应该”catching whatever comes out of those trys 并将其发送到 rxChooChoo;现存的onError 不应该是问题 b/c 每次评估只会调用一个。 只需将 catch 的参数指向subscriber.onError(),任何 Throwable-excepting these Exceptions-都将保留在轨道内,可能就像我在 Kermit 上面描述的轨道一样,但泄漏 create() 是你的错误。

    tl;dr:使用create() 手动定义 monad 值得全神贯注;这是现实世界,非常“势在必行”;从字面上看,那里可能发生任何事情。我自己,刚刚有幸发现了新的 fromEmitter,也很高兴在 rxJava 2.0 的菜单上看到 Observable.Generate

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多