Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 91b934b

Browse filesBrowse files
author
Quyunshuo
committed
Modify: 添加示例代码及注意事项
1 parent 55f5d6a commit 91b934b
Copy full SHA for 91b934b

File tree

1 file changed

+243
-1
lines changed
Filter options

1 file changed

+243
-1
lines changed

‎README.md

Copy file name to clipboardExpand all lines: README.md
+243-1Lines changed: 243 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,249 @@ android {
6767
**MVVM相关**
6868
* MVVM 采用 Jetpack 组件 + Repository 设计模式 实现,所使用的 Jetpack 并不是很多,像 DataBinding、Hilt(不支持多模块)、Room 等并没有使用,如果需要可以添加。采用架构模式目的就是为了解偶代码,对代码进行分层,各模块各司其职,所以既然使用了架构模式那就要遵守好规范
6969
* 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)
71313

72314
## 结语
73315
* 本人是一个刚大学毕业的 Android 开发者,技术相对来说比较薄弱,写这个框架主要是为了在以后自己使用、对自己技术做一个总结、对其他想学习的同学提供一个例子、也是想把一些东西开源出去,让这个社区更加的美好。文档中可能有些描述不太专业和生硬,我也很少写这些东西,所以表达起来很生疏。

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.