我在运行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"/>

其他回答

使用以下代码禁用严格模式:

if (android.os.Build.VERSION.SDK_INT > 9) {
    StrictMode.ThreadPolicy policy = 
        new StrictMode.ThreadPolicy.Builder().permitAll().build();
    StrictMode.setThreadPolicy(policy);
}

不建议使用AsyncTask接口。

两种方法的完整代码

谷歌不推荐Android 11中的Android AsyncTask API。

即使在主活动之外创建线程类,只要在main中调用它,也会得到相同的错误。调用必须在一个可运行的线程内,但如果您需要一些异步代码在后台执行或稍后在这里执行,您可以查看Kotlin和Java的一些替代方案:

*https://stackoverflow.com/questions/58767733/android-asynctask-api-deprecating-in-android-11-what-are-the-alternatives*

特别适合我的是mayank1513对上面链接中可运行线程的Java8实现的回答。代码如下:

new Thread(() -> {
        // do background stuff here
        runOnUiThread(()->{
            // OnPostExecute stuff here
        });
    }).start();

但是,您可以先在代码的某个部分定义线程,然后在其他地方启动它,如下所示:

线程定义

Thread thread = new Thread(() -> {
            // do background stuff here
            runOnUiThread(()->{
                // OnPostExecute stuff here
            });
        });

线程调用

thread.start();

我希望这可以让人省去看到不推荐的AsyncTask时的头疼。

这在Android 3.0及更高版本中发生。从Android 3.0及更高版本开始,他们限制在主线程/UI线程中运行网络操作(访问Internet的功能)(活动中创建和恢复方法产生的内容)。

这是为了鼓励在网络操作中使用单独的线程。有关如何正确执行网络活动的详细信息,请参阅AsyncTask。

在Android上,网络操作不能在主线程上运行。您可以使用线程、异步任务(短期运行任务)和服务(长期运行任务)来执行网络操作。

截至2018年,我建议在Kotlin中使用RxJava进行网络获取。下面是一个简单的例子。

Single.fromCallable {
        // Your Network Fetching Code
        Network.fetchHttp(url) 
    }
    .subscribeOn(Schedulers.io())
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe {
        // What you need to do with your result on the view 
        result -> view.updateScreen(result) 
    }