Android之使用权房继承继承来查询当前是在哪个活动

他的最新文章
他的热门文章
您举报文章:
举报原因:
原文地址:
原因补充:
(最多只允许输入30个字)Android考试题简答题总结_百度文库
两大类热门资源免费畅读
续费一年阅读会员,立省24元!
Android考试题简答题总结
&&安卓所有入门的简答
阅读已结束,下载本文需要
想免费下载本文?
定制HR最喜欢的简历
下载文档到电脑,方便使用
还剩9页未读,继续阅读
定制HR最喜欢的简历
你可能喜欢&p&刚好你需要,刚好我又有,多么美妙的事情,研究了自定义View一段时间,也总结了部分心得,如果能帮助到大家那就再好不过了。&/p&&p&自定义View说起来貌似是一个非常简单的概念,但做起来就会发现需要了解的东西非常多,不是看几篇文章就能说自己完全掌握的,最好的学习方法就是先了解自定义View的基本逻辑,然后通过不断的练习来补充不足的知识。&/p&&figure&&img src=&https://pic1.zhimg.com/a2f8ec94_b.png& alt=&img& class=&content_image&&&/figure&&p&&strong&&a href=&//link.zhihu.com/?target=http%3A//www.gcssloop.com/customview/CustomViewIndex/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&安卓自定义View教程目录&/a&&/strong&&/p&
&ul&&li&&a href=&//link.zhihu.com/?target=http%3A//www.gcssloop.com/customview/CoordinateSystem& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&安卓自定义View基础 - 坐标系&/a&&/li&&li&&a href=&//link.zhihu.com/?target=http%3A//www.gcssloop.com/customview/AngleAndRadian& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&安卓自定义View基础 - 角度弧度&/a&&/li&&li&&a href=&//link.zhihu.com/?target=http%3A//www.gcssloop.com/customview/Color& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&安卓自定义View基础 - 颜色&/a&&/li&&/ul&进阶篇
&ul&&li&&a href=&//link.zhihu.com/?target=http%3A//www.gcssloop.com/customview/CustomViewProcess& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&安卓自定义View进阶 - 分类和流程&/a&&/li&&li&&a href=&//link.zhihu.com/?target=http%3A//www.gcssloop.com/customview/Canvas_BasicGraphics& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&安卓自定义View进阶 - Canvas之绘制图形&/a&&/li&&li&&a href=&//link.zhihu.com/?target=http%3A//www.gcssloop.com/customview/Canvas_Convert& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&安卓自定义View进阶 - Canvas之画布操作&/a&&/li&&li&&a href=&//link.zhihu.com/?target=http%3A//www.gcssloop.com/customview/Canvas_PictureText& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&安卓自定义View进阶 - Canvas之图片文字&/a&&/li&&li&&a href=&//link.zhihu.com/?target=http%3A//www.gcssloop.com/customview/Path_Basic& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&安卓自定义View进阶 - Path之基本操作&/a&&/li&&li&&a href=&//link.zhihu.com/?target=http%3A//www.gcssloop.com/customview/Path_Bezier& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&安卓自定义View进阶 - Path之贝塞尔曲线&/a&&/li&&li&&a href=&//link.zhihu.com/?target=http%3A//www.gcssloop.com/customview/Path_Over& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&安卓自定义View进阶 - Path完结篇&/a&&/li&&li&&a href=&//link.zhihu.com/?target=http%3A//www.gcssloop.com/customview/Path_PathMeasure& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&安卓自定义View进阶 - PathMeasure&/a&&/li&&li&&a href=&//link.zhihu.com/?target=http%3A//www.gcssloop.com/customview/Matrix_Basic& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&安卓自定义View进阶 - Matrix原理&/a&&/li&&li&&a href=&//link.zhihu.com/?target=http%3A//www.gcssloop.com/customview/Matrix_Method& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&安卓自定义View进阶 - Matrix详解&/a&&/li&&li&&a href=&//link.zhihu.com/?target=http%3A//www.gcssloop.com/customview/matrix-3d-camera& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&安卓自定义View进阶 - Matrix Camera&/a&&/li&&li&&a href=&//link.zhihu.com/?target=http%3A//www.gcssloop.com/customview/dispatch-touchevent-theory& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&安卓自定义View进阶 - 事件分发机制原理&/a&&/li&&li&&a href=&//link.zhihu.com/?target=http%3A//www.gcssloop.com/customview/dispatch-touchevent-source& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&安卓自定义View进阶 - 事件分发机制详解&/a&&/li&&li&&a href=&//link.zhihu.com/?target=http%3A//www.gcssloop.com/customview/motionevent& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&安卓自定义View进阶 - MotionEvent详解&/a&&/li&&li&&a href=&//link.zhihu.com/?target=http%3A//www.gcssloop.com/customview/touch-matrix-region& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&安卓自定义View进阶 - 特殊控件的事件处理方案&/a&&/li&&/ul&&p&上述文章由易到难的讲解自定义VIew涉及到到知识点,相信看完这些文章之后基本就能搞定大部分的自定义View了。&/p&&figure&&img src=&https://pic1.zhimg.com/a2f8ec94_b.png& alt=&img& class=&content_image&&&/figure&&p&添加一张图,进阶篇开篇的内容,自定义View绘制流程函数调用链(简化版)。&/p&&figure&&img src=&https://pic4.zhimg.com/bded87613bbc9ff34b08d88b_b.png& alt=&& class=&content_image&&&/figure&&p&文章目前仍在更新中,如果你觉得我的文章有错误或者纰漏,欢迎指正,另外,如果你觉得有用的话,点个赞呗。&/p&&br&
刚好你需要,刚好我又有,多么美妙的事情,研究了自定义View一段时间,也总结了部分心得,如果能帮助到大家那就再好不过了。自定义View说起来貌似是一个非常简单的概念,但做起来就会发现需要了解的东西非常多,不是看几篇文章就能说自己完全掌握的,最好的…
&h2&&b&阿里云大学课程: &/b&&/h2&&h2&【Java学习路线图,看你掌握了多少】附全部知识点免费视频课程&/h2&&figure&&img src=&https://pic3.zhimg.com/v2-c5a1bc390cdbddaf26f0da6_b.png& data-rawwidth=&578& data-rawheight=&2271& class=&origin_image zh-lightbox-thumb& width=&578& data-original=&https://pic3.zhimg.com/v2-c5a1bc390cdbddaf26f0da6_r.png&&&/figure&&p&这个路线图中包含了Java学习的三部曲:&/p&&h2&&b&&a href=&//link.zhihu.com/?target=http%3A//click.aliyun.com/m/25781/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Java零基础入门&/a&(点击标题学习视频课程)
总计25课&/b&&/h2&&p&课时1:Java简介(Java发展概述) 26:42&/p&&p&课时2:Java简介(Java主要特点) 08:55&/p&&p&课时3:JDK的安装与配置 09:58&/p&&p&课时4:第一个Java程序 15:00&/p&&p&课时5:CLASSPATH环境属性 08:26&/p&&p&课时6:Java程序基本概念(注释) 05:24&/p&&p&课时7:Java程序基本概念(标识符与关键字) 06:18&/p&&p&课时8:Java数据类型划分(数据类型划分) 13:14&/p&&p&课时9:Java数据类型划分(整型类型) 30:18&/p&&p&课时10:Java数据类型划分(浮点类型) 09:23&/p&&p&课时11:Java数据类型划分(字符型) 11:48&/p&&p&课时12:Java数据类型划分(布尔型) 02:56&/p&&p&课时13:Java数据类型划分(初见String类) 11:18&/p&&p&课时14:Java运算符(基础数学运算符) 11:12&/p&&p&课时15:Java运算符(三目运算符) 05:42&/p&&p&课时16:Java运算符(关系运算符) 04:54&/p&&p&课时17:Java运算符(逻辑运算符) 07:39&/p&&p&课时18:Java运算符(位运算符) 16:50&/p&&p&课时19:程序逻辑控制(分支结构) 15:11&/p&&p&课时20:程序逻辑控制(循环结构) 10:18&/p&&p&课时21:程序逻辑控制(循环控制) 06:07&/p&&p&课时22:程序逻辑控制(循环嵌套) 06:27&/p&&p&课时23:方法的定义与使用(方法的基本定义) 12:07&/p&&p&课时24:方法的定义与使用(方法重载) 08:50&/p&&p&课时25:方法的定义与使用(方法递归调用) 15:44&/p&&h2&&a href=&//link.zhihu.com/?target=http%3A//click.aliyun.com/m/25783/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Java面向对象开发&/a&&b&(点击标题学习视频课程)
总计105课&/b&&/h2&&p&课时1:面向对象简介 13:22&/p&&p&课时2:类与对象(类与对象基本定义) 09:38&/p&&p&课时3:类与对象(类与对象定义) 09:36&/p&&p&课时4:类与对象(对象内存分析) 20:13&/p&&p&课时5:类与对象(引用传递初次分析) 15:00&/p&&p&课时6:private实现封装处理 16:29&/p&&p&课时7:构造方法与匿名对象 23:55&/p&&p&课时8:【第01个代码模型】综合案例:简单Java类 12:53&/p&&p&课时9:数组的定义与使用(数组基本概念) 14:32&/p&&p&课时10:数组的定义与使用(数组引用传递) 10:40&/p&&p&课时11:数组的定义与使用(数组静态初始化) 06:46&/p&&p&课时12:数组的定义与使用(二维数组) 11:20&/p&&p&课时13:数组的定义与使用(数组与方法互操作) 12:42&/p&&p&课时14:数组的定义与使用(Java对数组的支持) 08:57&/p&&p&课时15:数组的定义与使用(数组案例:数组数据统计) 16:51&/p&&p&课时16:数组的定义与使用(数组案例:数组排序) 13:28&/p&&p&课时17:数组的定义与使用(数组案例:数组转置) 20:16&/p&&p&课时18:数组的定义与使用(数组案例:二分查找法) 13:14&/p&&p&课时19:数组的定义与使用(对象数组) 09:05&/p&&p&课时20:String类的基本特点(String类两种实例化方式) 04:48&/p&&p&课时21:String类的基本特点(字符串比较) 08:09&/p&&p&课时22:String类的基本特点(字符串为匿名对象) 06:33&/p&&p&课时23:String类的基本特点(String两种实例化区别) 20:37&/p&&p&课时24:String类的基本特点(字符串常量不可变更) 10:05&/p&&p&课时25:String类的常用方法(DOC文档组成) 07:18&/p&&p&课时26:String类的常用方法(字符串与字符数组) 11:41&/p&&p&课时27:String类的常用方法(字节与字符串) 05:38&/p&&p&课时28:String类的常用方法(字符串比较) 06:13&/p&&p&课时29:String类的常用方法(字符串查找) 10:57&/p&&p&课时30:String类的常用方法(字符串替换) 02:49&/p&&p&课时31:String类的常用方法(字符串拆分) 07:33&/p&&p&课时32:String类的常用方法(字符串截取) 03:07&/p&&p&课时33:String类的常用方法(字符串其它操作方法) 12:31&/p&&p&课时34:this关键字(this调用属性) 07:15&/p&&p&课时35:this关键字(this调用方法) 09:58&/p&&p&课时36:this关键字(表示当前对象) 06:02&/p&&p&课时37:引用传递进阶分析 20:54&/p&&p&课时38:【第02个代码模型】综合案例:对象比较 11:22&/p&&p&课时39:引用传递实际应用 19:12&/p&&p&课时40:【第03个代码模型】综合案例:数据表与简单Java类(一对多) 17:07&/p&&p&课时41:【第03个代码模型】综合案例:数据表与简单Java类(多对多) 20:40&/p&&p&课时42:【第03个代码模型】综合案例:数据表与简单Java类(角色与权限) 26:58&/p&&p&课时43:static关键字(static属性) 17:08&/p&&p&课时44:static关键字(static方法) 06:25&/p&&p&课时45:static关键字(分析主方法) 08:41&/p&&p&课时46:static关键字(static应用) 06:24&/p&&p&课时47:代码块(普通代码块) 04:24&/p&&p&课时48:代码块(构造块) 04:09&/p&&p&课时49:代码块(静态代码块) 05:11&/p&&p&课时50:内部类的定义及使用(内部类基本概念) 20:56&/p&&p&课时51:内部类的定义及使用(static定义内部类) 04:58&/p&&p&课时52:内部类的定义及使用(在方法中定义内部类) 07:01&/p&&p&课时53:继承的定义与使用(继承问题的引出) 06:02&/p&&p&课时54:继承的定义与使用(继承的实现) 06:25&/p&&p&课时55:继承的定义与使用(继承使用限制) 21:13&/p&&p&课时56:覆写(方法覆写) 19:36&/p&&p&课时57:覆写(属性覆盖) 03:23&/p&&p&课时58:覆写(super关键字) 09:35&/p&&p&课时59:综合案例:数组操作(定义Array父类) 18:17&/p&&p&课时60:综合案例:数组操作(SortArray排序子类) 05:15&/p&&p&课时61:综合案例:数组操作(ReverseArray反转子类) 03:48&/p&&p&课时62:final关键字 06:05&/p&&p&课时63:多态性 28:26&/p&&p&课时64:抽象类的定义与使用(抽象类基本概念) 16:39&/p&&p&课时65:抽象类的定义与使用(抽象类使用限制) 18:06&/p&&p&课时66:抽象类的定义与使用(模版设计模式) 18:58&/p&&p&课时67:接口的定义与使用(接口基本概念) 17:34&/p&&p&课时68:接口的定义与使用(接口使用限制) 22:56&/p&&p&课时69:接口的定义与使用(使用接口定义标准) 14:34&/p&&p&课时70:接口的定义与使用(工厂设计模式) 13:23&/p&&p&课时71:接口的定义与使用(代理设计模式) 14:41&/p&&p&课时72:接口的定义与使用(抽象类与接口的区别) 12:51&/p&&p&课时73:匿名内部类 09:25&/p&&p&课时74:Object类(Object类简介) 06:01&/p&&p&课时75:Object类(取得对象信息) 07:45&/p&&p&课时76:Object类(对象比较) 08:50&/p&&p&课时77:Object类(接收引用数据类型) 05:46&/p&&p&课时78:包装类(包装类简介) 09:08&/p&&p&课时79:包装类(装箱与拆箱) 09:46&/p&&p&课时80:包装类(字符串与基本数据类型转换) 10:21&/p&&p&课时81:包的定义及使用(包的定义) 10:19&/p&&p&课时82:包的定义及使用(包的导入) 13:34&/p&&p&课时83:包的定义及使用(系统常用包) 08:36&/p&&p&课时84:访问控制权限 10:45&/p&&p&课时85:jar命令 09:38&/p&&p&课时86:单例设计模式(单例设计模式) 18:04&/p&&p&课时87:单例设计模式(多例设计模式) 05:43&/p&&p&课时88:【第04个代码模型】异常的捕获与处理(观察异常带来的问题) 05:35&/p&&p&课时89:【第04个代码模型】异常的捕获与处理(异常处理格式) 15:16&/p&&p&课时90:【第04个代码模型】异常的捕获与处理(throws关键字) 08:09&/p&&p&课时91:【第04个代码模型】异常的捕获与处理(throw关键字) 06:17&/p&&p&课时92:【第04个代码模型】异常的捕获与处理(异常处理模型) 09:03&/p&&p&课时93:【第04个代码模型】异常的捕获与处理(RuntimeException) 06:43&/p&&p&课时94:【第04个代码模型】异常的捕获与处理(断言) 04:20&/p&&p&课时95:【第04个代码模型】异常的捕获与处理(自定义异常类) 05:35&/p&&p&课时96:链表(链表基本概念) 17:03&/p&&p&课时97:链表(链表实现结构说明) 11:17&/p&&p&课时98:链表(增加链表数据) 16:14&/p&&p&课时99:链表(取得链表数据个数) 04:26&/p&&p&课时100:链表(链表数据转换为对象数组) 14:08&/p&&p&课时101:链表(查询数据) 06:01&/p&&p&课时102:链表(根据索引取得数据) 05:24&/p&&p&课时103:链表(修改指定索引数据) 04:07&/p&&p&课时104:链表(删除数据) 12:18&/p&&p&课时105:【第05个代码模型】综合案例:宠物商店 19:48&/p&&h2&&a href=&//link.zhihu.com/?target=http%3A//click.aliyun.com/m/25785/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Java高级开发&/a&&b&(点击标题学习视频课程)
总计155课&/b&&/h2&&p&课时1:Eclipse开发工具(Eclipse简介) 18:13&/p&&p&课时2:Eclipse开发工具(使用JDT开发程序) 33:05&/p&&p&课时3:Eclipse开发工具(debug调试) 09:08&/p&&p&课时4:Eclipse开发工具(junit测试工具) 06:07&/p&&p&课时5:Java基础新特性(可变参数) 11:02&/p&&p&课时6:Java基础新特性(foreach输出) 04:43&/p&&p&课时7:Java基础新特性(静态导入) 05:38&/p&&p&课时8:泛型(泛型问题引出) 10:03&/p&&p&课时9:泛型(泛型实现) 06:55&/p&&p&课时10:泛型(通配符) 17:37&/p&&p&课时11:泛型(泛型接口) 04:48&/p&&p&课时12:泛型(泛型方法) 03:14&/p&&p&课时13:枚举(多例与枚举) 06:15&/p&&p&课时14:枚举(Enum类) 05:30&/p&&p&课时15:枚举(枚举中定义其它结构) 05:48&/p&&p&课时16:枚举(枚举应用) 05:24&/p&&p&课时17:Annotation(代码开发逻辑) 12:10&/p&&p&课时18:Annotation(准确覆写) 05:44&/p&&p&课时19:Annotation(过期声明) 04:46&/p&&p&课时20:Annotation(压制警告) 04:12&/p&&p&课时21:接口定义加强 12:14&/p&&p&课时22:Lambda表达式 15:33&/p&&p&课时23:方法引用 12:15&/p&&p&课时24:内建函数式接口 12:30&/p&&p&课时25:进程与线程 13:20&/p&&p&课时26:Java多线程实现(Thread类实现多线程) 21:34&/p&&p&课时27:Java多线程实现(Runnable接口实现多线程) 07:44&/p&&p&课时28:Java多线程实现(Thread与Runnable区别) 16:39&/p&&p&课时29:Java多线程实现(线程状态) 02:50&/p&&p&课时30:Java多线程实现(Callable实现多线程) 14:36&/p&&p&课时31:多线程常用操作方法(线程命名和取得) 13:37&/p&&p&课时32:多线程常用操作方法(线程休眠) 08:00&/p&&p&课时33:多线程常用操作方法(线程优先级) 07:25&/p&&p&课时34:线程的同步与死锁(同步问题引出) 11:09&/p&&p&课时35:线程的同步与死锁(同步处理) 11:20&/p&&p&课时36:线程的同步与死锁(死锁) 07:54&/p&&p&课时37:【第06个代码模型】综合案例:生产者与消费者(基础模型) 10:48&/p&&p&课时38:【第06个代码模型】综合案例:生产者与消费者(解决同步问题) 04:24&/p&&p&课时39:【第06个代码模型】综合案例:生产者与消费者(解决重复操作问题) 09:44&/p&&p&课时40:线程池(线程池概念) 08:30&/p&&p&课时41:线程池(线程池实现) 10:49&/p&&p&课时42:StringBuffer类 18:34&/p&&p&课时43:Runtime类 10:39&/p&&p&课时44:System类 12:04&/p&&p&课时45:对象克隆 05:48&/p&&p&课时46:【第07个代码模型】日期处理类(Date类) 06:07&/p&&p&课时47:【第07个代码模型】日期处理类(SimpleDateFormat类) 11:20&/p&&p&课时48:数字操作类(Math类) 08:48&/p&&p&课时49:数字操作类(随机数) 03:23&/p&&p&课时50:数字操作类(大数字操作类) 12:54&/p&&p&课时51:Arrays类 04:14&/p&&p&课时52:比较器(Comparable) 11:35&/p&&p&课时53:比较器(二叉树) 15:04&/p&&p&课时54:比较器(Comparator) 08:35&/p&&p&课时55:国际化程序(国际化实现原理) 09:30&/p&&p&课时56:国际化程序(Locale类) 06:58&/p&&p&课时57:国际化程序(ResourceBundle) 10:28&/p&&p&课时58:国际化程序(国际化程序实现) 07:45&/p&&p&课时59:观察者设计模式 09:21&/p&&p&课时60:定时器 07:15&/p&&p&课时61:UUID类 02:16&/p&&p&课时62:Base64加密处理 09:07&/p&&p&课时63:【第08个代码模型】ThreadLocal类 15:09&/p&&p&课时64:【第09个代码模型】正则表达式(正则问题引出) 08:59&/p&&p&课时65:【第09个代码模型】正则表达式(正则符号) 17:52&/p&&p&课时66:【第09个代码模型】正则表达式(String类对正则的支持) 27:53&/p&&p&课时67:【第09个代码模型】正则表达式(java.util.regex开发包) 10:20&/p&&p&课时68:File文件操作类(File类基本操作) 19:01&/p&&p&课时69:File文件操作类(创建目录) 06:44&/p&&p&课时70:File文件操作类(取得文件信息) 09:45&/p&&p&课时71:File文件操作类(综合案例:目录列表) 11:15&/p&&p&课时72:字节流与字符流(流操作简介) 07:07&/p&&p&课时73:字节流与字符流(字节输出流:OutputStream) 23:21&/p&&p&课时74:字节流与字符流(AutoCloseable自动关闭支持) 06:44&/p&&p&课时75:字节流与字符流(字节输入流:InputStream) 15:31&/p&&p&课时76:字节流与字符流(字符输出流:OutputStream) 04:48&/p&&p&课时77:字节流与字符流(字符输入流:Reader) 05:24&/p&&p&课时78:字节流与字符流(字节流与字符流区别) 08:35&/p&&p&课时79:转换流 10:28&/p&&p&课时80:【第10个代码模型】综合案例:文件拷贝 33:34&/p&&p&课时81:字符编码(常用字符编码) 05:55&/p&&p&课时82:字符编码(乱码产生分析) 07:17&/p&&p&课时83:内存操作流(内存流基本操作) 19:32&/p&&p&课时84:内存操作流(内存流操作) 20:36&/p&&p&课时85:【第11个代码模型】打印流(打印流模型) 10:32&/p&&p&课时86:【第11个代码模型】打印流(使用系统打印流) 11:02&/p&&p&课时87:【第11个代码模型】打印流(格式化文本信息) 06:08&/p&&p&课时88:System类对IO的支持(系统输出) 09:59&/p&&p&课时89:System类对IO的支持(系统输入) 15:58&/p&&p&课时90:BufferedReader类 12:08&/p&&p&课时91:【第12个代码模型】Scanner类 13:13&/p&&p&课时92:【第13个代码模型】对象序列化(序列化基本概念) 04:52&/p&&p&课时93:【第13个代码模型】对象序列化(序列化实现) 11:43&/p&&p&课时94:【第13个代码模型】对象序列化(transient关键字) 03:56&/p&&p&课时95:认识反射机制 06:14&/p&&p&课时96:Class类对象的三种实例化模式 09:16&/p&&p&课时97:【第14个代码模型】反射与工厂设计模式 18:09&/p&&p&课时98:反射与类操作(取得父类信息) 06:03&/p&&p&课时99:反射与类操作(反射调用构造) 19:12&/p&&p&课时100:反射与类操作(反射调用方法) 12:15&/p&&p&课时101:反射与类操作(反射调用成员) 19:45&/p&&p&课时102:【第15个代码模型】综合案例:反射与简单Java类(单级VO操作原理) 18:26&/p&&p&课时103:【第15个代码模型】综合案例:反射与简单Java类(单级VO设置实现) 28:23&/p&&p&课时104:【第15个代码模型】综合案例:反射与简单Java类(多级VO设置实现) 14:59&/p&&p&课时105:【第15个代码模型】综合案例:反射与简单Java类(设置各种数据类型) 35:56&/p&&p&课时106:【第15个代码模型】综合案例:反射与简单Java类(级联实例化对象) 06:41&/p&&p&课时107:ClassLoader类加载器(认识类加载器) 14:44&/p&&p&课时108:ClassLoader类加载器(自定义ClassLoader) 12:48&/p&&p&课时109:【第16个代码模型】反射与代理设计模式(基础代理设计模式) 19:49&/p&&p&课时110:【第16个代码模型】反射与代理设计模式(动态代理设计模式) 20:55&/p&&p&课时111:【第16个代码模型】反射与代理设计模式(cglib实现动态代理) 12:13&/p&&p&课时112:反射与Annotation(反射取得Annotation) 07:49&/p&&p&课时113:反射与Annotation(自定义Annotation) 08:47&/p&&p&课时114:反射与Annotation(Annotation与工厂设计模式) 06:43&/p&&p&课时115:volatile关键字 14:20&/p&&p&课时116:网络编程(网络编程简介) 08:15&/p&&p&课时117:网络编程(基本网络程序模型) 09:26&/p&&p&课时118:网络编程(Echo程序) 18:00&/p&&p&课时119:JDBC简介 08:12&/p&&p&课时120:连接Oracle数据库 26:06&/p&&p&课时121:使用Statement操作数据库(Statement接口简介) 09:29&/p&&p&课时122:使用Statement操作数据库(Statement执行更新操作) 09:17&/p&&p&课时123:使用Statement操作数据库(Statement执行查询操作) 12:42&/p&&p&课时124:【第17个代码模型】使用PreparedStatement操作数据库(Statement执行分析) 16:50&/p&&p&课时125:【第17个代码模型】使用PreparedStatement操作数据库(PreparedStatement查询案例) 11:42&/p&&p&课时126:批处理与事务处理(批处理) 11:11&/p&&p&课时127:批处理与事务处理(事务处理) 07:04&/p&&p&课时128:Java类集简介 05:56&/p&&p&课时129:Collection集合接口 16:09&/p&&p&课时130:【第18个代码模型】List集合接口(List接口简介) 10:17&/p&&p&课时131:【第18个代码模型】List集合接口(ArrayList子类) 07:54&/p&&p&课时132:【第18个代码模型】List集合接口(List与简单Java类) 06:05&/p&&p&课时133:【第18个代码模型】List集合接口(Vector子类) 10:09&/p&&p&课时134:【第18个代码模型】List集合接口(LinkedList子类) 11:23&/p&&p&课时135:【第19个代码模型】Set集合接口(Set接口常用子类) 09:19&/p&&p&课时136:【第19个代码模型】Set集合接口(集合排序说明) 08:55&/p&&p&课时137:【第19个代码模型】Set集合接口(重复元素判断) 13:37&/p&&p&课时138:【第20个代码模型】集合输出(Iterator迭代输出) 09:04&/p&&p&课时139:【第20个代码模型】集合输出(ListIterator双向迭代) 08:11&/p&&p&课时140:【第20个代码模型】集合输出(Enumeration枚举输出) 05:25&/p&&p&课时141:【第20个代码模型】集合输出(foreach输出) 02:52&/p&&p&课时142:【第21个代码模型】Map集合(Map接口概述) 09:31&/p&&p&课时143:【第21个代码模型】Map集合(HashMap子类) 09:36&/p&&p&课时144:【第21个代码模型】Map集合(Hashtable子类) 06:27&/p&&p&课时145:【第21个代码模型】Map集合(ConcurrentHashMap子类) 23:56&/p&&p&课时146:【第21个代码模型】Map集合(Map使用Iterator输出) 14:46&/p&&p&课时147:【第21个代码模型】Map集合(Map中的key实现说明) 04:18&/p&&p&课时148:【第21个代码模型】Map集合(TreeMap子类) 05:10&/p&&p&课时149:Stack栈 06:48&/p&&p&课时150:Queue队列 19:06&/p&&p&课时151:Properties属性操作 09:17&/p&&p&课时152:Collections工具类 04:29&/p&&p&课时153:Stream数据流(Collection接口扩充) 08:30&/p&&p&课时154:Stream数据流(Stream基本操作) 11:07&/p&&p&课时155:Stream数据流(MapReduce模型) 13:49&/p&&p&在阿里云大学,你可以跟随Java名师李兴华学到路线图中所有的知识点&b&(完全免费哦)&/b&,赶快开始你的Java学习之路吧!&/p&&h2&&b&更多技术课程,请关注阿里云大学专栏:&a href=&https://zhuanlan.zhihu.com/aliyunedu& class=&internal&&阿里云大学 - 知乎专栏&/a&&/b& &/h2&
阿里云大学课程: 【Java学习路线图,看你掌握了多少】附全部知识点免费视频课程这个路线图中包含了Java学习的三部曲:(点击标题学习视频课程) 总计25课课时1:Java简介(Java发展概述) 26:42课时2:Java简介(Java主要特点) 08:55课时3…
&figure&&img src=&https://pic2.zhimg.com/v2-c4d93e8db_b.jpg& data-rawwidth=&1200& data-rawheight=&630& class=&origin_image zh-lightbox-thumb& width=&1200& data-original=&https://pic2.zhimg.com/v2-c4d93e8db_r.jpg&&&/figure&&blockquote&简评:虽然说 Android 的架构选择一直都很自由,MVP、MVC、MVVM 各有拥趸。但 Google 最近还是推出了一份关于应用架构的实践指南,并给出了相当详尽的步骤和一些指导建议。希望大家都能看一看,学习一下,打造更加优秀易用的 APP,也为 Android 生态的改善做一点贡献。: )&/blockquote&&p&最近,官方推出了一份关于应用架构的最佳实践指南。这里就给大家简要介绍一下:&/p&&p&首先,Android 开发者肯定都知道 Android 中有四大组件,这些组件都有各自的生命周期并且在一定程度上是不受你控制的。在任何时候,Android 操作系统都可能根据用户的行为或资源紧张等原因回收掉这些组件。&/p&&p&这也就引出了&b&第一条准则&/b&:「不要在应用程序组件中保存任何应用数据或状态,并且组件间也不应该相互依赖」。&/p&&p&最常见的错误就是在 Activity 或 Fragment 中写了与 UI 和交互无关的代码。尽可能减少对它们的依赖,这能避免大量生命周期导致的问题,以提供更好的用户体验。&/p&&p&&b&第二条准则&/b&:「通过 model 驱动应用 UI,并尽可能的持久化」。&/p&&p&这样做主要有两个原因:&/p&&ol&&li&如果系统回收了你的应用资源或其他什么意外情况,不会导致用户丢失数据。&br&&/li&&li&Model 就应该是负责处理应用程序数据的组件。独立于视图和应用程序组件,保持了视图代码的简单,也让你的应用逻辑更容易管理。并且,将应用数据置于 model 类中,也更有利于测试。&/li&&/ol&&br&&h2&官方推荐的 App 架构&/h2&&p&在这里,官方演示了通过使用最新推出的 &a href=&http://link.zhihu.com/?target=https%3A//developer.android.com/topic/libraries/architecture/index.html& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Architecture Components&/a& 来构建一个应用。&/p&&p&想象一下,您正在打算开发一个显示用户个人信息的界面,用户数据通过 REST API 从后端获取。&/p&&p&首先,我们需要创建三个文件:&/p&&ul&&li&user_profile.xml:定义界面。&/li&&li&UserProfileViewModel.java:数据类。&/li&&li&UserProfileFragment.java:显示 ViewModel 中的数据并对用户的交互做出反应。&br&&/li&&/ul&&br&&u&为了简单起见,我们这里就省略掉布局文件。&/u&&br&&div class=&highlight&&&pre&&code class=&language-java&&&span&&/span&&span class=&kd&&public&/span& &span class=&kd&&class&/span& &span class=&nc&&UserProfileViewModel&/span& &span class=&kd&&extends&/span& &span class=&n&&ViewModel&/span& &span class=&o&&{&/span&
&span class=&kd&&private&/span& &span class=&n&&String&/span& &span class=&n&&userId&/span&&span class=&o&&;&/span&
&span class=&kd&&private&/span& &span class=&n&&User&/span& &span class=&n&&user&/span&&span class=&o&&;&/span&
&span class=&kd&&public&/span& &span class=&kt&&void&/span& &span class=&nf&&init&/span&&span class=&o&&(&/span&&span class=&n&&String&/span& &span class=&n&&userId&/span&&span class=&o&&)&/span& &span class=&o&&{&/span&
&span class=&k&&this&/span&&span class=&o&&.&/span&&span class=&na&&userId&/span& &span class=&o&&=&/span& &span class=&n&&userId&/span&&span class=&o&&;&/span&
&span class=&o&&}&/span&
&span class=&kd&&public&/span& &span class=&n&&User&/span& &span class=&nf&&getUser&/span&&span class=&o&&()&/span& &span class=&o&&{&/span&
&span class=&k&&return&/span& &span class=&n&&user&/span&&span class=&o&&;&/span&
&span class=&o&&}&/span&
&span class=&o&&}&/span&
&/code&&/pre&&/div&&div class=&highlight&&&pre&&code class=&language-java&&&span&&/span&&span class=&kd&&public&/span& &span class=&kd&&class&/span& &span class=&nc&&UserProfileFragment&/span& &span class=&kd&&extends&/span& &span class=&n&&LifecycleFragment&/span& &span class=&o&&{&/span&
&span class=&kd&&private&/span& &span class=&kd&&static&/span& &span class=&kd&&final&/span& &span class=&n&&String&/span& &span class=&n&&UID_KEY&/span& &span class=&o&&=&/span& &span class=&s&&&uid&&/span&&span class=&o&&;&/span&
&span class=&kd&&private&/span& &span class=&n&&UserProfileViewModel&/span& &span class=&n&&viewModel&/span&&span class=&o&&;&/span&
&span class=&nd&&@Override&/span&
&span class=&kd&&public&/span& &span class=&kt&&void&/span& &span class=&nf&&onActivityCreated&/span&&span class=&o&&(&/span&&span class=&nd&&@Nullable&/span& &span class=&n&&Bundle&/span& &span class=&n&&savedInstanceState&/span&&span class=&o&&)&/span& &span class=&o&&{&/span&
&span class=&kd&&super&/span&&span class=&o&&.&/span&&span class=&na&&onActivityCreated&/span&&span class=&o&&(&/span&&span class=&n&&savedInstanceState&/span&&span class=&o&&);&/span&
&span class=&n&&String&/span& &span class=&n&&userId&/span& &span class=&o&&=&/span& &span class=&n&&getArguments&/span&&span class=&o&&().&/span&&span class=&na&&getString&/span&&span class=&o&&(&/span&&span class=&n&&UID_KEY&/span&&span class=&o&&);&/span&
&span class=&n&&viewModel&/span& &span class=&o&&=&/span& &span class=&n&&ViewModelProviders&/span&&span class=&o&&.&/span&&span class=&na&&of&/span&&span class=&o&&(&/span&&span class=&k&&this&/span&&span class=&o&&).&/span&&span class=&na&&get&/span&&span class=&o&&(&/span&&span class=&n&&UserProfileViewModel&/span&&span class=&o&&.&/span&&span class=&na&&class&/span&&span class=&o&&);&/span&
&span class=&n&&viewModel&/span&&span class=&o&&.&/span&&span class=&na&&init&/span&&span class=&o&&(&/span&&span class=&n&&userId&/span&&span class=&o&&);&/span&
&span class=&o&&}&/span&
&span class=&nd&&@Override&/span&
&span class=&kd&&public&/span& &span class=&n&&View&/span& &span class=&nf&&onCreateView&/span&&span class=&o&&(&/span&&span class=&n&&LayoutInflater&/span& &span class=&n&&inflater&/span&&span class=&o&&,&/span&
&span class=&nd&&@Nullable&/span& &span class=&n&&ViewGroup&/span& &span class=&n&&container&/span&&span class=&o&&,&/span& &span class=&nd&&@Nullable&/span& &span class=&n&&Bundle&/span& &span class=&n&&savedInstanceState&/span&&span class=&o&&)&/span& &span class=&o&&{&/span&
&span class=&k&&return&/span& &span class=&n&&inflater&/span&&span class=&o&&.&/span&&span class=&na&&inflate&/span&&span class=&o&&(&/span&&span class=&n&&R&/span&&span class=&o&&.&/span&&span class=&na&&layout&/span&&span class=&o&&.&/span&&span class=&na&&user_profile&/span&&span class=&o&&,&/span& &span class=&n&&container&/span&&span class=&o&&,&/span& &span class=&kc&&false&/span&&span class=&o&&);&/span&
&span class=&o&&}&/span&
&span class=&o&&}&/span&
&/code&&/pre&&/div&&u&注意其中的 ViewModel 和 LifecycleFragment 都是 Android 新引入的,可以参考&a href=&http://link.zhihu.com/?target=https%3A//developer.android.com/topic/libraries/architecture/adding-components.html& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&官方说明&/a&进行集成。&/u&&p&现在,我们完成了这三个模块,该如何将它们联系起来呢?也就是当 ViewModel 中的用户字段被设置时,我们需要一种方法来通知 UI。这就是 &b&LiveData &/b&的用武之地了。&/p&&blockquote&&a href=&http://link.zhihu.com/?target=https%3A//developer.android.com/topic/libraries/architecture/livedata.html& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&LiveData&/a& 是一个可被观察的数据持有者(用到了观察者模式)。其能够允许 Activity, Fragment 等应用程序组件对其进行观察,并且不会在它们之间创建强依赖。LiveData 还能够自动响应各组件的声明周期事件,防止内存泄漏,从而使应用程序不会消耗更多的内存。&br&&br&&b&注意&/b&:LiveData 和 RxJava 或 Agera 的区别主要在于 LiveData 自动帮助处理了生命周期事件,避免了内存泄漏。&/blockquote&&p&所以,现在我们来修改一下 UserProfileViewModel:&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&public class UserProfileViewModel extends ViewModel {
private LiveData&User&
public LiveData&User& getUser() {
&/code&&/pre&&/div&&p&再在 UserProfileFragment 中对其进行观察并更新我们的 UI:&/p&&div class=&highlight&&&pre&&code class=&language-java&&&span&&/span&&span class=&nd&&@Override&/span&
&span class=&kd&&public&/span& &span class=&kt&&void&/span& &span class=&nf&&onActivityCreated&/span&&span class=&o&&(&/span&&span class=&nd&&@Nullable&/span& &span class=&n&&Bundle&/span& &span class=&n&&savedInstanceState&/span&&span class=&o&&)&/span& &span class=&o&&{&/span&
&span class=&kd&&super&/span&&span class=&o&&.&/span&&span class=&na&&onActivityCreated&/span&&span class=&o&&(&/span&&span class=&n&&savedInstanceState&/span&&span class=&o&&);&/span&
&span class=&n&&viewModel&/span&&span class=&o&&.&/span&&span class=&na&&getUser&/span&&span class=&o&&().&/span&&span class=&na&&observe&/span&&span class=&o&&(&/span&&span class=&k&&this&/span&&span class=&o&&,&/span& &span class=&n&&user&/span& &span class=&o&&-&&/span& &span class=&o&&{&/span&
&span class=&c1&&// update UI&/span&
&span class=&o&&});&/span&
&span class=&o&&}&/span&
&/code&&/pre&&/div&&p&&b&获取数据&/b&&/p&&p&现在,我们联系了 ViewModel 和 Fragment,但 ViewModel 又怎么来获取到数据呢?&/p&&p&在这个示例中,我们假定后端提供了 REST API,因此我们选用 &a href=&http://link.zhihu.com/?target=http%3A//square.github.io/retrofit/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Retrofit&/a& 来访问我们的后端。&/p&&p&首先,定义一个 Webservice:&/p&&div class=&highlight&&&pre&&code class=&language-java&&&span&&/span&&span class=&kd&&public&/span& &span class=&kd&&interface&/span& &span class=&nc&&Webservice&/span& &span class=&o&&{&/span&
&span class=&cm&&/**&/span&
&span class=&cm&&
* @GET declares an HTTP GET request&/span&
&span class=&cm&&
* @Path(&user&) annotation on the userId parameter marks it as a&/span&
&span class=&cm&&
* replacement for the {user} placeholder in the @GET path&/span&
&span class=&cm&&
&span class=&nd&&@GET&/span&&span class=&o&&(&/span&&span class=&s&&&/users/{user}&&/span&&span class=&o&&)&/span&
&span class=&n&&Call&/span&&span class=&o&&&&/span&&span class=&n&&User&/span&&span class=&o&&&&/span& &span class=&nf&&getUser&/span&&span class=&o&&(&/span&&span class=&nd&&@Path&/span&&span class=&o&&(&/span&&span class=&s&&&user&&/span&&span class=&o&&)&/span& &span class=&n&&String&/span& &span class=&n&&userId&/span&&span class=&o&&);&/span&
&span class=&o&&}&/span&
&/code&&/pre&&/div&&p&不要通过 ViewModel 直接来获取数据,这里我们将工作转交给一个新的 &strong&Repository&/strong& 模块。&/p&&blockquote&Repository 模块负责数据处理,为应用的其他部分提供干净可靠的 API。你可以将其考虑为不同数据源(Web,缓存或数据库)与应用之间的中间层。&/blockquote&&div class=&highlight&&&pre&&code class=&language-java&&&span&&/span&&span class=&kd&&public&/span& &span class=&kd&&class&/span& &span class=&nc&&UserRepository&/span& &span class=&o&&{&/span&
&span class=&kd&&private&/span& &span class=&n&&Webservice&/span& &span class=&n&&webservice&/span&&span class=&o&&;&/span&
&span class=&c1&&// ...&/span&
&span class=&kd&&public&/span& &span class=&n&&LiveData&/span&&span class=&o&&&&/span&&span class=&n&&User&/span&&span class=&o&&&&/span& &span class=&nf&&getUser&/span&&span class=&o&&(&/span&&span class=&kt&&int&/span& &span class=&n&&userId&/span&&span class=&o&&)&/span& &span class=&o&&{&/span&
&span class=&c1&&// This is not an optimal implementation, we'll fix it below&/span&
&span class=&kd&&final&/span& &span class=&n&&MutableLiveData&/span&&span class=&o&&&&/span&&span class=&n&&User&/span&&span class=&o&&&&/span& &span class=&n&&data&/span& &span class=&o&&=&/span& &span class=&k&&new&/span& &span class=&n&&MutableLiveData&/span&&span class=&o&&&&();&/span&
&span class=&n&&webservice&/span&&span class=&o&&.&/span&&span class=&na&&getUser&/span&&span class=&o&&(&/span&&span class=&n&&userId&/span&&span class=&o&&).&/span&&span class=&na&&enqueue&/span&&span class=&o&&(&/span&&span class=&k&&new&/span& &span class=&n&&Callback&/span&&span class=&o&&&&/span&&span class=&n&&User&/span&&span class=&o&&&()&/span& &span class=&o&&{&/span&
&span class=&nd&&@Override&/span&
&span class=&kd&&public&/span& &span class=&kt&&void&/span& &span class=&nf&&onResponse&/span&&span class=&o&&(&/span&&span class=&n&&Call&/span&&span class=&o&&&&/span&&span class=&n&&User&/span&&span class=&o&&&&/span& &span class=&n&&call&/span&&span class=&o&&,&/span& &span class=&n&&Response&/span&&span class=&o&&&&/span&&span class=&n&&User&/span&&span class=&o&&&&/span& &span class=&n&&response&/span&&span class=&o&&)&/span& &span class=&o&&{&/span&
&span class=&c1&&// error case is left out for brevity&/span&
&span class=&n&&data&/span&&span class=&o&&.&/span&&span class=&na&&setValue&/span&&span class=&o&&(&/span&&span class=&n&&response&/span&&span class=&o&&.&/span&&span class=&na&&body&/span&&span class=&o&&());&/span&
&span class=&o&&}&/span&
&span class=&o&&});&/span&
&span class=&k&&return&/span& &span class=&n&&data&/span&&span class=&o&&;&/span&
&span class=&o&&}&/span&
&span class=&o&&}&/span&
&/code&&/pre&&/div&&p&&b&管理组件间的依赖关系&/b&&/p&&p&根据上面的代码,我们可以看到 UserRepository 中有一个 Webservice 的实例,不要直接在 UserRepository 中 new 一个 Webservice。这很容易导致代码的重复与复杂化,比如 UserRepository 很可能不是唯一用到 Webservice 的类,如果每个用到的类都新建一个 Webservice,这显示会导致资源的浪费。&/p&&p&这里,我们推荐使用 &a href=&http://link.zhihu.com/?target=https%3A//google.github.io/dagger/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Dagger 2&/a& 来管理这些依赖关系。&/p&&p&现在,让我们来把 ViewModel 和 Repository 连接起来吧:&/p&&div class=&highlight&&&pre&&code class=&language-java&&&span&&/span&&span class=&kd&&public&/span& &span class=&kd&&class&/span& &span class=&nc&&UserProfileViewModel&/span& &span class=&kd&&extends&/span& &span class=&n&&ViewModel&/span& &span class=&o&&{&/span&
&span class=&kd&&private&/span& &span class=&n&&LiveData&/span&&span class=&o&&&&/span&&span class=&n&&User&/span&&span class=&o&&&&/span& &span class=&n&&user&/span&&span class=&o&&;&/span&
&span class=&kd&&private&/span& &span class=&n&&UserRepository&/span& &span class=&n&&userRepo&/span&&span class=&o&&;&/span&
&span class=&nd&&@Inject&/span& &span class=&c1&&// UserRepository parameter is provided by Dagger 2&/span&
&span class=&kd&&public&/span& &span class=&nf&&UserProfileViewModel&/span&&span class=&o&&(&/span&&span class=&n&&UserRepository&/span& &span class=&n&&userRepo&/span&&span class=&o&&)&/span& &span class=&o&&{&/span&
&span class=&k&&this&/span&&span class=&o&&.&/span&&span class=&na&&userRepo&/span& &span class=&o&&=&/span& &span class=&n&&userRepo&/span&&span class=&o&&;&/span&
&span class=&o&&}&/span&
&span class=&kd&&public&/span& &span class=&kt&&void&/span& &span class=&nf&&init&/span&&span class=&o&&(&/span&&span class=&n&&String&/span& &span class=&n&&userId&/span&&span class=&o&&)&/span& &span class=&o&&{&/span&
&span class=&k&&if&/span& &span class=&o&&(&/span&&span class=&k&&this&/span&&span class=&o&&.&/span&&span class=&na&&user&/span& &span class=&o&&!=&/span& &span class=&kc&&null&/span&&span class=&o&&)&/span& &span class=&o&&{&/span&
&span class=&c1&&// ViewModel is created per Fragment so&/span&
&span class=&c1&&// we know the userId won't change&/span&
&span class=&k&&return&/span&&span class=&o&&;&/span&
&span class=&o&&}&/span&
&span class=&n&&user&/span& &span class=&o&&=&/span& &span class=&n&&userRepo&/span&&span class=&o&&.&/span&&span class=&na&&getUser&/span&&span class=&o&&(&/span&&span class=&n&&userId&/span&&span class=&o&&);&/span&
&span class=&o&&}&/span&
&span class=&kd&&public&/span& &span class=&n&&LiveData&/span&&span class=&o&&&&/span&&span class=&n&&User&/span&&span class=&o&&&&/span& &span class=&nf&&getUser&/span&&span class=&o&&()&/span& &span class=&o&&{&/span&
&span class=&k&&return&/span& &span class=&k&&this&/span&&span class=&o&&.&/span&&span class=&na&&user&/span&&span class=&o&&;&/span&
&span class=&o&&}&/span&
&span class=&o&&}&/span&
&/code&&/pre&&/div&&p&&b&缓存数据&/b&&/p&&p&在实际项目中,Repository 往往不会只有一个数据源。因此,我们这里在其中再加入缓存:&/p&&div class=&highlight&&&pre&&code class=&language-java&&&span&&/span&&span class=&nd&&@Singleton&/span&
&span class=&c1&&// informs Dagger that this class should be constructed once&/span&
&span class=&kd&&public&/span& &span class=&kd&&class&/span& &span class=&nc&&UserRepository&/span& &span class=&o&&{&/span&
&span class=&kd&&private&/span& &span class=&n&&Webservice&/span& &span class=&n&&webservice&/span&&span class=&o&&;&/span&
&span class=&c1&&// simple in memory cache, details omitted for brevity&/span&
&span class=&kd&&private&/span& &span class=&n&&UserCache&/span& &span class=&n&&userCache&/span&&span class=&o&&;&/span&
&span class=&kd&&public&/span& &span class=&n&&LiveData&/span&&span class=&o&&&&/span&&span class=&n&&User&/span&&span class=&o&&&&/span& &span class=&nf&&getUser&/span&&span class=&o&&(&/span&&span class=&n&&String&/span& &span class=&n&&userId&/span&&span class=&o&&)&/span& &span class=&o&&{&/span&
&span class=&n&&LiveData&/span&&span class=&o&&&&/span&&span class=&n&&User&/span&&span class=&o&&&&/span& &span class=&n&&cached&/span& &span class=&o&&=&/span& &span class=&n&&userCache&/span&&span class=&o&&.&/span&&span class=&na&&get&/span&&span class=&o&&(&/span&&span class=&n&&userId&/span&&span class=&o&&);&/span&
&span class=&k&&if&/span& &span class=&o&&(&/span&&span class=&n&&cached&/span& &span class=&o&&!=&/span& &span class=&kc&&null&/span&&span class=&o&&)&/span& &span class=&o&&{&/span&
&span class=&k&&return&/span& &span class=&n&&cached&/span&&span class=&o&&;&/span&
&span class=&o&&}&/span&
&span class=&kd&&final&/span& &span class=&n&&MutableLiveData&/span&&span class=&o&&&&/span&&span class=&n&&User&/span&&span class=&o&&&&/span& &span class=&n&&data&/span& &span class=&o&&=&/span& &span class=&k&&new&/span& &span class=&n&&MutableLiveData&/span&&span class=&o&&&&();&/span&
&span class=&n&&userCache&/span&&span class=&o&&.&/span&&span class=&na&&put&/span&&span class=&o&&(&/span&&span class=&n&&userId&/span&&span class=&o&&,&/span& &span class=&n&&data&/span&&span class=&o&&);&/span&
&span class=&c1&&// this is still suboptimal but better than before.&/span&
&span class=&c1&&// a complete implementation must also handle the error cases.&/span&
&span class=&n&&webservice&/span&&span class=&o&&.&/span&&span class=&na&&getUser&/span&&span class=&o&&(&/span&&span class=&n&&userId&/span&&span class=&o&&).&/span&&span class=&na&&enqueue&/span&&span class=&o&&(&/span&&span class=&k&&new&/span& &span class=&n&&Callback&/span&&span class=&o&&&&/span&&span class=&n&&User&/span&&span class=&o&&&()&/span& &span class=&o&&{&/span&
&span class=&nd&&@Override&/span&
&span class=&kd&&public&/span& &span class=&kt&&void&/span& &span class=&nf&&onResponse&/span&&span class=&o&&(&/span&&span class=&n&&Call&/span&&span class=&o&&&&/span&&span class=&n&&User&/span&&span class=&o&&&&/span& &span class=&n&&call&/span&&span class=&o&&,&/span& &span class=&n&&Response&/span&&span class=&o&&&&/span&&span class=&n&&User&/span&&span class=&o&&&&/span& &span class=&n&&response&/span&&span class=&o&&)&/span& &span class=&o&&{&/span&
&span class=&n&&data&/span&&span class=&o&&.&/span&&span class=&na&&setValue&/span&&span class=&o&&(&/span&&span class=&n&&response&/span&&span class=&o&&.&/span&&span class=&na&&body&/span&&span class=&o&&());&/span&
&span class=&o&&}&/span&
&span class=&o&&});&/span&
&span class=&k&&return&/span& &span class=&n&&data&/span&&span class=&o&&;&/span&
&span class=&o&&}&/span&
&span class=&o&&}&/span&
&/code&&/pre&&/div&&p&&b&持久化数据&/b&&/p&&p&现在当用户旋转屏幕或暂时离开应用再回来时,数据是直接可见的,因为是直接从缓存中获取的数据。但要是用户长时间关闭应用,并且 Android 还彻底杀死了进程呢?&/p&&p&我们目前的实现中,会再次从网络中获取数据。这可不是一个好的用户体验。这时就需要数据持久化了。继续引入一个新组件 &strong&&a href=&http://link.zhihu.com/?target=https%3A//developer.android.com/topic/libraries/architecture/room.html& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Room&/a&。&/strong&&/p&&blockquote&Room 能帮助我们方便的实现本地数据持久化,抽象出了很多常用的数据库操作,并且在编译时会验证每个查询,从而损坏的 SQL 查询只会导致编译时错误,而不是运行时崩溃。还能和上面介绍的 LiveData 完美合作,并帮开发者处理了很多线程问题。&/blockquote&&p&现在,让我们来看看怎么使用 Room 吧。: )&/p&&p&首先,在 User 类上面加上 @Entity,将 User 声明为你数据库中的一张表。&/p&&div class=&highlight&&&pre&&code class=&language-java&&&span&&/span&&span class=&nd&&@Entity&/span&
&span class=&kd&&class&/span& &span class=&nc&&User&/span& &span class=&o&&{&/span&
&span class=&nd&&@PrimaryKey&/span&
&span class=&kd&&private&/span& &span class=&kt&&int&/span& &span class=&n&&id&/span&&span class=&o&&;&/span&
&span class=&kd&&private&/span& &span class=&n&&String&/span& &span class=&n&&name&/span&&span class=&o&&;&/span&
&span class=&kd&&private&/span& &span class=&n&&String&/span& &span class=&n&&lastName&/span&&span class=&o&&;&/span&
&span class=&c1&&// getters and setters for fields&/span&
&span class=&o&&}&/span&
&/code&&/pre&&/div&&p&再创建数据库类并继承 &a href=&http://link.zhihu.com/?target=https%3A//developer.android.com/reference/android/arch/persistence/room/RoomDatabase.html& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&RoomDatabase&/a&:&/p&&div class=&highlight&&&pre&&code class=&language-java&&&span&&/span&&span class=&nd&&@Database&/span&&span class=&o&&(&/span&&span class=&n&&entities&/span& &span class=&o&&=&/span& &span class=&o&&{&/span&&span class=&n&&User&/span&&span class=&o&&.&/span&&span class=&na&&class&/span&&span class=&o&&},&/span& &span class=&n&&version&/span& &span class=&o&&=&/span& &span class=&mi&&1&/span&&span class=&o&&)&/span&
&span class=&kd&&public&/span& &span class=&kd&&abstract&/span& &span class=&kd&&class&/span& &span class=&nc&&MyDatabase&/span& &span class=&kd&&extends&/span& &span class=&n&&RoomDatabase&/span& &span class=&o&&{&/span&
&span class=&o&&}&/span&
&/code&&/pre&&/div&&p&注意 MyDatabase 是一个抽象类,Room 会自动添加实现的。&/p&&p&现在我们需要一种方法来将用户数据插入到数据库:&/p&&div class=&highlight&&&pre&&code class=&language-java&&&span&&/span&&span class=&nd&&@Dao&/span&
&span class=&kd&&public&/span& &span class=&kd&&interface&/span& &span class=&nc&&UserDao&/span& &span class=&o&&{&/span&
&span class=&nd&&@Insert&/span&&span class=&o&&(&/span&&span class=&n&&onConflict&/span& &span class=&o&&=&/span& &span class=&n&&REPLACE&/span&&span class=&o&&)&/span&
&span class=&kt&&void&/span& &span class=&nf&&save&/span&&span class=&o&&(&/span&&span class=&n&&User&/span& &span class=&n&&user&/span&&span class=&o&&);&/span&
&span class=&nd&&@Query&/span&&span class=&o&&(&/span&&span class=&s&&&SELECT * FROM user WHERE id = :userId&&/span&&span class=&o&&)&/span&
&span class=&n&&LiveData&/span&&span class=&o&&&&/span&&span class=&n&&User&/span&&span class=&o&&&&/span& &span class=&nf&&load&/span&&span class=&o&&(&/span&&span class=&n&&String&/span& &span class=&n&&userId&/span&&span class=&o&&);&/span&
&span class=&o&&}&/span&
&/code&&/pre&&/div&&p&再在数据库类中加入 DAO:&/p&&div class=&highlight&&&pre&&code class=&language-java&&&span&&/span&&span class=&nd&&@Database&/span&&span class=&o&&(&/span&&span class=&n&&entities&/span& &span class=&o&&=&/span& &span class=&o&&{&/span&&span class=&n&&User&/span&&span class=&o&&.&/span&&span class=&na&&class&/span&&span class=&o&&},&/span& &span class=&n&&version&/span& &span class=&o&&=&/span& &span class=&mi&&1&/span&&span class=&o&&)&/span&
&span class=&kd&&public&/span& &span class=&kd&&abstract&/span& &span class=&kd&&class&/span& &span class=&nc&&MyDatabase&/span& &span class=&kd&&extends&/span& &span class=&n&&RoomDatabase&/span& &span class=&o&&{&/span&
&span class=&kd&&public&/span& &span class=&kd&&abstract&/span& &span class=&n&&UserDao&/span& &span class=&nf&&userDao&/span&&span class=&o&&();&/span&
&span class=&o&&}&/span&
&/code&&/pre&&/div&&p&注意上面的 load 方法返回的是 LiveData&User&,Room 会知道什么时候数据库发生了变化并自动通知所有的观察者。这也就是 LiveData 和 Room 搭配的妙用。&/p&&p&现在继续修改 UserRepository:&/p&&div class=&highlight&&&pre&&code class=&language-java&&&span&&/span&&span class=&nd&&@Singleton&/span&
&span class=&kd&&public&/span& &span class=&kd&&class&/span& &span class=&nc&&UserRepository&/span& &span class=&o&&{&/span&
&span class=&kd&&private&/span& &span class=&kd&&final&/span& &span class=&n&&Webservice&/span& &span class=&n&&webservice&/span&&span class=&o&&;&/span&
&span class=&kd&&private&/span& &span class=&kd&&final&/span& &span class=&n&&UserDao&/span& &span class=&n&&userDao&/span&&span class=&o&&;&/span&
&span class=&kd&&private&/span& &span class=&kd&&final&/span& &span class=&n&&Executor&/span& &span class=&n&&executor&/span&&span class=&o&&;&/span&
&span class=&nd&&@Inject&/span&
&span class=&kd&&public&/span& &span class=&nf&&UserRepository&/span&&span class=&o&&(&/span&&span class=&n&&Webservice&/span& &span class=&n&&webservice&/span&&span class=&o&&,&/span& &span class=&n&&UserDao&/span& &span class=&n&&userDao&/span&&span class=&o&&,&/span& &span class=&n&&Executor&/span& &span class=&n&&executor&/span&&span class=&o&&)&/span& &span class=&o&&{&/span&
&span class=&k&&this&/span&&span class=&o&&.&/span&&span class=&na&&webservice&/span& &span class=&o&&=&/span& &span class=&n&&webservice&/span&&span class=&o&&;&/span&
&span class=&k&&this&/span&&span class=&o&&.&/span&&span class=&na&&userDao&/span& &span class=&o&&=&/span& &span class=&n&&userDao&/span&&span class=&o&&;&/span&
&span class=&k&&this&/span&&span class=&o&&.&/span&&span class=&na&&executor&/span& &span class=&o&&=&/span& &span class=&n&&executor&/span&&span class=&o&&;&/span&
&span class=&o&&}&/span&
&span class=&kd&&public&/span& &span class=&n&&LiveData&/span&&span class=&o&&&&/span&&span class=&n&&User&/span&&span class=&o&&&&/span& &span class=&nf&&getUser&/span&&span class=&o&&(&/span&&span class=&n&&String&/span& &span class=&n&&userId&/span&&span class=&o&&)&/span& &span class=&o&&{&/span&
&span class=&n&&refreshUser&/span&&span class=&o&&(&/span&&span class=&n&&userId&/span&&span class=&o&&);&/span&
&span class=&c1&&// return a LiveData directly from the database.&/span&
&span class=&k&&return&/span& &span class=&n&&userDao&/span&&span class=&o&&.&/span&&span class=&na&&load&/span&&span class=&o&&(&/span&&span class=&n&&userId&/span&&span class=&o&&);&/span&
&span class=&o&&}&/span&
&span class=&kd&&private&/span& &span class=&kt&&void&/span& &span class=&nf&&refreshUser&/span&&span class=&o&&(&/span&&span class=&kd&&final&/span& &span class=&n&&String&/span& &span class=&n&&userId&/span&&span class=&o&&)&/span& &span class=&o&&{&/span&
&span class=&n&&executor&/span&&span class=&o&&.&/span&&span class=&na&&execute&/span&&span class=&o&&(()&/span& &span class=&o&&-&&/span& &span class=&o&&{&/span&
&span class=&c1&&// running in a background thread&/span&
&span class=&c1&&// check if user was fetched recently&/span&
&span class=&kt&&boolean&/span& &span class=&n&&userExists&/span& &span class=&o&&=&/span& &span class=&n&&userDao&/span&&span class=&o&&.&/span&&span class=&na&&hasUser&/span&&span class=&o&&(&/span&&span class=&n&&FRESH_TIMEOUT&/span&&span class=&o&&);&/span&
&span class=&k&&if&/span& &span class=&o&&(!&/span&&span class=&n&&userExists&/span&&span class=&o&&)&/span& &span class=&o&&{&/span&
&span class=&c1&&// refresh the data&/span&
&span class=&n&&Response&/span& &span class=&n&&response&/span& &span class=&o&&=&/span& &span class=&n&&webservice&/span&&span class=&o&&.&/span&&span class=&na&&getUser&/span&&span class=&o&&(&/span&&span class=&n&&userId&/span&&span class=&o&&).&/span&&span class=&na&&execute&/span&&span class=&o&&();&/span&
&span class=&c1&&// TODO check for error etc.&/span&
&span class=&c1&&// Update the database.The LiveData will automatically refresh so&/span&
&span class=&c1&&// we don't need to do anything else here besides updating the database&/span&
&span class=&n&&userDao&/span&&span class=&o&&.&/span&&span class=&na&&save&/span&&span class=&o&&(&/span&&span class=&n&&response&/span&&span class=&o&&.&/span&&span class=&na&&body&/span&&span class=&o&&());&/span&
&span class=&o&&}&/span&
&span class=&o&&});&/span&
&span class=&o&&}&/span&
&span class=&o&&}&/span&
&/code&&/pre&&/div&&p&可以看到,即使我们更改了 UserRepository 中的数据源,我们也完全不需要修改 ViewModel 和 Fragment,这就是抽象的好处。同时还非常适合测试,我们可以在测试 UserProfileViewModel 时提供测试用的 UserRepository。&/p&&blockquote&下面部分的内容在原文中是作为附录,但我个人觉得也很重要,所以擅自挪上来,一起为大家介绍了。: )&/blockquote&&p&在上面的例子中,有心的大家可能发现了我们没有处理网络错误和正在加载状态。但在实际开发中其实是很重要的。这里,我们就实现一个工具类来根据不同的网络状况选择不同的数据源。&/p&&p&首先,实现一个 Resource 类:&/p&&div class=&highlight&&&pre&&code class=&language-java&&&span&&/span&&span class=&c1&&//a generic class that describes a data with a status&/span&
&span class=&kd&&public&/span& &span class=&kd&&class&/span& &span class=&nc&&Resource&/span&&span class=&o&&&&/span&&span class=&n&&T&/span&&span class=&o&&&&/span& &span class=&o&&{&/span&
&span class=&nd&&@NonNull&/span& &span class=&kd&&public&/span& &span class=&kd&&final&/span& &span class=&n&&Status&/span& &span class=&n&&status&/span&&span class=&o&&;&/span&
&span class=&nd&&@Nullable&/span& &span class=&kd&&public&/span& &span class=&kd&&final&/span& &span class=&n&&T&/span& &span class=&n&&data&/span&&span class=&o&&;&/span&
&span class=&nd&&@Nullable&/span& &span class=&kd&&public&/span& &span class=&kd&&final&/span& &span class=&n&&String&/span& &span class=&n&&message&/span&&span class=&o&&;&/span&
&span class=&kd&&private&/span& &span class=&nf&&Resource&/span&&span class=&o&&(&/span&&span class=&nd&&@NonNull&/span& &span class=&n&&Status&/span& &span class=&n&&status&/span&&span class=&o&&,&/span& &span class=&nd&&@Nullable&/span& &span class=&n&&T&/span& &span class=&n&&data&/span&&span class=&o&&,&/span& &span class=&nd&&@Nullable&/span& &span class=&n&&String&/span& &span class=&n&&message&/span&&span class=&o&&)&/span& &span class=&o&&{&/span&
&span class=&k&&this&/span&&span class=&o&&.&/span&&span class=&na&&status&/span& &span class=&o&&=&/span& &span class=&n&&status&/span&&span class=&o&&;&/span&
&span class=&k&&this&/span&&span class=&o&&.&/span&&span class=&na&&data&/span& &span class=&o&&=&/span& &span class=&n&&data&/span&&span class=&o&&;&/span&
&span class=&k&&this&/span&&span class=&o&&.&/span&&span class=&na&&message&/span& &span class=&o&&=&/span& &span class=&n&&message&/span&&span class=&o&&;&/span&
&span class=&o&&}&/span&
&span class=&kd&&public&/span& &span class=&kd&&static&/span& &span class=&o&&&&/span&&span class=&n&&T&/span&&span class=&o&&&&/span& &span class=&n&&Resource&/span&&span class=&o&&&&/span&&span class=&n&&T&/span&&span class=&o&&&&/span& &span class=&nf&&success&/span&&span class=&o&&(&/span&&span class=&nd&&@NonNull&/span& &span class=&n&&T&/span& &span class=&n&&data&/span&&span class=&o&&)&/span& &span class=&o&&{&/span&
&span class=&k&&return&/span& &span class=&k&&new&/span& &span class=&n&&Resource&/span&&span class=&o&&&&(&/span&&span class=&n&&SUCCESS&/span&&span class=&o&&,&/span& &span class=&n&&data&/span&&span class=&o&&,&/span& &span class=&kc&&null&/span&&span class=&o&&);&/span&
&span class=&o&&}&/span&
&span class=&kd&&public&/span& &span class=&kd&&static&/span& &span class=&o&&&&/span&&span class=&n&&T&/span&&span class=&o&&&&/span& &span class=&n&&Resource&/span&&span class=&o&&&&/span&&span class=&n&&T&/span&&span class=&o&&&&/span& &span class=&nf&&error&/span&&span class=&o&&(&/span&&span class=&n&&String&/span& &span class=&n&&msg&/span&&span class=&o&&,&/span& &span class=&nd&&@Nullable&/span& &span class=&n&&T&/span& &span class=&n&&data&/span&&span class=&o&&)&/span& &span class=&o&&{&/span&
&span class=&k&&return&/span& &span class=&k&&new&/span& &span class=&n&&Resource&/span&&span class=&o&&&&(&/span&&span class=&n&&ERROR&/span&&span class=&o&&,&/span& &span class=&n&&data&/span&&span class=&o&&,&/span& &span class=&n&&msg&/span&&span class=&o&&);&/span&
&span class=&o&&}&/span&
&span class=&kd&&public&/span& &span class=&kd&&static&/span& &span class=&o&&&&/span&&span class=&n&&T&/span&&span class=&o&&&&/span& &span class=&n&&Resource&/span&&span class=&o&&&&/span&&span class=&n&&T&/span&&span class=&o&&&&/span& &span class=&nf&&loading&/span&&span class=&o&&(&/span&&span class=&nd&&@Nullable&/span& &span class=&n&&T&/span& &span class=&n&&data&/span&&span class=&o&&)&/span& &span class=&o&&{&/span&
&span class=&k&&return&/span& &span class=&k&&new&/span& &span class=&n&&Resource&/span&&span class=&o&&&&(&/span&&span class=&n&&LOADING&/span&&span class=&o&&,&/span& &span class=&n&&data&/span&&span class=&o&&,&/span& &span class=&kc&&null&/span&&span class=&o&&);&/span&
&span class=&o&&}&/span&
&span class=&o&&}&/span&
&/code&&/pre&&/div&&p&因为,从网络加载数据和从磁盘加载是很相似的,所以再新建一个 NetworkBoundResource 类,方便多处复用。下面是 NetworkBoundResource 的决策树:&/p&&p&&figure&&img data-rawwidth=&534& data-rawheight=&465& src=&http://pic4.zhimg.com/v2-fc7fbc0139441cab1ea3_b.png& class=&origin_image zh-lightbox-thumb& width=&534& data-original=&http://pic4.zhimg.com/v2-fc7fbc0139441cab1ea3_r.png&&&/figure&API 设计:&/p&&div class=&highlight&&&pre&&code class=&language-java&&&span&&/span&&span class=&c1&&// ResultType: Type for the Resource data&/span&
&span class=&c1&&// RequestType: Type for the API response&/span&
&span class=&kd&&public&/span& &span class=&kd&&abstract&/span& &span class=&kd&&class&/span& &span class=&nc&&NetworkBoundResource&/span&&span class=&o&&&&/span&&span class=&n&&ResultType&/span&&span class=&o&&,&/span& &span class=&n&&RequestType&/span&&span class=&o&&&&/span& &span class=&o&&{&/span&
&span class=&c1&&// Called to save the result of the API response into the database&/span&
&span class=&nd&&@WorkerThread&/span&
&span class=&kd&&protected&/span& &span class=&kd&&abstract&/span& &span class=&kt&&void&/span& &span class=&nf&&saveCallResult&/span&&span class=&o&&(&/span&&span class=&nd&&@NonNull&/span& &span class=&n&&RequestType&/span& &span class=&n&&item&/span&&span class=&o&&);&/span&
&span class=&c1&&// Called with the data in the database to decide whether it should be&/span&
&span class=&c1&&// fetched from the network.&/span&
&span class=&nd&&@MainThread&/span&
&span class=&kd&&protected&/span& &span class=&kd&&abstract&/span& &span class=&kt&&boolean&/span& &span class=&nf&&shouldFetch&/span&&span class=&o&&(&/span&&span class=&nd&&@Nullable&/span& &span class=&n&&ResultType&/span& &span class=&n&&data&/span&&span class=&o&&);&/span&
&span class=&c1&&// Called to get the cached data from the database&/span&
&span class=&nd&&@NonNull&/span& &span class=&nd&&@MainThread&/span&
&span class=&kd&&protected&/span& &span class=&kd&&abstract&/span& &span class=&n&&LiveData&/span&&span class=&o&&&&/span&&span class=&n&&ResultType&/span&&span class=&o&&&&/span& &span class=&nf&&loadFromDb&/span&&span class=&o&&();&/span&
&span class=&c1&&// Called to create the API call.&/span&
&span class=&nd&&@NonNull&/span& &span class=&nd&&@MainThread&/span&
&span class=&kd&&protected&/span& &span class=&kd&&abstract&/span& &span class=&n&&LiveData&/span&&span class=&o&&&&/span&&span class=&n&&ApiResponse&/span&&span class=&o&&&&/span&&span class=&n&&RequestType&/span&&span class=&o&&&&&/span& &span class=&nf&&createCall&/span&&span class=&o&&();&/span&
&span class=&c1&&// Called when the fetch fails. The child class may want to reset components&/span&
&span class=&c1&&// like rate limiter.&/span&
&span class=&nd&&@MainThread&/span&
&span class=&kd&&protected&/span& &span class=&kt&&void&/span& &span class=&nf&&onFetchFailed&/span&&span class=&o&&()&/span& &span class=&o&&{&/span&
&span class=&o&&}&/span&
&span class=&c1&&// returns a LiveData that represents the resource&/span&
&span class=&kd&&public&/span& &span class=&kd&&final&/span& &span class=&n&&LiveData&/span&&span class=&o&&&&/span&&span class=&n&&Resource&/span&&span class=&o&&&&/span&&span class=&n&&ResultType&/span&&span class=&o&&&&&/span& &span class=&nf&&getAsLiveData&/span&&span class=&o&&()&/span& &span class=&o&&{&/span&
&span class=&k&&return&/span& &span class=&n&&result&/span&&span class=&o&&;&/span&
&span class=&o&&}&/span&
&span class=&o&&}&/span&
&/code&&/pre&&/div&&p&注意上面使用了 ApiResponse 作为网络请求, ApiResponse 是对于 Retrofit2.Call 的简单包装,用于将其响应转换为 LiveData。&/p&&p&下面是具体的实现:&/p&&div class=&highlight&&&pre&&code class=&language-java&&&span&&/span&&span class=&kd&&public&/span& &span class=&kd&&abstract&/span& &span class=&kd&&class&/span& &span class=&nc&&NetworkBoundResource&/span&&span class=&o&&&&/span&&span class=&n&&ResultType&/span&&span class=&o&&,&/span& &span class=&n&&RequestType&/span&&span class=&o&&&&/span& &span class=&o&&{&/span&
&span class=&kd&&private&/span& &span class=&kd&&final&/span& &span class=&n&&MediatorLiveData&/span&&span class=&o&&&&/span&&span class=&n&&Resource&/span&&span class=&o&&&&/span&&span class=&n&&ResultType&/span&&span class=&o&&&&&/span& &span class=&n&&result&/span& &span class=&o&&=&/span& &span class=&k&&new&/span& &span class=&n&&MediatorLiveData&/span&&span class=&o&&&&();&/span&
&span class=&nd&&@MainThread&/span&
&span class=&n&&NetworkBoundResource&/span&&span class=&o&&()&/span& &span class=&o&&{&/span&
&span class=&n&&result&/span&&span class=&o&&.&/span&&span class=&na&&setValue&/span&&span class=&o&&(&/span&&span class=&n&&Resource&/span&&span class=&o&&.&/span&&span class=&na&&loading&/span&&span class=&o&&(&/span&&span class=&kc&&null&/span&&span class=&o&&));&/span&
&span class=&n&&LiveData&/span&&span class=&o&&&&/span&&span class=&n&&ResultType&/span&&span class=&o&&&&/span& &span class=&n&&dbSource&/span& &span class=&o&&=&/span& &span class=&n&&loadFromDb&/span&&span class=&o&&();&/span&
&span class=&n&&result&/span&&span class=&o&&.&/span&&span class=&na&&addSource&/span&&span class=&o&&(&/span&&span class=&n&&dbSource&/span&&span class=&o&&,&/span& &span class=&n&&data&/span& &span class=&o&&-&&/span& &span class=&o&&{&/span&
&span class=&n&&result&/span&&span class=&o&&.&/span&&span class=&na&&removeSource&/span&&span class=&o&&(&/span&&span class=&n&&dbSource&/span&&span class=&o&&);&/span&
&span class=&k&&if&/span& &span class=&o&&(&/span&&span class=&n&&shouldFetch&/span&&span class=&o&&(&/span&&span class=&n&&data&/span&&span class=&o&&))&/span& &span class=&o&&{&/span&
&span class=&n&&fetchFromNetwork&/span&&span class=&o&&(&/span&&span class=&n&&dbSource&/span&&span class=&o&&);&/span&
&span class=&o&&}&/span& &span class=&k&&else&/span& &span class=&o&&{&/span&
&span class=&n&&result&/span&&span class=&o&&.&/span&&span class=&na&&addSource&/span&&span class=&o&&(&/span&&span class=&n&&dbSource&/span&&span class=&o&&,&/span&
&span class=&n&&newData&/span& &span class=&o&&-&&/span& &span class=&n&&result&/span&&span class=&o&&.&/span&&span class=&na&&setValue&/span&&span class=&o&&(&/span&&span class=&n&&Resource&/span&&span class=&o&&.&/span&&span class=&na&&success&/span&&span class=&o&&(&/span&&span class=&n&&newData&/span&&span class=&o&&)));&/span&
&span class=&o&&}&/span&
&span class=&o&&});&/span&
&span class=&o&&}&/span&
&span class=&kd&&private&/span& &span class=&kt&&void&/span& &span class=&nf&&fetchFromNetwork&/span&&span class=&o&&(&/span&&span class=&kd&&final&/span& &span class=&n&&LiveData&/span&&span class=&o&&&&/span&&span class=&n&&ResultType&/span&&span class=&o&&&&/span& &span class=&n&&dbSource&/span&&span class=&o&&)&/span& &span class=&o&&{&/span&
&span class=&n&&LiveData&/span&&span class=&o&&&&/span&&span class=&n&&ApiResponse&/span&&span class=&o&&&&/span&&span class=&n&&RequestType&/span&&span class=&o&&&&&/span& &span class=&n&&apiResponse&/span& &span class=&o&&=&/span& &span class=&n&&createCall&/span&&span class=&o&&();&/span&
&span class=&c1&&// we re-attach dbSource as a new source,&/span&
&span class=&c1&&// it will dispatch its latest value quickly&/span&
&span class=&n&&result&/span&&span class=&o&&.&/span&&span class=&na&&addSource&/span&&span class=&o&&(&/span&&span class=&n&&dbSource&/span&&span class=&o&&,&/span&
&span class=&n&&newData&/span& &span class=&o&&-&&/span& &span class=&n&&result&/span&&span class=&o&&.&/span&&span class=&na&&setValue&/span&&span class=&o&&(&/span&&span class=&n&&Resource&/span&&span class=&o&&.&/span&&span class=&na&&loading&/span&&span class=&o&&(&/span&&span class=&n&&newData&/span&&span class=&o&&)));&/span&
&span class=&n&&result&/span&&span class=&o&&.&/span&&span class=&na&&addSource&/span&&span class=&o&&(&/span&&span class=&n&&apiResponse&/span&&span class=&o&&,&/span& &span class=&n&&response&/span& &span class=&o&&-&&/span& &span class=&o&&{&/span&
&span class=&n&&result&/span&&span class=&o&&.&/span&&span class=&na&&removeSource&/span&&span class=&o&&(&/span&&span class=&n&&apiResponse&/span&&span class=&o&&);&/span&
&span class=&n&&result&/span&&span class=&o&&.&/span&&span class=&na&&removeSource&/span&&span class=&o&&(&/span&&span class=&n&&dbSource&/span&&span class=&o&&);&/span&
&span class=&c1&&//noinspection ConstantConditions&/span&
&span class=&k&&if&/span& &span class=&o&&(&/span&&span class=&n&&response&/span&&span class=&o&&.&/span&&span class=&na&&isSuccessful&/span&&span class=&o&&())&/span& &span class=&o&&{&/span&
&span class=&n&&saveResultAndReInit&/span&&span class=&o&&(&/span&&span class=&n&&response&/span&&span class=&o&&);&/span&
&span class=&o&&}&/span& &span class=&k&&else&/span& &span class=&o&&{&/span&
&span class=&n&&onFetchFailed&/span&&span class=&o&&();&/span&
&span class=&n&&result&/span&&span class=&o&&.&/span&&span class=&na&&addSource&/span&&span class=&o&&(&/span&&span class=&n&&dbSource&/span&&span class=&o&&,&/span&
&span class=&n&&newData&/span& &span class=&o&&-&&/span& &span class=&n&&result&/span&&span class=&o&&.&/span&&span class=&na&&setValue&/span&&span class=&o&&(&/span&
&span class=&n&&Resource&/span&&span class=&o&&.&/span&&span class=&na&&error&/span&&span class=&o&&(&/span&&span class=&n&&response&/span&&span class=&o&&.&/span&&span class=&na&&errorMessage&/span&&span class=&o&&,&/span& &span class=&n&&newData&/span&&span class=&o&&)));&/span&
&span class=&o&&}&/span&
&span class=&o&&});&/span&
&span class=&o&&}&/span&
&span class=&nd&&@MainThread&/span&
&span class=&kd&&private&/span& &span class=&kt&&void&/span& &span class=&nf&&saveResultAndReInit&/span&&span class=&o&&(&/span&&span class=&n&&ApiResponse&/span&&span class=&o&&&&/span&&span class=&n&&RequestType&/span&&span class=&o&&&&/span& &span class=&n&&response&/span&&span class=&o&&)&/span& &span class=&o&&{&/span&
&span class=&k&&new&/span& &span class=&n&&AsyncTask&/span&&span class=&o&&&&/span&&span class=&n&&Void&/span&&span class=&o&&,&/span& &span class=&n&&Void&/span&&span class=&o&&,&/span& &span class=&n&&Void&/span&&span class=&o&&&()&/span& &span class=&o&&{&/span&
&span class=&nd&&@Override&/span&
&span class=&kd&&protected&/span& &span class=&n&&Void&/span& &span class=&nf&&doInBackground&/span&&span class=&o&&(&/span&&span class=&n&&Void&/span&&span class=&o&&...&/span& &span class=&n&&voids&/span&&span class=&o&&)&/span& &span class=&o&&{&/span&
&span class=&n&&saveCallResult&/span&&span class=&o&&(&/span&&span class=&n&&response&/span&&span class=&o&&.&/span&&span class=&na&&body&/span&&span class=&o&&);&/span&
&span class=&k&&return&/span& &span class=&kc&&null&/span&&span class=&o&&;&/span&
&span class=&o&&}&/span&
&span class=&nd&&@Override&/span&
&span class=&kd&&protected&/span& &span class=&kt&&void&/span& &span class=&nf&&onPostExecute&/span&&span class=&o&&(&/span&&span class=&n&&Void&/span& &span class=&n&&aVoid&/span&&span class=&o&&)&/span& &span class=&o&&{&/span&
&span class=&c1&&// we specially request a new live data,&/span&
&span class=&c1&&// otherwise we will get immediately last cached value,&/span&
&span class=&c1&&// which may not be updated with latest results received from n

我要回帖

更多关于 使用接口不使用继承 的文章

 

随机推荐