RxAndroid - http connectionandroid.os.NetworkOnMainThreadException 错误
RxAndroid - Error in http connectionandroid.os.NetworkOnMainThreadException
我有以下包含网络操作的代码。我在哪里得到众所周知的错误 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
。但是现在我无法 运行 网络代码。
我假设我所做的导致此错误的事情是被禁止的。
好吧,我不是 100% 确定,但让我们试着解释一下 (:
如果你在 .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()
来调试和试验线程,以检查您的代码在何处执行。
我有以下包含网络操作的代码。我在哪里得到众所周知的错误 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
。但是现在我无法 运行 网络代码。
我假设我所做的导致此错误的事情是被禁止的。
好吧,我不是 100% 确定,但让我们试着解释一下 (:
如果你在 .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()
来调试和试验线程,以检查您的代码在何处执行。