android.os.NetworkOnMainThreadException在android上使用rxjava

时间:2014-12-29 11:23:08

标签: java android rx-java

我在实施rxJava时遇到了问题,以便检查android上是否有互联网连接我这样做:

在我的启动器活动中,我在onCreate中有这个:

AndroidObservable.bindActivity(this,
            Observable.just(Utils.isActiveInternetConnection(Launcher.this)))
            .subscribeOn(Schedulers.newThread())
            .subscribe(new Action1<Boolean>() {
                @Override
                public void call(Boolean aBoolean) {
                    if (aBoolean) {
                        Toast.makeText(Launcher.this, "There is internet connection", Toast.LENGTH_SHORT).show();
                    } else {
                        Toast.makeText(Launcher.this, "There is no internet connection", Toast.LENGTH_SHORT).show();
                    }
                }
            });

我有一个Utils类,它是一个带有静态方法的最终类,observable使用的方法是这样的:

    public static boolean isActiveInternetConnection(Context context) {
    if (isNetworkAvailable(context)) {
        try {
            HttpURLConnection urlc = (HttpURLConnection) (new URL("http://www.google.com").openConnection());
            urlc.setRequestProperty("User-Agent", "Test");
            urlc.setRequestProperty("Connection", "close");
            urlc.setConnectTimeout(1500);
            urlc.connect();
            return (urlc.getResponseCode() == 200);
        } catch (IOException e) {
            Log.e("network", "Error checking internet connection", e);
        }
    } else {
        Log.d("network", "No network available!");
    }
    return false;
}

private static boolean isNetworkAvailable(Context context){
    ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
    NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
    if (null != activeNetwork) {
        return true;
    }
    else {
        return false;
    }
}

我收到android.os.NetworkOnMainThreadException,我无法找到原因,提前谢谢。

4 个答案:

答案 0 :(得分:17)

在调用线程(主线程,在本例中)上立即调用

Observable.just(...)。您的代码实际上只是一个内联版本:

boolean activeConn = Utils.isActiveInternetConnection(Launcher.this);
AndroidObservable.bindActivity(this, 
        Observable.just(activeConn))
        .subscribeOn(...)
        ...

您已经尝试通过拨打subscribeOn()将其从主线程移开 - 但是呼叫已经发生。

我们处理这个问题的方式(我不确定这是最好的方法,但它确实有效)是推迟网络或阻止调用直到订阅发生,设置observable以在正确的线程上运行,然后订阅:

AndroidObservable.bindActivity(this,
        Observable.defer(new Func0<Boolean>() {
            @Override
            public Observable<Observable<Boolean>> call() {
                return Observable.just(Utils.isActiveInternetConnection(Launcher.this));
            }
        })
        .subscribeOn(Schedulers.io())
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(new Action1<Boolean>() {
            @Override
            public void call(Boolean aBoolean) {
                if (aBoolean) {
                    Toast.makeText(Launcher.this, "There is internet connection", Toast.LENGTH_SHORT).show();
                } else {
                    Toast.makeText(Launcher.this, "There is no internet connection", Toast.LENGTH_SHORT).show();
                }
            }
        });

答案 1 :(得分:1)

AdamS是正确的,但是RxJava 2现在提供Observable.fromCallable()来将可观察的操作推迟到订阅。 一个很好的参考: https://caster.io/lessons/fromcallable-converting-slow-methods-into-an-observable/

我的用例中的一些示例代码:

Single.fromCallable(new Callable<Response>() {
        @Override
        public Response call() throws Exception {
            return NetworkGateway.networkRequest();
        }
    })
    .subscribeOn(Schedulers.io())
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe(observer);

答案 2 :(得分:0)

我猜just只是同步调用该方法,因为它需要布尔值并尝试获取它。

我对RxJava感到很沮丧,但你可以尝试这样的事情:

Observable<Boolean> onlineObservable = Observable.create(new Observable.OnSubscribe<Boolean>() {
    @Override
    public void call(Subscriber subscriber) {
        subscriber.onNext(Utils.isActiveInternetConnection(context));
    }
});
onlineObservable.subscribeOn(Schedulers.newThread()).subscribe(result -> {...});

答案 3 :(得分:0)

这是我通过RXAndroid代码从DataBase检索数据:

    Observable.create(new Observable.OnSubscribe<List<GRO_VO>>() {
        @Override
        public void call(Subscriber<? super List<GRO_VO>> subscriber) {

            String jsonIn;
            jsonIn =retrieveDataFromDB();
            Gson gson = new Gson();
            Type listType = new TypeToken<List<GRO_VO>>() {

            }.getType();   
            eventJoinList = gson.fromJson(jsonIn, listType);
            Log.d("RX",jsonIn);
            subscriber.onNext(eventJoinList);
        }
    })

                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Action1<List<GRO_VO>>() {
        @Override
        public void call(List<GRO_VO> eventJoinList) {
            Log.d("RX", ".subscribe");
       recyclerView.setAdapter(new EventJoinAdapter(eventJoinList));
        }
    });

我认为just运算符会立即发出数据,因此它无法通过网络从数据库中检索数据。它非常易于使用,但它只能用于已经在设备内部的数据。

我也有这个问题,就像@Baniares一样,但在我使用create运算符之后,所有问题都消失了......

来自RXJava文档:

  

static <T> Observable<T> create(Observable.OnSubscribe<T> f)   

返回一个Observable,当订阅者订阅它时将执行指定的函数。

使用create运算符可以建立标准流程:

1 .subscribe(...)订阅者(Observer类的子类)启动与Observable的连接。

2 .subscribeOn(Schedulers.io())从RX-ThreadPool收集一个backGround线程

3 .create(...)在某些netWork..etc

期间从服务器检索数据

4 .observeOn(AndroidSchedulers.mainThread())这意味着数据将由UI-Thread

设置

5一旦我们得到数据,我们就可以在.subscribe( )的onNext()方法中设置数据,因为我们让UI-thread完成工作,所以UI-Thread上的数据将被设置在UI上在.observerOn(AndroidSchedulers.mainThread())

请注意,如果使用.create()运算符,则必须在.create()中完成observable,其他运算符如map,flatMap将不会在.create()运算符后执行。

在开始使用RXJava / RXAndroid之前我们必须知道的一个非常重要的概念。 RX是一个基于回调的库,你告诉RX它应该在什么条件下做什么,它调用你的传入函数(或者在JAVA中我可能应该称之为匿名内部类......)来实现你想要的。