【发布时间】: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