3html
"你感受到了吗?" 应用的 GitHub Repo 地址.java
6node
Android 系统可以同时运行多个线程, 所以能够相互独立的处理 两组或多组任务。若是有多个线程须要运行, Android 还会就什么时候运行哪些线程进行优先级排序, 并肯定各线程的运行时长。react
线程也知道如何保存其位置。它不只会记录全部变量的值, 还会记住完成当前正在执行的指令 会调用的函数系列: 即可以从新完成工做所需的一切内容。android
构建全部多线程应用程序都是为了可以同时运行两个或 多个进程。现代编程语言和 CPU 旨在利用多线程, 所以,在 Android 平台上构建应用并无什么不一样!git
有关更进一步的讨论,请参阅“进程与线程”这篇文章。github
还有另外一篇关于“保持你的应用及时响应”这一话题的开发者指南。编程
7json
我强烈建议观看关于线程的 Android Performance Patterns Youtube视频,演讲者为 Google 技术推广工程师 Colt McAnlis。数组
8
设计提示:理论上,应用中的内容是即时加载的。若是 未加载,请尝试容许用户与应用的其余部分进行交互, 以便用户不会坐在那里无所事事,或是观看进度条。若是应用中没有 任何有意义的事可供用户去作,材料设计规范提供了有关如何针对须要花费很长时间加载的内容来 显示进度的指南。
10
11
要检查 NetworkConnect 应用,能够从开发者站点下载代码。或者 在 Android Studio 内,单击文件 (File) > 新建 (New) > 导入示例 (Import Sample),并搜索 "Network Connect" 示例。
内部类。
12
提示:若是你陷入僵局,须要更详细的步骤,请参阅此 列表。可是,首先要尝试本身完成任务!
建立 AsyncTask 的子类做为 MainActivity 类中的 私有内部类。 实现 doInBackground() 方法来获取地震数据并 返回结果。 实现 onPostExecute() 方法以根据咱们的结果 更新 UI。
在 MainActivity onCreate() 方法中建立咱们的内部类的实例, 并执行。
13
我要指出的是,目前,咱们的代码是针对最佳 状况编写的。咱们假设 EarthquakeAsyncTask 经过咱们预期的输入调用, 且在执行网络请求时未出现任何 错误。
咱们试图进一步验证咱们的应用,以便咱们或接触代码的任何其余开发者 不会不当心在应用中致使 bug 或崩溃。 为此,咱们须要将当前类之外的代码编写假设、 以及超出咱们控制的假设 最小化。
若是咱们能够接受任何输入(零输入、1 个 输入、2 个输入等)或处理任何意外行为(服务器 作出有效或无效响应),并作出得体的处理而不使应用崩溃, 那么就说明咱们的代码变得更加稳健。
为了这个目的,请对 "你感受到了吗?" 应用进行下列修改, 以处理 EarthquakeAsyncTask 中空或 Null 状况。
在 doInBackground 方法中,检查 url 数组是否至少具备 1 个 条目且第一个条目不为空。若是数组长度为 0 或第一个条目为空,则经过返回 null 提前离开 此方法。咱们须要返回 null,由于须要有对象 做为返回值。若是有 1 个有效字符串 URL,则继续 获取数据。
protected Event doInBackground(String... urls) { // 若是不存在任何 URL 或第一个 URL 为空,切勿执行请求。 if (urls.length < 1 || urls[0] == null) { return null; } Event result = Utils.fetchEarthquakeData(urls[0]); return result; }
在 onPostExecute 方法中,若是不存在地震结果,则提前 返回。
protected void onPostExecute(Event result) { // 若是不存在任何结果,则不执行任何操做。 if (result == null) { return; } updateUi(result); }
下面是完整的 EarthquakeAsyncTask 类声明。
/** * {@link AsyncTask} 用于在后台线程上执行网络请求,而后 * 使用响应中的第一个地震更新 UI。 */ private class EarthquakeAsyncTask extends AsyncTask<String, Void, Event> { /** * 此方法在后台线程上激活(调用),所以咱们能够执行 * 诸如作出网络请求等长时间运行操做。 * * 由于不能从后台线程更新 UI,因此咱们仅返回 * {@link Event} 对象做为结果。 */ protected Event doInBackground(String... urls) { // 若是不存在任何 URL 或第一个 URL 为空,切勿执行请求。 if (urls.length < 1 || urls[0] == null) { return null; } Event result = Utils.fetchEarthquakeData(urls[0]); return result; } /** * 此方法是在完成后台工做后,在主 UI 线程上 * 激活的。 * * 能够在此方法内修改 UI。咱们获得 {@link Event} 对象 * (该对象从 doInBackground() 方法返回),并更新屏幕上的视图。 */ protected void onPostExecute(Event result) { // 若是不存在任何结果,则不执行任何操做。 if (result == null) { return; } updateUi(result); } }
你编译并运行应用时,应该看起来是这样的。
要在 GitHub 上浏览“你感受到了吗?”应用的完整和最终状态, 请单击此处。
15
因此最近咱们看到 List 与 ArrayList 的大量使用。它们 两者的使用方式看起来类似,但此处 有何区别呢?
这里的根本区别很简单:List 是 接口,而 ArrayList 是具体类。没法建立 List 的对象实例,由于它是接口 且其方法未实现。可是能够建立 ArrayList 的对象实例并为 E 指定泛型参数, 由于它是具体类。
例如:要使用 Earthquake 数据类型定义 ArrayList 的实例, 能够编写:
ArrayList<Earthquake> earthquakeList = new ArrayList<Earthquake>();
这将会运行良好。你也能够 在 List 数据类型的变量中存储该对象:
List<Earthquake> earthquakeList = new ArrayList<Earthquake>();
这样作的缘由是为了具备更大的灵活性:
与 ArrayList 类类似的另外一种类型的类是 LinkedList,此类 也可用于实现 List 接口。这两种类具备类似的方法 和实现策略,但两者内部详细信息和存储器 略有不一样。若是出于某种缘由,你的应用会 因使用 LinkedList 而非 ArrayList 而从中受益,则 仅在实例的定义位置进行更新会很容易, 而且全部 List 代码仍能正常工做!下面是一个例子:
List<Earthquake> earthquakeList = new ArrayList<Earthquake>(); earthquakeList.add(foo);
变为:
List<Earthquake> earthquakeList = new LinkedList<Earthquake>(); earthquakeList.add(foo);
而且它仍能工做!
在全部状况下,最佳的作法是,只要须要列表对象(不论是 ArrayList 仍是 LinkedList)时,便使用 List, 这样你就能够 保持代码的灵活性。
要了解有关这方面的更多信息,请阅读 List 接口的文档, 并查看 什么时候使用 List 和什么时候可能使用 ArrayList 与 LinkedList 中有关 StackOverflow 的热烈讨论。
16
是时候挽起袖子开始编码了!
修改 地震报告应用,以作出对此 URL 的网络请求。 此查询将为你提供全球最近发生的震级至少为 6 级 的 10 大地震。http://earthquake.usgs.gov/fdsnws/event/1/query?format=geojson&eventtype=earthquake&orderby=time&minmag=6&limit=10
收到响应后,解析 JSON,而后更新 应用中的列表。
提示 #1:在进行这些增量更改时, 尝试尽量多地编译并运行应用。不然,最后可能会有大量错误 须要解决。
提示 #2:请记住,你能够回过来参考 "Soonami" 和 "Did You Feel it" 示例应用。
若是你须要更多调试提示,请查看此论坛线程,其余 学生会在这里就如何完成此长编码任务发表建议。
来自大家课程导师的备注: 上面那个 HTTP 连接,有可能会返回 301 的状态码,是由于请求被重定向到HTTPS了。浏览器一般会自动处理这个重定向,可是咱们如今的代码请求并不会自动处理这个问题,因此把连接改为HTTPS便可。
顺便,更多关于 HTTP 状态码( HTTP Status Code )的介绍能够看这里,更多关于 HTTPS 能够看这里。固然去看Wikipedia的介绍也是极好的。
17
18
做为提示,如下是可能的答案选项:
onLoaderReset()
onCreateLoader()
LoaderManager.LoaderCallbacks
LoaderManager
onLoadFinished()
getLoaderManager().initLoader(0, null, this);
有关详细信息,请查看此处:
19
做为提示,如下是可能的答案选项:
AsyncTaskLoader
List
loadInBackground()
若是遇到困难,请查看如下资源:
21
当 地震报告应用具备在整个代码中添加的日志消息时, 请测试如下场景:
22
可选:你是否了解尝试将空状态变为 愉快用户体验的 Android 应用?在论坛上 分享屏幕截图。
ListView setEmptyView() 方法。
材料设计原则 - 与空状态有关。
23
提示:在常见 Android 视图备忘表中查看 ProgressBar 视图的示例。
Material Design 进度与活动
提示:执行如下 2 个测试,检查加载指示符 将通向地震结果列表仍是 空视图。
测试 #1:强制后台线程睡眠 2 秒钟
为强制后台线程睡眠 2 秒钟,咱们 暂时模拟一个极慢的网络响应时间咱们 “假设”耗时好久来获取响应。这 能够较正常状况下延长屏幕上加载下拉菜单的时间, 以便咱们查看。
在 QueryUtils.java 文件的 fetchEarthquakeData() 方法内, 将此代码段添加到方法顶部。将方法中的 其他部分代码保持不变。强制后台线程 暂停执行并等待 2 秒钟(2000 毫秒), 而后再继续执行此方法中的其他代码行。 若是尝试单独添加 Thread.sleep(2000); 方法调用, Android Studio 将告知存在未捕获的异常,因此 咱们须要使用 try/catch 块将该语句括起来。
在 QueryUtils.java 中:
public static List<Earthquake> fetchEarthquakeData(String requestUrl) { try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } … }
如今,当运行应用时,将显示 2 秒钟的加载指示符, 而后才出现地震列表。
测试 #2:假设没有从服务器返回任何结果
在 EarthquakeActivity onLoadFInished 方法中,暂时注释掉 向适配器添加地震数据的 代码行。这会使应用看起来像是没有要显示的地震 结果。
在 QueryUtils.java 中:
@Override public void onLoadFinished(Loader<List<Earthquake>> loader, List<Earthquake> earthquakes) { ... // 若是存在 {@link Earthquake} 的有效列表,则将其添加到适配器的 // 数据集。这将触发 ListView 执行更新。 if (earthquakes != null && !earthquakes.isEmpty()) { // mAdapter.addAll(earthquakes); } }
如今,当运行应用时,将显示 2 秒钟的加载指示符, 而后出现显示“未发现地震。(No earthquakes found.)”的空状态
24