【问题标题】:NetworkOnMainThreadException using rxjava androidNetworkOnMainThreadException 使用 rxjava android
【发布时间】:2018-12-15 02:57:30
【问题描述】:

我正在使用 rxjava2 进行网络调用,我感到很害怕。 NetworkOnMainThreadException。我正在使用 fromCallable,它应该将调用推迟到订阅。这是我的代码:

override fun getMovie(movieId: Int) {
    Single.fromCallable{getMovieFromAPI(movieId)}
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .doOnError { throwable -> Log.e(TAG, throwable.message) }
            .unsubscribeOn(Schedulers.io())
            .subscribe(object : SingleObserver<ArrayList<Movie>> {
                override fun onSuccess(t: ArrayList<Movie>) {
                    view?.get()?.setMoviesActivityUIElements(t)
                }

                override fun onSubscribe(d: Disposable) {
                    compositeDisposable.add(d)
                }

                override fun onError(e: Throwable) {
                    Log.e(TAG,e.localizedMessage)
                    e.printStackTrace()

                }

            })
}

还有我的 getMovieFromAPI(movieID):

fun getMovieFromAPI(movieId : Int) : ArrayList<Movie> {

    val URL = Constants.API_URL + "/" + movieId
    val httpURLConnection: HttpURLConnection
    var movieList: ArrayList<Movie> = ArrayList()

    val requestParam = RequestParam(Constants.GET_METHOD, URL)
    requestParam.addParam(Constants.PARAM_LANGUAGE, Constants.PARAM_ENGLISH)
    requestParam.addParam(Constants.PARAM_API_KEY, Constants.APIKey)

    try {
        httpURLConnection = requestParam.setUpConnection()
        val statusCode = httpURLConnection.responseCode // <--error happens here
        val stringBuilder = Movie.getResponse(httpURLConnection)
        when (statusCode) {
            HttpURLConnection.HTTP_OK -> movieList = Movie.parseMovie(stringBuilder.toString())

            HttpURLConnection.HTTP_NOT_FOUND, HttpURLConnection.HTTP_UNAUTHORIZED -> {
                view?.get()?.showError(statusCode)
                errorMessage = Movie.errorMessage
                movieList.clear()
            }
            else -> {
                view?.get()?.showError(-1)
                movieList.clear()
            }
        }
        httpURLConnection.disconnect()


    } catch (e: IOException) {
        e.printStackTrace()
    } catch (e: JSONException) {
        e.printStackTrace()
    }

    return movieList
}

为什么会这样?我看了this question 并没有回答我的问题。

编辑 在getMovieFromAPI的第一行添加Log.e(TAG,Thread.currentThread().toString()),

打印:线程[main,5,main]

07-06 06:49:55.882 1897-1897/com.webnation.imdb E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.webnation.imdb, PID: 1897
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.webnation.imdb/com.webnation.imdb.MovieDetailActivity}: android.os.NetworkOnMainThreadException
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2778)
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2856)
    at android.app.ActivityThread.-wrap11(Unknown Source:0)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1589)
    at android.os.Handler.dispatchMessage(Handler.java:106)
    at android.os.Looper.loop(Looper.java:164)
    at android.app.ActivityThread.main(ActivityThread.java:6494)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)
 Caused by: android.os.NetworkOnMainThreadException
    at android.os.StrictMode$AndroidBlockGuardPolicy.onNetwork(StrictMode.java:1450)
    at java.net.Inet6AddressImpl.lookupHostByName(Inet6AddressImpl.java:102)
    at java.net.Inet6AddressImpl.lookupAllHostAddr(Inet6AddressImpl.java:90)
    at java.net.InetAddress.getAllByName(InetAddress.java:787)
    at com.android.okhttp.Dns$1.lookup(Dns.java:39)
    at com.android.okhttp.internal.http.RouteSelector.resetNextInetSocketAddress(RouteSelector.java:175)
    at com.android.okhttp.internal.http.RouteSelector.nextProxy(RouteSelector.java:141)
    at com.android.okhttp.internal.http.RouteSelector.next(RouteSelector.java:83)
    at com.android.okhttp.internal.http.StreamAllocation.findConnection(StreamAllocation.java:174)
    at com.android.okhttp.internal.http.StreamAllocation.findHealthyConnection(StreamAllocation.java:126)
    at com.android.okhttp.internal.http.StreamAllocation.newStream(StreamAllocation.java:95)
    at com.android.okhttp.internal.http.HttpEngine.connect(HttpEngine.java:281)
    at com.android.okhttp.internal.http.HttpEngine.sendRequest(HttpEngine.java:224)
    at com.android.okhttp.internal.huc.HttpURLConnectionImpl.execute(HttpURLConnectionImpl.java:461)
    at com.android.okhttp.internal.huc.HttpURLConnectionImpl.getResponse(HttpURLConnectionImpl.java:407)
    at com.android.okhttp.internal.huc.HttpURLConnectionImpl.getResponseCode(HttpURLConnectionImpl.java:538)
    at com.android.okhttp.internal.huc.DelegatingHttpsURLConnection.getResponseCode(DelegatingHttpsURLConnection.java:105)
    at com.android.okhttp.internal.huc.HttpsURLConnectionImpl.getResponseCode(Unknown Source:0)
    at com.webnation.imdb.presenter.MovieDetailPresenter.getMovieFromAPI(MovieDetailPresenter.kt:76)
    at com.webnation.imdb.MovieDetailActivity.onCreate(MovieDetailActivity.kt:73)
    at android.app.Activity.performCreate(Activity.java:7009)
    at android.app.Activity.performCreate(Activity.java:7000)
    at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1214)
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2731)

【问题讨论】:

  • 除非Schedulers.io() 被重写为主线程调度程序,否则它不应抛出该异常。你确定你提供了实际的代码,而你实际上又没有this了吗?
  • 是的,我展示了实际代码。
  • 是的,就是这样,我调用了错误的方法。谢谢你的帮助。发布答案,我会接受。
  • Rx,Kotlin,原始 HttpUrlConnection。奇怪的项目:D 但在后台线程上触摸视图层次结构似乎是个坏主意

标签: android rx-java2 networkonmainthread


【解决方案1】:

在主线程上运行网络调用从来都不是一个好主意。而是将其作为异步任务运行:类似于

private class MyTask extends AsyncTask<Void, Void, Integer> {

    String textResult;

    private final ProgressDialog mProgress = new ProgressDialog(SendMessageActivity.this);

    String value;
    int value2;

    @Override
    public void onPreExecute() {
        mProgress.setMessage("Processing...");
        mProgress.show();
    }


    @Override
    protected Integer doInBackground(Void... params) {

        val URL = Constants.API_URL + "/" + movieId
val httpURLConnection: HttpURLConnection
var movieList: ArrayList<Movie> = ArrayList()

val requestParam = RequestParam(Constants.GET_METHOD, URL)
requestParam.addParam(Constants.PARAM_LANGUAGE, Constants.PARAM_ENGLISH)
requestParam.addParam(Constants.PARAM_API_KEY, Constants.APIKey)

try {
    httpURLConnection = requestParam.setUpConnection()
    val statusCode = httpURLConnection.responseCode // <--error happens here
    val stringBuilder = Movie.getResponse(httpURLConnection)
    when (statusCode) {
        HttpURLConnection.HTTP_OK -> movieList = Movie.parseMovie(stringBuilder.toString())

        HttpURLConnection.HTTP_NOT_FOUND, HttpURLConnection.HTTP_UNAUTHORIZED -> {
            view?.get()?.showError(statusCode)
            errorMessage = Movie.errorMessage
            movieList.clear()
        }
        else -> {
            view?.get()?.showError(-1)
            movieList.clear()
        }
    }
    httpURLConnection.disconnect()
    }

    @Override
    protected void onPostExecute(Integer result) {


        mProgress.dismiss();

        if (result==200){
            //Put success message here
        }
        else {

        }

        super.onPostExecute(result);
    }

}

然后在你的主线程中调用AsyncTask:

new MyTask().execute();

【讨论】:

  • 这并没有解决问题。
猜你喜欢
  • 2021-03-21
  • 2017-09-15
  • 2016-03-24
  • 2017-10-15
  • 2018-09-11
  • 2021-03-25
  • 2017-09-29
  • 1970-01-01
  • 2016-12-11
相关资源
最近更新 更多