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

如何解决此问题?


当前回答

Android Jetpack引入了WorkManager,它解决了Android 8.1(奥利奥)中后台服务限制的问题,并在Android 5.0(棒棒糖)以下使用Alarm Manager,在Lolipop以上使用JobScheduler。

请使用WorkManager在后台线程上运行任务,即使用户关闭应用程序,它也将继续运行。

其他回答

你可以使用Kotlin和Anko。

Kotlin是Android的新官方语言。您可以在这里找到更多信息:适用于Android的Kotlin。

Anko是Android中Kotlin支持的库。GitHub页面上有一些文档。

这个解决方案非常有用,只有@AntonioLeiva编写的几行代码:使用Anko在Android中使用Kotlin运行后台任务(KAD 09)。

doAsync {
    var result = runLongTask()
    uiThread {
        toast(result)
    }
}

虽然很简单,但当您在UI线程上运行后台作业时,就会出现NetworkOnMainThread,因此您必须做的一件事就是在后台运行longTask作业。你可以在Android应用程序中使用此方法和Kotlin与Anko来完成此操作。

spektom的顶级答案非常完美。

如果您正在内联编写AsyncTask,而不是作为类扩展,并且在此基础上,如果需要从AsyncTask中获取响应,可以使用如下的get()方法。

RSSFeed feed = new RetreiveFeedTask().execute(urlToRssFeed).get();

(从他的例子中。)

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

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

不建议使用AsyncTask接口。

两种方法的完整代码

您不能在蜂巢上的UI线程上执行网络I/O。从技术上讲,这在早期版本的Android上是可能的,但这是一个非常糟糕的想法,因为它会导致你的应用停止响应,并可能导致操作系统因你的应用行为不端而杀死你的应用。您需要运行后台进程或使用AsyncTask在后台线程上执行网络事务。

Android开发者网站上有一篇关于“无痛苦线程”的文章,这是一篇很好的介绍,它将为您提供比这里实际提供的答案更深入的答案。

将代码放入:

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

Or:

class DemoTask extends AsyncTask<Void, Void, Void> {

    protected Void doInBackground(Void... arg0) {
        //Your implementation
    }

    protected void onPostExecute(Void result) {
        // TODO: do something with the feed
    }
}