我在运行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
如何解决此问题?
您几乎应该始终在线程上或作为异步任务运行网络操作。
但如果您愿意接受后果,则可以取消此限制,并覆盖默认行为。
Add:
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
在你的课堂上,
and
在Android manifest.xml文件中添加此权限:
<uses-permission android:name="android.permission.INTERNET"/>
后果:
你的应用程序(在互联网连接不稳定的地区)将变得无响应并被锁定,用户感觉到速度缓慢,必须进行强制关闭,你冒着活动管理器关闭你的应用并告诉用户应用程序已停止的风险。
Android提供了一些关于良好编程实践的好建议,以设计响应能力:NetworkOnMainThreadException | Android开发人员
该错误是由于在主线程中执行长时间运行的操作造成的。您可以使用AsynTask或thread轻松纠正该问题。您可以签出此库AsyncHTTPClient以获得更好的处理。
AsyncHttpClient client = new AsyncHttpClient();
client.get("http://www.google.com", new AsyncHttpResponseHandler() {
@Override
public void onStart() {
// Called before a request is started
}
@Override
public void onSuccess(int statusCode, Header[] headers, byte[] response) {
// Called when response HTTP status is "200 OK"
}
@Override
public void onFailure(int statusCode, Header[] headers, byte[] errorResponse, Throwable e) {
// Called when response HTTP status is "4XX" (for example, 401, 403, 404)
}
@Override
public void onRetry(int retryNo) {
// Called when request is retried
}
});
您可以将代码的一部分移动到另一个线程中以卸载主线程,并避免获得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)
它的主要要点是,它使异步代码看起来非常像同步代码
在这里、这里、这里和这里阅读更多信息。
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线程中被调用。