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

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

其他回答

您可以将代码的一部分移动到另一个线程中以卸载主线程,并避免获得ANR、NetworkOnMainThreadException、IllegalStateException(例如,无法访问主线程上的数据库,因为它可能会长时间锁定UI)。

你应该根据情况选择一些方法

Java线程或Android HandlerThread:

Java线程只能一次性使用,并在执行其运行方法后死亡。HandlerThread是一个方便的类,用于启动具有looper的新线程。

AsyncTask(API级别30中已弃用)

AsyncTask被设计为围绕线程和处理程序的帮助类,不构成通用线程框架。AsyncTasks最好用于短操作(最多几秒钟)。如果需要让线程长时间运行,强烈建议您使用java.util.concurrent包提供的各种API,如Executor、ThreadPoolExecutor和FutureTask。

由于主线程独占UI组件,因此不可能访问某些视图,这就是为什么Handler会出手相助的原因

[执行器框架]

实现ExecutorService的ThreadPoolExecutor类,该类可以对线程池进行精细控制(例如,核心池大小、最大池大小、保活时间等)ScheduledThreadPoolExecutor-一个扩展ThreadPoolExecuto的类。它可以在给定延迟后或周期性地安排任务。

未来任务

FutureTask执行异步处理,但是,如果结果尚未就绪或处理尚未完成,则调用get()将阻塞线程

异步任务加载器

AsyncTaskLoader,因为它们解决了AsyncTask固有的许多问题

Intent服务

这是Android上长期运行处理的事实选择,一个很好的例子就是上传或下载大型文件。即使用户退出应用程序,上传和下载也可能会继续,并且您当然不想阻止用户在执行这些任务时使用应用程序。

作业调度程序

实际上,您必须使用JobInfo.Builder创建一个服务并创建一个作业,该作业指定了何时运行服务的条件。

RxJava语言

通过使用可观察序列来组合异步和基于事件的程序的库。

花冠(Kotlin)

它的主要要点是,它使异步代码看起来非常像同步代码

在这里、这里、这里和这里阅读更多信息。

永远不要在UI线程上执行任何长时间运行的工作。长时间运行的工作可以是与服务器通信、读取/写入文件等。这些任务应该在后台线程上。这就是创建服务、异步任务和线程的原因。您可以禁用StrictMode,这将防止崩溃。但是,这是绝对不建议的。

我建议您至少在调试模式下利用StrictMode。使用下面的代码获取主线程上减慢应用程序速度的任何问题的日志。

StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
            .detectAll()
            .penaltyLog()
            .build());

您可以设置不同的惩罚:

penaltyLog() // to print log
penaltyDeath() // This will crash you App(so costly penalty)
penaltyDialog() // Show alert when something went lazy on Main thread

这里有更多关于StrictMode的信息:StrictMode|Android开发者。

您也可以使用以下代码使用严格模式来解决此问题。这也是解决这个问题的一个替代方案。

StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);

但最好的做法是使用AsyncTask。

我也有类似的问题。我刚才在活动的oncreate方法中使用了以下内容。

// Allow strict mode
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);

而且效果很好。

需要注意的是,对超过100毫秒的网络请求使用此选项将导致明显的UI冻结,并可能导致ANR(应用程序未响应),因此请记住这一点。

在主线程上执行网络操作时,将引发android.os.NetworkOnMainThreadException。您最好在AsyncTask中执行此操作以删除此异常。这样写:

    new AsyncTask<Void,String,String>(){

        @Override
        protected Void doInBackground(Void... params) {
            // Perform your network operation.
            // Get JSON or XML string from the server.
            // Store in a local variable (say response) and return.
            return response;
        }

        protected void onPostExecute(String results){
            // Response returned by doInBackGround() will be received
            // by onPostExecute(String results).
            // Now manipulate your jason/xml String(results).
        }

    }.execute();
}