RxAndroid - http connectionandroid.os.NetworkOnMainThreadException

时间:2016-06-17 20:53:44

标签: android rx-java rx-android

我有以下包含网络操作的代码。我在哪里得到众所周知的错误Error in http connectionandroid.os.NetworkOnMainThreadException,该错误非常具有描述性,并在例如here中进行了解释。

我不明白的是,当我明确订阅Scheduler.io()时,错误如何发生在这里。我做错了什么?

ReactiveLocationProvider locationProvider = new ReactiveLocationProvider(mContext);
locationProvider.getLastKnownLocation().subscribeOn(Schedulers.io()).subscribe((location -> {
    // ... unrelated code
    try {
        this.postPing(pingResponse); // <<< this is an http post causing the error
        Log.d(LOG_TAG, "trying to post response");
    } catch (Exception e) {
        e.printStackTrace();
    }
    cursor.close();

编辑:这似乎并非完全无足轻重。这就是我提供额外背景的原因。

上面的代码看起来像这样,并没有使用ReactiveLocationProvider,而是FusedLocationApi

 Location location = LocationServices.FusedLocationApi.getLastLocation(MainActivity.mGoogleApiClient);
                    // ... unrelated code
                    try {
                        this.postPing(pingResponse);
                        Log.d(LOG_TAG, "trying to post response");
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    cursor.close();

从GcmListenerService中运行:

@Override
    public void onMessageReceived(String from, Bundle data) {
        Log.d("GCMListener", "onMessageReceived");
        String action = data.getString("action");
        switch (action) {
            case "getPing":
                requests.getPingObservable()
                        .subscribeOn(Schedulers.io()).retryWhen(
                        errors ->
                                errors
                                        .zipWith(Observable.range(1, 3), (n, i) -> i)
                                        .flatMap(retryCount -> Observable.timer((long) Math.pow(5, retryCount), TimeUnit.SECONDS))
                        ).subscribe((pingsJsonObjectString) -> {
                }, (error) -> error.printStackTrace());
                break;
            default:
                break;
        }
    }

不幸的是,当应用关闭时,GcmListenerService不会收到通知。因此我决定作弊并制造一个警报,以便通过警报触发接收器。

AndroidMainfest.xml我添加了行<category android:name="com.smilingkoala.ping.periodic_wakeup"/>

<!-- The Google Cloud Messaging receiver and services -->
        <receiver
            android:name="com.google.android.gms.gcm.GcmReceiver"
            android:exported="true"
            android:permission="com.google.android.c2dm.permission.SEND">
            <intent-filter>
                <action android:name="com.google.android.c2dm.intent.RECEIVE" />
                <action android:name="com.google.android.c2dm.intent.REGISTRATION" />
                <category android:name="com.smilingkoala.ping" />
                <category android:name="com.smilingkoala.ping.periodic_wakeup"/>
            </intent-filter>
        </receiver>

并在MainActivity.java我致电:

public void startAlarm(Context context) {
    Intent intent = new Intent("com.smilingkoala.ping.periodic_wakeup");
    PendingIntent sender = PendingIntent.getService(context, 0, intent, 0);
    AlarmManager am = (AlarmManager) getSystemService(ALARM_SERVICE);
    am.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
            AlarmManager.INTERVAL_FIFTEEN_MINUTES / 3, AlarmManager.INTERVAL_FIFTEEN_MINUTES, sender);
}

关闭应用程序后重新启动侦听器。 这实际上有效。我收到了一条消息。但是现在我无法访问我在旧代码中使用的MainActivity.mGoogleApiClient。这就是我被迫使用ReactiveLocationProvider的原因。但是现在我无法运行网络代码。

我认为禁止导致此错误。

1 个答案:

答案 0 :(得分:2)

好的,我不是百分百肯定,但让我们试着解释一下(:

如果您在.subscribeOn运算符上阅读documentation,您将看到它定义了将执行Observable 本身(而非订阅者!)的调度程序。您需要使用.observeOn运算符为订阅者显式定义调度程序,否则它将在订阅它的线程上执行。

有关更多详细信息和示例,请查看以下链接: http://www.grahamlea.com/2014/07/rxjava-threading-examples/ http://www.introtorx.com/Content/v1.0.10621.0/15_SchedulingAndThreading.html#SubscribeOnObserveOn

您还可以通过调用Thread.currentThread()来检查和试验线程,以检查代码的执行位置。