@@ -67,7 +67,249 @@ android {
67
67
** MVVM相关**
68
68
* MVVM 采用 Jetpack 组件 + Repository 设计模式 实现,所使用的 Jetpack 并不是很多,像 DataBinding、Hilt(不支持多模块)、Room 等并没有使用,如果需要可以添加。采用架构模式目的就是为了解偶代码,对代码进行分层,各模块各司其职,所以既然使用了架构模式那就要遵守好规范
69
69
* Repository 仓库层负责数据的提供,ViewModel 无需关心数据的来源,Repository 内避免使用 LiveData,框架里使用了 Kotlin 协程的 Flow 进行处理请求或访问数据库,最后将数据发射到 ViewModel 调用者,Flow上游负责提供数据,下游也就是ViewModel获取到数据使用LiveData进行存储,View层订阅LiveData,实现数据驱动视图
70
- * 三者的依赖都是单向依赖,View -> ViewModel -> Repository
70
+ * 三者的依赖都是单向依赖,View -> ViewModel -> Repository
71
+
72
+ # <p align =" center " > 示例代码及注意事项🐽</p >
73
+
74
+ ## ViewModel
75
+ ` ViewModel ` 类旨在以注重生命周期的方式存储和管理界面相关的数据。` ViewModel ` 类让数据可在发生屏幕旋转等配置更改后继续留存。
76
+ ** 使用方式:**
77
+ ```
78
+ class MainViewModel : ViewModel(){
79
+ }
80
+
81
+ class MainActivity : AppCompatActivity() {
82
+ // 获取无参构造的ViewModel实例
83
+ val mViewModel = ViewModelProvider(this).get(MainViewModel::class.java)
84
+ }
85
+ ```
86
+ ** 资料:**
87
+ 官方文档: [ https://developer.android.com/topic/libraries/architecture/viewmodel ] ( https://developer.android.com/topic/libraries/architecture/viewmodel )
88
+ Android ViewModel,再学不会你砍我: [ https://juejin.im/post/6844903919064186888 ] ( https://juejin.im/post/6844903919064186888 )
89
+ ## LiveData
90
+ ` LiveData ` 是一种可观察的数据存储器类。与常规的可观察类不同,` LiveData ` 具有生命周期感知能力,意指它遵循其他应用组件(如 ` Activity ` 、` Fragment ` 或 ` Service ` )的生命周期。这种感知能力可确保 ` LiveData ` 仅更新处于活跃生命周期状态的应用组件观察者
91
+ LiveData 分为可变值的` MutableLiveData ` 和不可变值的` LiveData `
92
+ ** 常用方法:**
93
+ ```
94
+ fun test() {
95
+ val liveData = MutableLiveData<String>()
96
+ // 设置更新数据源
97
+ liveData.value = "LiveData"
98
+ // 将任务发布到主线程以设置给定值
99
+ liveData.postValue("LiveData")
100
+ // 获取值
101
+ val value = liveData.value
102
+ // 观察数据源更改(第一个参数应是owner:LifecycleOwner 比如实现了LifecycleOwner接口的Activity)
103
+ liveData.observe(this, {
104
+ // 数据源更改后触发的逻辑
105
+ })
106
+ }
107
+ ```
108
+ ** 资料:**
109
+ 官方文档: [ https://developer.android.com/topic/libraries/architecture/livedata ] ( https://developer.android.com/topic/libraries/architecture/livedata )
110
+
111
+ ## Lifecycle
112
+ ` Lifecycle ` 是一个类,用于存储有关组件(如 ` Activity ` 或 ` Fragment ` )的生命周期状态的信息,并允许其他对象观察此状态。
113
+ ` LifecycleOwner ` 是单一方法接口,表示类具有 ` Lifecycle ` 。它具有一种方法(即 ` getLifecycle() ` ),该方法必须由类实现。
114
+ 实现 ` LifecycleObserver ` 的组件可与实现 ` LifecycleOwner ` 的组件无缝协同工作,因为所有者可以提供生命周期,而观察者可以注册以观察生命周期。
115
+
116
+ ** 资料:**
117
+ 官方文档: [ https://developer.android.com/topic/libraries/architecture/lifecycle ] ( https://developer.android.com/topic/libraries/architecture/lifecycle )
118
+
119
+ ## ViewBinding
120
+ 通过视图绑定功能,您可以更轻松地编写可与视图交互的代码。在模块中启用视图绑定之后,系统会为该模块中的每个 XML 布局文件生成一个绑定类。绑定类的实例包含对在相应布局中具有 ID 的所有视图的直接引用。
121
+ 在大多数情况下,视图绑定会替代 ` findViewById `
122
+ ** 使用方式:**
123
+ 按模块启用` ViewBinding `
124
+ ```
125
+ // 模块下的build.gradle文件
126
+ android {
127
+ // 开启ViewBinding
128
+ // 高版本AS
129
+ buildFeatures {
130
+ viewBinding = true
131
+ }
132
+ // 低版本AS 最低3.6
133
+ viewBinding {
134
+ enabled = true
135
+ }
136
+ }
137
+ ```
138
+ ` Activity ` 中 ` ViewBinding ` 的使用
139
+ ```
140
+ // 之前设置视图的方法
141
+ setContentView(R.layout.activity_main)
142
+
143
+ // 使用ViewBinding后的方法
144
+ val mBinding = ActivityMainBinding.inflate(layoutInflater)
145
+ setContentView(mBinding.root)
146
+
147
+ // ActivityMainBinding类是根据布局自动生成的 如果没有请先build一下项目
148
+ // ViewBinding会将控件id转换为小驼峰命名法,所以为了保持一致规范,在xml里声明id时也请使用小驼峰命名法
149
+ // 比如你有一个id为mText的控件,可以这样使用
150
+ mBinding.mText.text = "ViewBinding"
151
+ ```
152
+ ` Fragment ` 中 ` ViewBinding ` 的使用
153
+ ```
154
+ // 原来的写法
155
+ return inflater.inflate(R.layout.fragment_blank, container, false)
156
+
157
+ // 使用ViewBinding的写法
158
+ mBinding = FragmentBlankBinding.inflate(inflater)
159
+ return mBinding.root
160
+ ```
161
+ ** 资料:**
162
+ 官方文档: [ https://developer.android.com/topic/libraries/view-binding ] ( https://developer.android.com/topic/libraries/view-binding )
163
+ 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 )
164
+
165
+ ## ARoute
166
+ ` ARoute ` 是阿里巴巴的一个用于帮助 Android App 进行组件化改造的框架 —— 支持模块间的路由、通信、解耦
167
+ ** 使用方式:**
168
+ ```
169
+ // 1.在需要进行路由跳转的Activity或Fragment上添加 @Route 注解
170
+ @Route(path = "/test/activity")
171
+ public class YourActivity extend Activity {
172
+ ...
173
+ }
174
+
175
+ // 2.发起路由跳转
176
+ ARouter.getInstance()
177
+ .build("目标路由地址")
178
+ .navigation()
179
+
180
+ // 3.携带参数跳转
181
+ ARouter.getInstance()
182
+ .build("目标路由地址")
183
+ .withLong("key1", 666L)
184
+ .withString("key3", "888")
185
+ .withObject("key4", new Test("Jack", "Rose"))
186
+ .navigation()
187
+
188
+ // 4.接收参数
189
+ @Route(path = RouteUrl.MainActivity2)
190
+ class MainActivity : AppCompatActivity() {
191
+
192
+ // 通过name来映射URL中的不同参数
193
+ @Autowired(name = "key")
194
+ lateinit var name: String
195
+
196
+ override fun onCreate(savedInstanceState: Bundle?) {
197
+ super.onCreate(savedInstanceState)
198
+ setContentView(mBinding.root)
199
+ // ARouter 依赖注入 ARouter会自动对字段进行赋值,无需主动获取
200
+ ARouter.getInstance().inject(this)
201
+ }
202
+ }
203
+
204
+ // 5.获取Fragment
205
+ Fragment fragment = (Fragment) ARouter.getInstance().build("/test/fragment").navigation();
206
+ ```
207
+ ** 资料:**
208
+ 官方文档:[ https://github.com/alibaba/ARouter ] ( https://github.com/alibaba/ARouter )
209
+
210
+ ## 屏幕适配 AndroidAutoSize
211
+ 屏幕适配使用的是 JessYan 大佬的 今日头条屏幕适配方案终极版
212
+ GitHub: [ https://github.com/JessYanCoding/AndroidAutoSize ] ( https://github.com/JessYanCoding/AndroidAutoSize )
213
+ ** 使用方式:**
214
+ ```
215
+ // 在清单文件中声明
216
+ <manifest>
217
+ <application>
218
+ // 主单位使用dp 没设置副单位
219
+ <meta-data
220
+ android:name="design_width_in_dp"
221
+ android:value="360"/>
222
+ <meta-data
223
+ android:name="design_height_in_dp"
224
+ android:value="640"/>
225
+ </application>
226
+ </manifest>
227
+
228
+ // 默认是以竖屏的宽度为基准进行适配
229
+ // 如果是横屏项目要适配Pad(Pad适配尽量使用两套布局 因为手机和Pad屏幕宽比差距很大 无法完美适配)
230
+ <manifest>
231
+ <application>
232
+ // 以高度为基准进行适配 (还需要手动代码设置以高度为基准进行适配) 目前以高度适配比宽度为基准适配 效果要好
233
+ <meta-data
234
+ android:name="design_height_in_dp"
235
+ android:value="400"/>
236
+ </application>
237
+ </manifest>
238
+
239
+ // 在Application 中设置
240
+ // 屏幕适配 AndroidAutoSize 以横屏高度为基准进行适配
241
+ AutoSizeConfig.getInstance().isBaseOnWidth = false
242
+ ```
243
+ ## EventBus APT
244
+ 事件总线这里选择的还是` EventBus ` ,也有很多比较新的事件总线框架,还是选择了这个直接上手的
245
+ 在框架内我对` EventBus ` 进行了基类封装,自动注册和解除注册,在需要注册的类上添加` @EventBusRegister ` 注解即可,无需关心内存泄漏及没及时解除注册的情况,基类里已经做了处理
246
+ ```
247
+ @EventBusRegister
248
+ class MainActivity : AppCompatActivity() {
249
+ }
250
+ ```
251
+ 很多使用` EventBus ` 的其实都没有发现APT的功能,这是` EventBus3.0 ` 的重大更新,使用` EventBus APT ` 可以编译期生成订阅类,这样就可以避免使用低效率的反射,很多人不知道这个更新,用着3.0的版本,实际上却是2.0的效率
252
+ 项目中已经在各模块中开启了` EventBus APT ` ,` EventBus ` 会在编译器对各模块生成订阅类,需要我们手动代码去集成这些订阅类
253
+ ```
254
+ // 因为App包依赖了所有的模块所以选择在App包下的Application中进行设置
255
+ // 开启EventBus APT
256
+ EventBus
257
+ .builder()
258
+ .addIndex("各模块生成的订阅类的实例 类名在 moduleBase.gradle 脚本中进行了设置 比如 Lib_Main 生成的订阅类就是 MainEventIndex")
259
+ .installDefaultEventBus()
260
+ ```
261
+
262
+ ## PermissionX
263
+ ` PermissionX ` 是郭霖的一个权限申请框架
264
+ ** 使用方式:**
265
+ ```
266
+ PermissionX.init(this)
267
+ .permissions("需要申请的权限")
268
+ .request { allGranted, grantedList, deniedList -> }
269
+ ```
270
+ ** 资料:**
271
+ GitHub: [ https://github.com/guolindev/PermissionX ] ( https://github.com/guolindev/PermissionX )
272
+ ## 组件化资源命名冲突
273
+ 组件化方案中有一个坑就是资源命名冲突的问题,小则导致合并清单文件时资源丢失,大则直接导致崩溃
274
+ 为了解决这个问题,需要在` build.gradle ` 文件中,对各模块声明资源前缀规则
275
+ ```
276
+ android {
277
+ // 前缀最好以组件包名规定
278
+ resourcePrefix "main_"
279
+ }
280
+ ```
281
+ ## Kotlin 协程
282
+ ` Kotlin Coroutines ` 是一套解决异步编程的方案,在 Android 平台就是一个线程框架,用了都说好
283
+ ** 使用示例:**
284
+ * ` Activity ` 中
285
+ ```
286
+ // 在 Activity 中 可以使用 lifecycleScope 协程作用域 进行开启协程
287
+ // lifecycleScope 是 LifecycleOwner 的扩展属性 使用 lifecycleScope 你就无需关心Activity声明周期的问题 无需关心因为生命周期导致的协程泄漏的问题 可以说是真方便
288
+ // 使用示例
289
+ lifecycleScope.launch(Dispatchers.Default) {
290
+ delay(1000L)
291
+ ARouter.getInstance()
292
+ .build(RouteUrl.MainActivity)
293
+ .navigation()
294
+ delay(100L)
295
+ finish()
296
+ }
297
+ // launch() 函数开启了一个协程 调度器默认是Main 这里我指定了 Dispatchers.Default
298
+ // 使用默认调度器可以直接使用 launch{}
299
+ // Activity 中还有一个协程作用域可以使用 就是 MainScope() 它会返回一个协程作用域实例 使用这个就需要我们手动去处理声明周期的问题了
300
+ ```
301
+ * ` ViewModel ` 中使用
302
+ ```
303
+ // 在 ViewModel 中可以使用
304
+ viewModelScope.launch {}
305
+ // 默认的调度器也是Main 同样也不需要我们去做生命周期的处理
306
+ ```
307
+ * ` Flow `
308
+ ` Flow ` 类似于` RxJava ` ,它也有一系列的操作符
309
+ ** 资料:**
310
+ Google 推荐在 MVVM 架构中使用 Kotlin Flow: [ https://juejin.im/post/6854573211930066951 ] ( https://juejin.im/post/6854573211930066951 )
311
+ 即学即用Kotlin - 协程: [ https://juejin.im/post/6854573211418361864 ] ( https://juejin.im/post/6854573211418361864 )
312
+ Kotlin Coroutines Flow 系列(1-5): [ https://juejin.im/post/6844904057530908679 ] ( https://juejin.im/post/6844904057530908679 )
71
313
72
314
## 结语
73
315
* 本人是一个刚大学毕业的 Android 开发者,技术相对来说比较薄弱,写这个框架主要是为了在以后自己使用、对自己技术做一个总结、对其他想学习的同学提供一个例子、也是想把一些东西开源出去,让这个社区更加的美好。文档中可能有些描述不太专业和生硬,我也很少写这些东西,所以表达起来很生疏。
0 commit comments