├── .gitignore ├── README.md ├── app ├── .gitignore ├── build.gradle ├── multidexKeep.pro ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── quyunshuo │ │ └── androidbaseframemvvm │ │ └── app │ │ └── AppApplication.kt │ └── res │ ├── drawable-v24 │ └── ic_launcher_foreground.xml │ ├── drawable │ └── ic_launcher_background.xml │ ├── mipmap-anydpi-v26 │ ├── ic_launcher.xml │ └── ic_launcher_round.xml │ ├── mipmap-xxhdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── values │ └── strings.xml │ └── xml │ └── network_security_config.xml ├── base_lib.gradle ├── base_module.gradle ├── build.gradle.kts ├── buildSrc ├── build.gradle.kts ├── gradlew ├── gradlew.bat └── src │ └── main │ └── kotlin │ └── com │ └── quyunshuo │ └── androidbaseframemvvm │ └── buildsrc │ ├── DependencyConfig.kt │ ├── ProjectBuildConfig.kt │ └── SDKKeyConfig.kt ├── gradle.properties ├── gradle ├── libs.versions.toml └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── img └── img2.png ├── lib_base ├── .gitignore ├── build.gradle ├── consumer-rules.pro ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── quyunshuo │ │ └── androidbaseframemvvm │ │ └── base │ │ ├── BaseApplication.kt │ │ ├── app │ │ ├── ActivityLifecycleCallbacksImpl.kt │ │ ├── ApplicationLifecycle.kt │ │ └── LoadModuleProxy.kt │ │ ├── constant │ │ └── VersionStatus.kt │ │ ├── ktx │ │ ├── ActivityKtx.kt │ │ ├── EditTextKtx.kt │ │ ├── LifecycleOwnerKtx.kt │ │ ├── NetUtils.kt │ │ ├── PopupWindowKtx.kt │ │ ├── SizeUnitKtx.kt │ │ ├── VideoViewKtx.kt │ │ ├── ViewKtx.kt │ │ ├── ViewModelKtx.kt │ │ └── ViewPager2Ktx.kt │ │ ├── mvvm │ │ ├── m │ │ │ └── BaseRepository.kt │ │ ├── v │ │ │ ├── BaseFrameActivity.kt │ │ │ ├── BaseFrameFragment.kt │ │ │ └── FrameView.kt │ │ └── vm │ │ │ ├── BaseViewModel.kt │ │ │ └── EmptyViewModel.kt │ │ ├── utils │ │ ├── ActivityStackManager.kt │ │ ├── AndroidBugFixUtils.kt │ │ ├── AppUtils.kt │ │ ├── BarUtils.java │ │ ├── ClipboardUtils.kt │ │ ├── CoilGIFImageLoader.kt │ │ ├── DateUtils.kt │ │ ├── EventBusUtils.kt │ │ ├── ForegroundBackgroundHelper.kt │ │ ├── ProcessUtils.kt │ │ ├── RegisterEventBus.kt │ │ ├── ResourcesFun.kt │ │ ├── SpUtils.kt │ │ ├── SpannableStringUtils.java │ │ ├── StateLayoutEnum.kt │ │ ├── ThreadUtils.kt │ │ ├── ToastUtils.kt │ │ ├── Utils.kt │ │ ├── network │ │ │ ├── AutoRegisterNetListener.kt │ │ │ ├── NetworkCallbackImpl.kt │ │ │ ├── NetworkStateChangeListener.kt │ │ │ ├── NetworkStateClient.kt │ │ │ └── NetworkTypeEnum.kt │ │ └── status │ │ │ ├── ViewStatusHelper.kt │ │ │ └── imp │ │ │ └── BaseFrameViewStatusHelperImp.kt │ │ └── view │ │ └── OnSingleClickListener.kt │ └── res │ └── values │ ├── colors.xml │ ├── strings.xml │ └── styles.xml ├── lib_common ├── .gitignore ├── build.gradle ├── consumer-rules.pro ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── quyunshuo │ │ └── androidbaseframemvvm │ │ └── common │ │ ├── CommonApplication.kt │ │ ├── constant │ │ ├── NetBaseUrlConstant.kt │ │ ├── RouteKey.kt │ │ ├── RouteUrl.kt │ │ └── SpKey.kt │ │ ├── di │ │ └── DINetworkModule.kt │ │ ├── helper │ │ ├── ExceptionHandler.kt │ │ ├── ResponseCodeEnum.kt │ │ └── ResponseException.kt │ │ └── ui │ │ ├── BaseActivity.kt │ │ ├── BaseFragment.kt │ │ └── BaseFragmentStateAdapter.kt │ └── res │ └── values │ └── colors.xml ├── module_home ├── .gitignore ├── build.gradle ├── consumer-rules.pro ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── quyunshuo │ │ └── module │ │ └── home │ │ └── ExampleInstrumentedTest.kt │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── quyunshuo │ │ │ └── module │ │ │ └── home │ │ │ ├── activity │ │ │ ├── HomeRepository.kt │ │ │ ├── HomeViewModel.kt │ │ │ ├── InternalPagerActivity.kt │ │ │ └── MainActivity.kt │ │ │ ├── di │ │ │ └── DIHomeNetServiceModule.kt │ │ │ ├── fragment │ │ │ ├── InternalFragment.kt │ │ │ ├── InternalRepository.kt │ │ │ └── InternalViewModel.kt │ │ │ └── net │ │ │ └── HomeApiService.kt │ └── res │ │ ├── layout │ │ ├── home_activity_internal_layout.xml │ │ ├── home_activity_main.xml │ │ └── home_fragment_internal_layout.xml │ │ └── values │ │ └── strings.xml │ └── test │ └── java │ └── com │ └── quyunshuo │ └── module │ └── home │ └── ExampleUnitTest.kt └── settings.gradle.kts /.gitignore: -------------------------------------------------------------------------------- 1 | # Built application files 2 | *.apk 3 | *.ap_ 4 | 5 | # Files for the ART/Dalvik VM 6 | *.dex 7 | 8 | # Java class files 9 | *.class 10 | 11 | # Generated files 12 | bin/ 13 | gen/ 14 | out/ 15 | 16 | # Gradle files 17 | .gradle/ 18 | build/ 19 | 20 | # Local configuration file (sdk path, etc) 21 | local.properties 22 | 23 | # Proguard folder generated by Eclipse 24 | proguard/ 25 | 26 | # Log Files 27 | *.log 28 | 29 | # Android Studio Navigation editor temp files 30 | .navigation/ 31 | 32 | # Android Studio captures folder 33 | captures/ 34 | 35 | # IntelliJ 36 | *.iml 37 | .idea/workspace.xml 38 | .idea/tasks.xml 39 | .idea/gradle.xml 40 | .idea/assetWizardSettings.xml 41 | .idea/dictionaries 42 | .idea/libraries 43 | .idea/caches 44 | .idea/* 45 | 46 | # Keystore files 47 | # Uncomment the following line if you do not want to check your keystore files in. 48 | #*.jks 49 | 50 | # External native build folder generated in Android Studio 2.2 and later 51 | .externalNativeBuild 52 | 53 | # Google Services (e.g. APIs or Firebase) 54 | google-services.json 55 | 56 | # Freeline 57 | freeline.py 58 | freeline/ 59 | freeline_project_description.json 60 | 61 | # fastlane 62 | fastlane/report.xml 63 | fastlane/Preview.html 64 | fastlane/screenshots 65 | fastlane/test_output 66 | fastlane/readme.md 67 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | #
AndroidBaseFrameMVVM 🐽
2 | 3 | > **AndroidBaseFrameMVVM** 是一个Android工程框架,所使用技术栈为:**组件化、Kotlin、MVVM、Jetpack、Repository、Kotlin-Coroutine-Flow**,本框架既是一个可以开箱即用的工程框架基础层,也是一个很好的学习资源,文档下面会对框架中所使用的一些核心技术进行阐述。该框架作为个人技术积累的产物,会一直更新维护,如果有技术方面的谈论或者框架中的错误点,可以在 **GitHub** 上提 **Issues**,我会及时进行回应。希望这个框架项目能给大家带来帮助,喜欢可以Start🌟。 4 | > 5 | > 项目地址:[AndroidBaseFrameMVVM](https://github.com/Quyunshuo/AndroidBaseFrameMVVM) 6 | 7 | ## Demo 8 | 9 | 以鸿洋大神的玩安卓开放Api做了简单的页面示例,仓库地址:[WanAndroidMVVM](https://github.com/Quyunshuo/WanAndroidMVVM) 10 | 11 | ## 框架图示 12 | 13 | **谷歌 Android 团队 Jetpack 视图模型:** 14 | 15 |
7 | * - 文件描述 : 采用了一种链式调用,所有对象持有自己父级帮助类,进行场景回复时先恢复链头的数据
8 | */
9 | abstract class ViewStatusHelper(val parentViewStatusHelper: ViewStatusHelper?) {
10 |
11 | open fun onRestoreInstanceStatus(savedInstanceState: Bundle?) {
12 | parentViewStatusHelper?.onRestoreInstanceStatus(savedInstanceState)
13 | }
14 |
15 | open fun onSaveInstanceState(bundle: Bundle) {
16 | parentViewStatusHelper?.onSaveInstanceState(bundle)
17 | }
18 | }
--------------------------------------------------------------------------------
/lib_base/src/main/java/com/quyunshuo/androidbaseframemvvm/base/utils/status/imp/BaseFrameViewStatusHelperImp.kt:
--------------------------------------------------------------------------------
1 | package com.quyunshuo.androidbaseframemvvm.base.utils.status.imp
2 |
3 | import android.os.Bundle
4 | import com.quyunshuo.androidbaseframemvvm.base.utils.status.ViewStatusHelper
5 |
6 | /**
7 | * @author DBoy 2021/7/8
8 | *
9 | * - 文件描述 : 视图,activity,fragment重建帮助类
10 | */
11 | open class BaseFrameViewStatusHelperImp(parentViewStatusHelper: ViewStatusHelper? = null) : ViewStatusHelper(parentViewStatusHelper) {
12 | /**
13 | * 重建标记key 以包名保存数据可以防止嵌套层级出现重复Key
14 | */
15 | private val KEY_RECREATE = "com.quyunshuo.androidbaseframemvvm.base.utils.status.BaseFrameViewStatusHelperImp.Recreate"
16 |
17 | /**
18 | * 是否重建
19 | */
20 | var isRecreate = false
21 | private set
22 |
23 |
24 | /**
25 | * 恢复状态
26 | */
27 | override fun onRestoreInstanceStatus(savedInstanceState: Bundle?) {
28 | super.onRestoreInstanceStatus(savedInstanceState)
29 | isRecreate = savedInstanceState?.getBoolean(KEY_RECREATE) ?: false
30 | }
31 |
32 | /**
33 | * 保存状态
34 | */
35 | override fun onSaveInstanceState(bundle: Bundle) {
36 | super.onSaveInstanceState(bundle)
37 | bundle.putBoolean(KEY_RECREATE, true)
38 | }
39 |
40 | }
--------------------------------------------------------------------------------
/lib_base/src/main/java/com/quyunshuo/androidbaseframemvvm/base/view/OnSingleClickListener.kt:
--------------------------------------------------------------------------------
1 | package com.quyunshuo.androidbaseframemvvm.base.view
2 |
3 | import android.view.View
4 |
5 | /**
6 | * 带有防抖效果的单击监听
7 | *
8 | * @param mDelayTime Int 防抖间隔时间,单位是毫秒,默认值 500ms
9 | * @param mListener (v: View) -> Unit 具体的点击事件
10 | *
11 | * @author Qu Yunshuo
12 | * @since 2023/3/15 23:39
13 | */
14 | class OnSingleClickListener(
15 | private val mDelayTime: Int = 500,
16 | private val mListener: (v: View) -> Unit
17 | ) : View.OnClickListener {
18 |
19 | /**
20 | * 上次有效点击的时间
21 | */
22 | private var mLastClickTime = 0L
23 | override fun onClick(v: View) {
24 | val currentTimeMillis = System.currentTimeMillis()
25 | if (currentTimeMillis - mLastClickTime >= mDelayTime) {
26 | mLastClickTime = currentTimeMillis
27 | mListener.invoke(v)
28 | }
29 | }
30 | }
--------------------------------------------------------------------------------
/lib_base/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
12 | * - 文件描述 : ViewPager2 FragmentAdapter封装
13 | * - 对于元数据[mData]的增加删除操作只能通过内部提供的4种方式进行操作:
14 | * - [setNewData]
15 | * - [addNewData]
16 | * - [addData]
17 | * - [removeData]
18 | * - 内部使用[DiffUtil]工具实现更新UI,不需调用[notifyDataSetChanged]等一系列方法。
19 | */
20 | abstract class BaseFragmentStateAdapter
17 | // * - 文件描述 : ViewPager2+fragment 模拟Fragment页面重建。
18 | // */
19 | //@AndroidEntryPoint
20 | //class InternalPagerActivity : BaseActivity
13 | // * - 文件描述 : 测试fragment
14 | // */
15 | //@AndroidEntryPoint
16 | //class InternalFragment : BaseFragment
9 | // * - 文件描述 :
10 | // */
11 | //class InternalRepository @Inject constructor() : BaseRepository() {
12 | //
13 | // suspend fun getData() = request
19 | // * - 文件描述 : ViewModel再ViewPager2的Fragment中会随着Fragment执行[Fragment.onDestory]一同销毁。
20 | // * 所以一些需要长期保存的变量数据,不适合保存再ViewModel,考虑使用[ViewStatusHelper]保存页面上部分数据,
21 | // * 页面恢复的时候再交给ViewModel处理,例如[recreatedCont]
22 | // */
23 | //@HiltViewModel
24 | //class InternalViewModel @Inject constructor() :
25 | // BaseViewModel() {
26 | //
27 | // @Inject
28 | // lateinit var repository: InternalRepository
29 | //
30 | // /**
31 | // * 重建计数
32 | // */
33 | // val recreatedCont = MutableLiveData