我在运行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:
AsyncTask理想情况下应用于短操作(最多几秒钟)
使用newCachedThreadPool是一个好方法。还可以考虑其他选项,如newSingleThreadExecutor、newFixedThreadPool
ExecutorService myExecutor = Executors.newCachedThreadPool();
myExecutor.execute(new Runnable() {
@Override
public void run() {
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);
}
});
ThreadPoolExecutor是一个帮助程序类,可使此过程更简单。这类管理一组线程的创建并管理如何在这些线程之间分配工作。随着工作量的增加或减少,该类会加速或破坏更多线程可根据工作负载进行调整。
有关Android线程的更多信息,请参阅本文。
我们还可以使用RxJava将网络操作移动到后台线程。这也相当简单。
webService.doSomething(someData)
.subscribeOn(Schedulers.newThread())-- This for background thread
.observeOn(AndroidSchedulers.mainThread()) -- for callback on UI
.subscribe(result -> resultText.setText("It worked!"),
e -> handleError(e));
你可以用RxJava做更多的事情。下面是RxJava的一些链接。请随意挖掘。
Android中的RxJava异步任务
http://blog.stablekernel.com/replace-asynctask-asynctaskloader-rx-observable-rxjava-android-patterns/
永远不要在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开发者。
注意: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"/>
简单地说,
不在UI线程中执行网络工作
例如,如果您执行HTTP请求,则这是一个网络操作。
解决方案:
您必须创建一个新线程或使用AsyncTask类
Way:
把你所有的作品放进去
新线程的run()方法或AsyncTask类的doInBackground()方法。
But:
当您从网络响应中获得一些内容并希望在视图中显示它(如在TextView中显示响应消息)时,需要返回到UI线程。
如果不执行此操作,将获得ViewRootImpl$CalledFromWrongThreadException。
如何
使用AsyncTask时,从onPostExecute()方法更新视图或者调用runOnUiThread()方法并更新run()方法内的视图。