因为豆瓣关闭了我的开发者 API Key 申请,此应用已不可能向公众发布,所以决定提早开放源代码,也给有兴趣者作些 HACKING。html
如下是关于豆芽的说明。算法
图片:缓存
视频:bash
豆芽的名字取自“Douban, Yet Another”的缩写和中文词语“豆芽”的拼音正好相同的巧合。网络
取名以后,我才得知豆瓣的 Windows Phone 客户端的名字也叫作“豆芽”。因此相对于豆瓣官方应用“一个叫‘豆瓣’的App”,也正好将这个应用称为“另外一个叫豆芽的应用”了。架构
直接访问豆瓣的全部人里,最广泛而一致的用法是围绕电影、电视、书、唱片、活动(咱们叫作”条目”的东西)的评分评论、发现和讨论。咱们会把和网站同步的评分评论做为一个起点和基础,在手机上从新构建围绕我的兴趣的发现和讨论。框架
一个叫“豆瓣”的App——豆瓣日志异步
豆瓣历来不是一个单一的网站,而对于豆瓣的用法天然不尽相同。使用豆瓣是为了获取信息,但信息的获取是基于条目和算法,仍是基于友邻和人,这个问题在豆瓣的屡次改版中大概一直悬而未决。ide
此次,一个叫“豆瓣”的应用选择的是基于条目的推荐。但我我的做为一个重度豆瓣用户,重视的却刚好是基于人的推荐,喜欢的是友邻间的鸡犬相闻,以及闲逛时从条目评论、广播、日记中发现新友邻的惊喜。正如我在某次“还我旧版”运动中听到的声音,“无论怎么改版,只要友邻们还在就好”,改版是豆瓣不断良好发展的必经之路,但这句话中对友邻的珍重又令我感觉到了豆瓣最宝贵的特质。工具
豆瓣做为一个工具的价值能够经过条目很好体现,但豆瓣做为一个独一无二的社区,只能经过它独有的、克制的、以人为本的方式才能维系。做为一个普通但也深爱豆瓣的用户,我但愿豆瓣在这个方向上也不要失落,由于一个只有工具属性的网站对我而言将再也没有这样的归属感。
我在这一点上与豆瓣应用有了不一样的追求,而且刚好有一些这方面的能力,又刚好豆瓣提供了开放的 API,因而就想要将这个想法实现出来了。
选择开始豆芽这个项目,还有一个缘由是我但愿在豆瓣继续看到平台原生的设计。
豆瓣广播在几年前就已是国内少有的几个 Android Design 的应用,这一点一直令我钦佩和喜好。在豆瓣应用最开始的版本中,也曾有过 Material Design 的尝试,但随着和 iOS 风格设计的杂糅,逐渐显得不合时宜,以致于最终选择了彻底的 iOS 风格。我对此一直感到有些遗憾,何况 Material Design 也是一款更加优秀的设计语言。因此,我但愿实现未能见到的另外一种可能性。
豆芽的最终目标是为豆瓣中基于友邻的信息获取方式提供在移动端的便利。为了优雅地实现这个目标,豆芽将主要遵循如下的原则:
规则能够被打破,但前提是理解规则。
豆芽的架构将与当前网站的设计十分相似。
你可能会问,难道豆芽只是要作一个豆瓣网站源码的移动端界面么?并不是如此。豆芽的最终目标是为基于友邻的信息获取方式提供便利,因此架构设计也是为此服务。而架构与当前网页端设计基本相同,则是由于如今网页端正是一个符合这个目标的设计,而且与移动端的导航也能够很好地契合。
让咱们详细地规划一下豆芽吧。
导航采用抽屉一级导航 + 选项卡二级导航的方式。工具栏上将显示全局的动做。
在子页面设计中,豆芽将尽可能鼓励长内容和用心的互动。由于我相信只有豆瓣值得这样尝试。
我在最初的二十天内冲刺实现了应用的网络层、帐户系统等基础架构,和查看友邻广播须要的大部分功能,大约 8000 行代码。
在接下来的八十天中,因为课业、其余事情和速度瓶颈,实现过程有所减慢。可是,应用的细节功能和界面交互都正在不断地被实现和优化。代码量达到了 14000 行,同时为此应用而写做的多个开源库的数千行代码并无被计入。
目前实现了友邻广播的查看、回应、删除等操做,提醒的查看,以及相关的设置条目。剩下的工做也正在继续进行中。
应用除了对少数内容进行缓存,其余内容均直接从网络获取。
使用 Support Library 中的 AppCompat、Design、CardView、RecyclerView 进行 Material Design 实现,在必要时引入/本身写做第三方库以实现部分界面元素和效果。
使用框架的 Shared Element Transition 实如今 Android 5.0 以上的界面过渡动画。
界面实现通常分为 Activity、Fragment、Adapter 三个模块,分别负责做为容器,发起请求、展现数据和用户交互,以及数据/交互绑定。
Volley 自己是一个不算十分完备的库,对于请求参数、重试、认证等方面都须要开发者本身实现。在豆芽中,应用对 Volley 进行了包装,增长了以上功能,而且尽力作到了通用,为以后 API 层创建提供了不少方便。
DiskLRUCache 是一个只实现了同步读取写入的库,所以豆芽对其进行了包装,提供了异步读写的 API,正确实现,提升了应用的响应速度。
因为各个界面独自获取数据,数据自己与常规的 ContentProvider 机制中不一样,是去中心化的,便可能遇到状态不一样步的问题。
具体地说,即有可能用户在广播详情界面中点赞后,回到主界面列表视图,发现并未更新状态。
而豆芽解决方案则是使用 EventBus,在请求完成后通知全部界面刷新同一数据。
Android 5.0 以上提供了 SharedElementTransition,然而默认状况下共享的界面元素在动画时却会被放置在其余界面元素之上,致使其忽然越过 AppBar 或 StatusBar 的状况。
经过大量的文档阅读、源代码分析和调试,通过大约一周的时间,最终实现了较为理想的效果。
Android 在屏幕旋转时,会销毁视图和 Activity 并重建,此时如何保存视图状态和已加载的数据、正在进行的网络请求便是问题。
Android 对部分视图状态提供了自动保存恢复,而豆芽对于其余须要保存的状态则经过自定义的 onSaveViewState()
和onRestoreViewState()
。
对于数据,豆芽经过自定义的一个无界面的 RetainDataFragment
进行数据保留,而且接口十分简单易用。
同时,因为网络请求的异步特性,豆芽经过自定义的一个 RequestFragment
实现了网络请求在 Activity 重建期间的保留,而且可以在 Activity 重建完成后将请求前的状态和请求结果回调至新的 Activity。
Android 自己的资源系统提供了对不一样配置的很好支持,经过创建不一样的资源文件,便可在手机和平板上使用不一样的界面设定。
此外,因为采用了 RecyclerView,经过在运行时判断当前设备配置,能够动态给界面设置为 一、二、3 列视图,充分利用屏幕空间。
Android 默认在冷启动应用进程至可以调用 Activity.onCreate()
前会加载应用主题中的背景做为预览,而默认背景是白色,与应用在上部拥有绿色 AppBar 的效果不相匹配。
为了生成适应于不一样屏幕大小、系统版本的图片,我使用 bash 编写了一系列脚本,并实现了一个通用的模板化 SVG 格式,详情见 MaterialColdStart 和 AndroidSVGScripts。
通过自定义窗口背景和其余优化,应用在手机上已经能够达到当即启动的视觉效果。