我在运行RssReader的Android项目时出错。

代码:

URL url = new URL(urlToRssFeed);
SAXParserFactory factory = SAXParserFactory.newInstance();
SAXParser parser = factory.newSAXParser();
XMLReader xmlreader = parser.getXMLReader();
RssHandler theRSSHandler = new RssHandler();
xmlreader.setContentHandler(theRSSHandler);
InputSource is = new InputSource(url.openStream());
xmlreader.parse(is);
return theRSSHandler.getFeed();

它显示以下错误:

android.os.NetworkOnMainThreadException

如何解决此问题?


当前回答

注意:AsyncTask在API级别30中已弃用。AsyncTask | Android开发人员

当应用程序尝试在其主线程上执行网络操作时,会引发此异常。在AsyncTask中运行代码:

class RetrieveFeedTask extends AsyncTask<String, Void, RSSFeed> {

    private Exception exception;

    protected RSSFeed doInBackground(String... urls) {
        try {
            URL url = new URL(urls[0]);
            SAXParserFactory factory = SAXParserFactory.newInstance();
            SAXParser parser = factory.newSAXParser();
            XMLReader xmlreader = parser.getXMLReader();
            RssHandler theRSSHandler = new RssHandler();
            xmlreader.setContentHandler(theRSSHandler);
            InputSource is = new InputSource(url.openStream());
            xmlreader.parse(is);

            return theRSSHandler.getFeed();
        } catch (Exception e) {
            this.exception = e;

            return null;
        } finally {
            is.close();
        }
    }

    protected void onPostExecute(RSSFeed feed) {
        // TODO: check this.exception
        // TODO: do something with the feed
    }
}

如何执行任务:

在MainActivity.java文件中,可以在oncreate()方法中添加此行

new RetrieveFeedTask().execute(urlToRssFeed);

不要忘记将其添加到AndroidManifest.xml文件中:

<uses-permission android:name="android.permission.INTERNET"/>

其他回答

RxAndroid是解决这个问题的另一个更好的选择,它让我们省去了创建线程然后在Android UI线程上发布结果的麻烦。

我们只需要指定需要在哪些线程上执行任务,并且所有事情都在内部处理。

Observable<List<String>> musicShowsObservable = Observable.fromCallable(new Callable<List<String>>() {

  @Override
  public List<String> call() {
    return mRestClient.getFavoriteMusicShows();
  }

});

mMusicShowSubscription = musicShowsObservable
  .subscribeOn(Schedulers.io())
  .observeOn(AndroidSchedulers.mainThread())
  .subscribe(new Observer<List<String>>() {

    @Override
    public void onCompleted() { }

    @Override
    public void onError(Throwable e) { }

    @Override
    public void onNext(List<String> musicShows) {
        listMusicShows(musicShows);
    }
});

通过指定(Schedulers.io()),RxAndroid将在不同的线程上运行getFavoriteMusicShows()。通过使用AndroidSchedulers.mainThread(),我们希望在UI线程上观察这个Observable,也就是说,我们希望我们的onNext()回调在UI线程中被调用。

这个问题有两种解决方案。

不要在主UI线程中使用网络调用。为此使用异步任务。在setContentView(R.layout.activity_main)之后,将以下代码写入MainActivity文件:如果(android.os.Build.VERSION.SDK_INT>9){StrictMode.ThreadPolicy policy=new StrictMode.SthreadPolicy.Builder().permitAll().build();StrictMode.setThreadPolicy(策略);}

以及下面的import语句到Java文件中。

import android.os.StrictMode;

实际上,您可以启动一个新线程。我以前有过这个问题,并用这种方法解决了它。

基于网络的操作不能在主线程上运行。您需要在子线程上运行所有基于网络的任务或实现AsyncTask。

这是在子线程中运行任务的方式:

new Thread(new Runnable(){
    @Override
    public void run() {
        try {
            // Your implementation goes here
        } 
        catch (Exception ex) {
            ex.printStackTrace();
        }
    }
}).start();

使用以下代码执行繁重的任务。

// Your package here


import java.util.List;
import org.apache.http.NameValuePair;

import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Context;
import android.os.AsyncTask;
import android.view.View.OnSystemUiVisibilityChangeListener;

public class AsyncRequest extends AsyncTask<String, Integer, String> {

    Context context;
    ProgressDialog pDialog;

    // Three Constructors
    public AsyncRequest(Activity a, String m, List<NameValuePair> p) {
        context = a;
        method = m;
        parameters = p;
    }

    public AsyncRequest(Activity a) {
        this.caller = (OnAsyncRequestComplete) a;
        context = a;
    }

    public String doInBackground(String... urls) {

        //Perform your task here
        return result;
    }

    public void onPreExecute() {
        pDialog = new ProgressDialog(context);
        pDialog.setMessage("Please wait..");
        pDialog.setCancelable(false);
        pDialog.show();
    }

    public void onProgressUpdate(Integer... progress) {
        // You can implement some progressBar and update it in this record.
        //   setProgressPercent(progress[0]);
    }

    public void onPostExecute(String response) {
        if (pDialog != null && pDialog.isShowing()) {
            pDialog.dismiss();
        }
        // Get the result here
    }

    protected void onCancelled(String response) {

        if (pDialog != null && pDialog.isShowing()) {
            pDialog.dismiss();
        }
    }
}