本文已参与「新人创作礼」活动, 一起开启掘金创作之路。
本文是对下面链接中项目的注释,
正在学习项目源码 并且加入了自己的理解
请克隆项目,了解项目背景与软件功能后.结合源码查看本笔记
目录结构
app.src.main
│ AndroidManifest.xml // 软件应用清单文件包含了应用的配置信息,组件,需要的权限
│
├─assets //存储静态文件的文件夹
│ bensound-sunny.mp3
│ summary.html
│
├─java
│ └─com.kunminx.puremusic
│ │ App.java // Application对象 用于存放初始化view初始化前要执行的代码
│ │ MainActivity.java // 主要Activity对象 在这里初始化view
│ │
│ ├─data
│ │ ├─api // 存放http请求函数
│ │ │ AccountService.java // 定义了请求函数接口
│ │ │ APIs.java // 存放接口地址
│ │ │
│ │ ├─bean // 存放定义的bean对象
│ │ │ DownloadFile.java
│ │ │ LibraryInfo.java
│ │ │ TestAlbum.java
│ │ │ User.java
│ │ │
│ │ ├─config // 设置文件的路径
│ │ │ Configs.java
│ │ │
│ │ └─repository
│ │ DataRepository.java // 数据仓库,包含网络请求,上传下载,认证相关的函数, 任务随页面声明周期叫停, 下载进度使用使用 DataResult通知页面而非 LiveData
│ │ ILocalSource.java // 地址保存
│ │ IRemoteSource.java // 地址保存
│ │
│ ├─domain
│ │ ├─message
│ │ │ DrawerCoordinateManager.java // 抽屉侧滑控制器
│ │ │ SharedViewModel.java // UnPeekLiveData 配合 SharedViewModel 发送跨页面通知样例
│ │ │
│ │ ├─request
│ │ │ AccountRequest.java
│ │ │ DownloadRequest.java
│ │ │ InfoRequest.java
│ │ │ MusicRequest.java
│ │ │
│ │ └─usecase
│ │ CanBeStoppedUseCase.java // UseCase 例,实现LifeCycle接口,用于可叫停业务
│ │ DownloadUseCase.java
│ │
│ ├─player
│ │ │ PlayerManager.java // 播放管理器
│ │ │
│ │ ├─helper
│ │ │ PlayerCallHelper.java // 在来电时自动协调和暂停音乐播放
│ │ │ PlayerFileNameGenerator.java
│ │ │
│ │ └─notification
│ │ PlayerReceiver.java
│ │ PlayerService.java
│ │
│ └─ui
│ ├─base
│ │ └─binding_adapter // BindingAdapter实现了数据绑定,某一个绑定值(被观察者)改变后,绑定一个方法,然后执行相应逻辑
│ │ CommonBindingAdapter.java
│ │ DrawerBindingAdapter.java
│ │ IconBindingAdapter.java
│ │ TabPageBindingAdapter.java
│ │ WebViewBindingAdapter.java
│ │
│ ├─page // 每个页面都要单独配备一个 state-ViewModel,职责仅限于 "状态托管和恢复",
│ │ │ DrawerFragment.java
│ │ │ LoginFragment.java
│ │ │ MainFragment.java
│ │ │ PlayerFragment.java
│ │ │ SearchFragment.java
│ │ │
│ │ ├─adapter
│ │ │ DiffUtils.java
│ │ │ DrawerAdapter.java
│ │ │ PlaylistAdapter.java
│ │ │
│ │ └─helper
│ │ DefaultInterface.java
│ │
│ ├─state // 存放各个页面的ViewModel
│ │ DrawerViewModel.java
│ │ LoginViewModel.java
│ │ MainActivityViewModel.java
│ │ MainViewModel.java
│ │ PlayerViewModel.java
│ │ SearchViewModel.java
│ │
│ └─view
│ PlayerSlideListener.java
│ PlayPauseDrawable.java
│ PlayPauseView.java
│
└─res
├─anim // 定义应用中的动画表现
│ 内容略
│
├─drawable // 定义应用从存放的图标
│ 内容略
│ 有多个文件夹适配不同清晰度资源文件夹略
│
├─layout // 应用界面定义
│ activity_main.xml
│ adapter_library.xml
│ adapter_play_item.xml
│ fragment_drawer.xml
│ fragment_login.xml
│ fragment_main.xml
│ fragment_player.xml
│ fragment_search.xml
│ notify_player_big.xml
│ notify_player_small.xml
│
├─layout-land // 横屏的排列结构
│ activity_main.xml
│ fragment_main.xml
│ fragment_player.xml
│
├─navigation // 界面跳转定义
│ nav_drawer.xml
│ nav_main.xml
│ nav_slide.xml
│
├─values // 值
│ attrs.xml
│ colors.xml
│ dimen.xml
│ strings.xml
│ styles.xml
│
└─xml
network_security_config.xml
代码结构
重点了解
事件绑定代码位置
layout xml文件 -DataBinding-> Fragment.ClickProxy 通过在Fragment文件的ClickProxy集中编写点击事件 避免在xml文件中大量引入对象,同时避免了重复在Fragment中对所有需要点击事件的元素执行 找到视图对象 绑定对象 绑定点击事件的操作
应用分别由哪几部分组成
应用有一个带有ViewPager与搜索框的主界面
搭配上侧边栏与地下的播放器
点击搜索栏有登录页 ,搜索页
应用有哪几个页面/组件
主要应用:
activity_main
- 堆砌fragment
- 使用DataBinding导入自己ViewModel与ListenerHandler
- 这里用于编写程序的主体框架,用于组合fragment. 不放置业务与复杂的视图代码
fragment_main
- 设计主页面
- 使用DataBinding导入自己ViewModel, ClickProxy与Adapter
fragment_player
- 设计组件界面
- 使用DataBinding导入自己的ViewModel, ClickProxy与ListenerHandler
navigation的跳转 相关文件与定义
在activity_main.xml中使用@navigation/引入nav_main, nav_slide, nav_drawer三个资源
文件中action(动作) 定义了动画效果
layout xml文件命名方案 与文件组织
放在res.layout文件夹
前缀为文件类型如 activity, fragment adapter notify
adapter: RecyclerView内条目的展示样式
notify: 通知条样式
java 中对应fragment文件组织方式
在ui.page下, 一个类对应一个fragment
java 中对应fragment命名方式
大驼峰命名,以Fragment结尾
java 中对应ViewModel文件组织方式
所有activity与fragment分别对应一个ViewModel
java 中对应ViewModel命名方式
大驼峰
fragment以ViewModel结尾
activity以ActivityViewModel结尾
BindingAdapter是什么
编写带 @BindingAdapter 注解的方法可以允许程序员自行设定xml文件中的属性值, 设置对应属性值的对象会调用方法提供的自定义逻辑.
BindingAdapter的用法
在layout文件中, 如程序段中第二行
<TabLayout
android:id="@+id/tab_layout"
initTabAndPage="@{vm.initTabAndPage}"
android:layout_width="match_parent"
android:layout_height="48dp"
...
>
...
</TabLayout>
下面是适配器的编写方法
@BindingAdapter(value = {"initTabAndPage"}, requireAll = false)
public static void initTabAndPage(TabLayout tabLayout, boolean initTabAndPage) {
int count = tabLayout.getTabCount();
String[] title = new String[count];
...
}
这种写法是单向绑定, 当TabLayout初始化时, 会执行一次initTabAndPage方法. 第一个值是视图对象, 第二个值是layout xml文件中给传入的对象.
当值改变时, 会再执行一次该方法
注解中value后可以填写多个属性, 设置requireAll为假. 对象设置任意一个属性值, 都会调用此方法
Request类一般承担什么职责
Request 通常按业务划分 一个项目中通常存在多个 Request 类, 每个页面配备的 state-ViewModel 实例可根据业务需要持有多个不同的 Request 实例。
request 的职责仅限于 "业务逻辑处理" 和 "Event 分发",不建议在此处理 UI 逻辑, UI 逻辑只适合在 Activity/Fragment 等视图控制器中完成,是 “数据驱动” 的一部分,