代码之家  ›  专栏  ›  技术社区  ›  Kristy Welsh

使用rxjava android的NetworkOnMainThreadException

  •  1
  • Kristy Welsh  · 技术社区  · 6 年前

    我用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 但它不能回答我的问题。

    编辑 添加Log.e(标签,线程.currentThread().toString())在getMovieFromAPI的第一行,

    打印:线程[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)
    
    1 回复  |  直到 6 年前
        1
  •  -2
  •   C-Spydo    6 年前

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

    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();