Modify: 添加示例代码及注意事项

This commit is contained in:
Quyunshuo
2020-08-31 19:27:01 +08:00
parent 13b359ce8c
commit ff5af81f01

242
README.md
View File

@ -69,6 +69,248 @@ android {
* Repository 仓库层负责数据的提供,ViewModel 无需关心数据的来源,Repository 内避免使用 LiveData,框架里使用了 Kotlin 协程的 Flow 进行处理请求或访问数据库,最后将数据发射到 ViewModel 调用者,Flow上游负责提供数据,下游也就是ViewModel获取到数据使用LiveData进行存储,View层订阅LiveData,实现数据驱动视图
* 三者的依赖都是单向依赖,View -> ViewModel -> Repository
# <p align="center"> 示例代码及注意事项🐽</p>
## ViewModel
`ViewModel` 类旨在以注重生命周期的方式存储和管理界面相关的数据。`ViewModel` 类让数据可在发生屏幕旋转等配置更改后继续留存。
**使用方式:**
```
class MainViewModel : ViewModel(){
}
class MainActivity : AppCompatActivity() {
// 获取无参构造的ViewModel实例
val mViewModel = ViewModelProvider(this).get(MainViewModel::class.java)
}
```
**资料:**
官方文档: [https://developer.android.com/topic/libraries/architecture/viewmodel](https://developer.android.com/topic/libraries/architecture/viewmodel)
Android ViewModel再学不会你砍我: [https://juejin.im/post/6844903919064186888](https://juejin.im/post/6844903919064186888)
## LiveData
`LiveData`是一种可观察的数据存储器类。与常规的可观察类不同,`LiveData` 具有生命周期感知能力,意指它遵循其他应用组件(如 `Activity``Fragment``Service`)的生命周期。这种感知能力可确保 `LiveData` 仅更新处于活跃生命周期状态的应用组件观察者
LiveData 分为可变值的`MutableLiveData`和不可变值的`LiveData`
**常用方法:**
```
fun test() {
val liveData = MutableLiveData<String>()
// 设置更新数据源
liveData.value = "LiveData"
// 将任务发布到主线程以设置给定值
liveData.postValue("LiveData")
// 获取值
val value = liveData.value
// 观察数据源更改(第一个参数应是owner:LifecycleOwner 比如实现了LifecycleOwner接口的Activity)
liveData.observe(this, {
// 数据源更改后触发的逻辑
})
}
```
**资料:**
官方文档: [https://developer.android.com/topic/libraries/architecture/livedata](https://developer.android.com/topic/libraries/architecture/livedata)
## Lifecycle
`Lifecycle` 是一个类,用于存储有关组件(如 `Activity``Fragment`)的生命周期状态的信息,并允许其他对象观察此状态。
`LifecycleOwner` 是单一方法接口,表示类具有 `Lifecycle`。它具有一种方法(即 `getLifecycle()`),该方法必须由类实现。
实现 `LifecycleObserver` 的组件可与实现 `LifecycleOwner` 的组件无缝协同工作,因为所有者可以提供生命周期,而观察者可以注册以观察生命周期。
**资料:**
官方文档: [https://developer.android.com/topic/libraries/architecture/lifecycle](https://developer.android.com/topic/libraries/architecture/lifecycle)
## ViewBinding
通过视图绑定功能,您可以更轻松地编写可与视图交互的代码。在模块中启用视图绑定之后,系统会为该模块中的每个 XML 布局文件生成一个绑定类。绑定类的实例包含对在相应布局中具有 ID 的所有视图的直接引用。
在大多数情况下,视图绑定会替代 `findViewById`
**使用方式:**
按模块启用`ViewBinding`
```
// 模块下的build.gradle文件
android {
// 开启ViewBinding
// 高版本AS
buildFeatures {
viewBinding = true
}
// 低版本AS 最低3.6
viewBinding {
enabled = true
}
}
```
`Activity``ViewBinding` 的使用
```
// 之前设置视图的方法
setContentView(R.layout.activity_main)
// 使用ViewBinding后的方法
val mBinding = ActivityMainBinding.inflate(layoutInflater)
setContentView(mBinding.root)
// ActivityMainBinding类是根据布局自动生成的 如果没有请先build一下项目
// ViewBinding会将控件id转换为小驼峰命名法,所以为了保持一致规范,在xml里声明id时也请使用小驼峰命名法
// 比如你有一个id为mText的控件,可以这样使用
mBinding.mText.text = "ViewBinding"
```
`Fragment``ViewBinding` 的使用
```
// 原来的写法
return inflater.inflate(R.layout.fragment_blank, container, false)
// 使用ViewBinding的写法
mBinding = FragmentBlankBinding.inflate(inflater)
return mBinding.root
```
**资料:**
官方文档: [https://developer.android.com/topic/libraries/view-binding](https://developer.android.com/topic/libraries/view-binding)
CSDN: [https://blog.csdn.net/u010976213/article/details/104501830?depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromBaidu-5&utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromBaidu-5](https://blog.csdn.net/u010976213/article/details/104501830?depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromBaidu-5&utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromBaidu-5)
## ARoute
`ARoute`是阿里巴巴的一个用于帮助 Android App 进行组件化改造的框架 —— 支持模块间的路由、通信、解耦
**使用方式:**
```
// 1.在需要进行路由跳转的Activity或Fragment上添加 @Route 注解
@Route(path = "/test/activity")
public class YourActivity extend Activity {
...
}
// 2.发起路由跳转
ARouter.getInstance()
.build("目标路由地址")
.navigation()
// 3.携带参数跳转
ARouter.getInstance()
.build("目标路由地址")
.withLong("key1", 666L)
.withString("key3", "888")
.withObject("key4", new Test("Jack", "Rose"))
.navigation()
// 4.接收参数
@Route(path = RouteUrl.MainActivity2)
class MainActivity : AppCompatActivity() {
// 通过name来映射URL中的不同参数
@Autowired(name = "key")
lateinit var name: String
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(mBinding.root)
// ARouter 依赖注入 ARouter会自动对字段进行赋值无需主动获取
ARouter.getInstance().inject(this)
}
}
// 5.获取Fragment
Fragment fragment = (Fragment) ARouter.getInstance().build("/test/fragment").navigation();
```
**资料:**
官方文档:[https://github.com/alibaba/ARouter](https://github.com/alibaba/ARouter)
## 屏幕适配 AndroidAutoSize
屏幕适配使用的是 JessYan 大佬的 今日头条屏幕适配方案终极版
GitHub: [https://github.com/JessYanCoding/AndroidAutoSize](https://github.com/JessYanCoding/AndroidAutoSize)
**使用方式:**
```
// 在清单文件中声明
<manifest>
<application>
// 主单位使用dp 没设置副单位
<meta-data
android:name="design_width_in_dp"
android:value="360"/>
<meta-data
android:name="design_height_in_dp"
android:value="640"/>
</application>
</manifest>
// 默认是以竖屏的宽度为基准进行适配
// 如果是横屏项目要适配Pad(Pad适配尽量使用两套布局 因为手机和Pad屏幕宽比差距很大 无法完美适配)
<manifest>
<application>
// 以高度为基准进行适配 (还需要手动代码设置以高度为基准进行适配) 目前以高度适配比宽度为基准适配 效果要好
<meta-data
android:name="design_height_in_dp"
android:value="400"/>
</application>
</manifest>
// 在Application 中设置
// 屏幕适配 AndroidAutoSize 以横屏高度为基准进行适配
AutoSizeConfig.getInstance().isBaseOnWidth = false
```
## EventBus APT
事件总线这里选择的还是`EventBus`,也有很多比较新的事件总线框架,还是选择了这个直接上手的
在框架内我对`EventBus`进行了基类封装,自动注册和解除注册,在需要注册的类上添加`@EventBusRegister`注解即可,无需关心内存泄漏及没及时解除注册的情况,基类里已经做了处理
```
@EventBusRegister
class MainActivity : AppCompatActivity() {
}
```
很多使用`EventBus`的其实都没有发现APT的功能,这是`EventBus3.0`的重大更新,使用`EventBus APT`可以编译期生成订阅类,这样就可以避免使用低效率的反射,很多人不知道这个更新,用着3.0的版本,实际上却是2.0的效率
项目中已经在各模块中开启了`EventBus APT`,`EventBus`会在编译器对各模块生成订阅类,需要我们手动代码去集成这些订阅类
```
// 因为App包依赖了所有的模块所以选择在App包下的Application中进行设置
// 开启EventBus APT
EventBus
.builder()
.addIndex("各模块生成的订阅类的实例 类名在 moduleBase.gradle 脚本中进行了设置 比如 Lib_Main 生成的订阅类就是 MainEventIndex")
.installDefaultEventBus()
```
## PermissionX
`PermissionX` 是郭霖的一个权限申请框架
**使用方式:**
```
PermissionX.init(this)
.permissions("需要申请的权限")
.request { allGranted, grantedList, deniedList -> }
```
**资料:**
GitHub: [https://github.com/guolindev/PermissionX](https://github.com/guolindev/PermissionX)
## 组件化资源命名冲突
组件化方案中有一个坑就是资源命名冲突的问题,小则导致合并清单文件时资源丢失,大则直接导致崩溃
为了解决这个问题,需要在`build.gradle`文件中,对各模块声明资源前缀规则
```
android {
// 前缀最好以组件包名规定
resourcePrefix "main_"
}
```
## Kotlin 协程
`Kotlin Coroutines` 是一套解决异步编程的方案,在 Android 平台就是一个线程框架,用了都说好
**使用示例:**
* `Activity`
```
// 在 Activity 中 可以使用 lifecycleScope 协程作用域 进行开启协程
// lifecycleScope 是 LifecycleOwner 的扩展属性 使用 lifecycleScope 你就无需关心Activity声明周期的问题 无需关心因为生命周期导致的协程泄漏的问题 可以说是真方便
// 使用示例
lifecycleScope.launch(Dispatchers.Default) {
delay(1000L)
ARouter.getInstance()
.build(RouteUrl.MainActivity)
.navigation()
delay(100L)
finish()
}
// launch() 函数开启了一个协程 调度器默认是Main 这里我指定了 Dispatchers.Default
// 使用默认调度器可以直接使用 launch{}
// Activity 中还有一个协程作用域可以使用 就是 MainScope() 它会返回一个协程作用域实例 使用这个就需要我们手动去处理声明周期的问题了
```
* `ViewModel` 中使用
```
// 在 ViewModel 中可以使用
viewModelScope.launch {}
// 默认的调度器也是Main 同样也不需要我们去做生命周期的处理
```
* `Flow`
`Flow`类似于`RxJava`,它也有一系列的操作符
**资料:**
Google 推荐在 MVVM 架构中使用 Kotlin Flow: [https://juejin.im/post/6854573211930066951](https://juejin.im/post/6854573211930066951)
即学即用Kotlin - 协程: [https://juejin.im/post/6854573211418361864](https://juejin.im/post/6854573211418361864)
Kotlin Coroutines Flow 系列(1-5): [https://juejin.im/post/6844904057530908679](https://juejin.im/post/6844904057530908679)
## 结语
* 本人是一个刚大学毕业的 Android 开发者,技术相对来说比较薄弱,写这个框架主要是为了在以后自己使用、对自己技术做一个总结、对其他想学习的同学提供一个例子、也是想把一些东西开源出去,让这个社区更加的美好。文档中可能有些描述不太专业和生硬,我也很少写这些东西,所以表达起来很生疏。
* 如果你绝对该项目对你有用,那就请给一个 star🌟吧🥰