Modify: 删除无用文件,现在是一个无项目相关性的可修改直接复用的MVVM架构框架

This commit is contained in:
Quyunshuo
2020-08-29 21:09:38 +08:00
parent 9e8a0010e6
commit afd6c5e0b2
30 changed files with 9 additions and 470 deletions

View File

@ -40,11 +40,8 @@ open class BaseApplication : Application() {
}
ARouter.init(this)
// // 屏幕适配 AndroidAutoSize 以横屏高度为基准进行适配
// AutoSizeConfig.getInstance().isBaseOnWidth = false
// Bugly 初始化 第三个参数为SDK调试模式开关
CrashReport.initCrashReport(this, "c5a9b1304f", BuildConfig.DEBUG)
CrashReport.initCrashReport(this, "申请的id", BuildConfig.DEBUG)
}
override fun attachBaseContext(base: Context?) {

View File

@ -1,3 +0,0 @@
package com.quyunshuo.common.bean
data class TestBean(val msgTest: String)

View File

@ -6,6 +6,4 @@ package com.quyunshuo.common.constant
* @Class: NetUrl
* @Remark: 请求公共地址 统一放在此类
*/
object NetUrl {
const val url1 = "https://api.com/"
}
object NetUrl

View File

@ -6,6 +6,4 @@ package com.quyunshuo.common.constant
* @Class: RouteKey
* @Remark: 路由使用中 用到的Key 统一写在此类中
*/
object RouteKey {
const val KEY_NAME = "key_name"
}
object RouteKey

View File

@ -6,11 +6,4 @@ package com.quyunshuo.common.constant
* @Class: RoutePath
* @Remark: 路由地址
*/
object RouteUrl {
// MainActivity
const val MainActivity: String = "/lib_splash/SplashActivity"
// MainActivity2
const val MainActivity2: String = "/lib_splash/SplashActivity2"
}
object RouteUrl

View File

@ -6,6 +6,4 @@ package com.quyunshuo.common.constant
* @Class: SpKey
* @Remark: 本地存储的键 放在此类中
*/
object SpKey {
const val IS_FIRST_START = "is_first_start"
}
object SpKey

View File

@ -1,7 +1,6 @@
package com.quyunshuo.common.net
import com.quyunshuo.common.net.api.ApiCommonService
import com.quyunshuo.common.net.api.ApiHomeService
/**
* @Author: QuYunShuo
@ -11,11 +10,6 @@ import com.quyunshuo.common.net.api.ApiHomeService
*/
object NetRequest {
// Home Service
val homeService by lazy(mode = LazyThreadSafetyMode.NONE) {
NetServiceCreator.create(ApiHomeService::class.java)
}
// 公共接口
val commonService by lazy(mode = LazyThreadSafetyMode.NONE) {
NetServiceCreator.create(ApiCommonService::class.java)

View File

@ -2,7 +2,6 @@ package com.quyunshuo.common.net
import com.quyunshuo.base.BaseApplication
import com.quyunshuo.base.BuildConfig
import com.quyunshuo.common.constant.NetUrl
import com.readystatesoftware.chuck.ChuckInterceptor
import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
@ -18,7 +17,7 @@ import java.util.concurrent.TimeUnit
*/
object NetServiceCreator {
private const val BASE_URL = NetUrl.url1
private const val BASE_URL = ""
private const val CONNECT_TIME_OUT = 15L

View File

@ -1,19 +0,0 @@
package com.quyunshuo.common.net.api
import com.quyunshuo.common.bean.TestBean
import retrofit2.http.GET
import retrofit2.http.Query
/**
* @Author: QuYunShuo
* @Time: 2020/8/29
* @Class: ApiService
* @Remark: Home接口
*/
interface ApiHomeService {
// Retrofit 2.6版本开始支持协程 只需要将抽象方法写成挂起函数即可
@GET()
suspend fun getTestData(@Query("test") test: String): TestBean
}

1
Lib_Main/.gitignore vendored
View File

@ -1 +0,0 @@
/build

View File

@ -1,5 +0,0 @@
apply from: '../moduleBase.gradle'
android {
resourcePrefix "main_"
}

View File

@ -1,21 +0,0 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile

View File

@ -1,24 +0,0 @@
package com.quyunshuo.main
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.ext.junit.runners.AndroidJUnit4
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.Assert.*
/**
* Instrumented test, which will execute on an Android device.
*
* See [testing documentation](http://d.android.com/tools/testing).
*/
@RunWith(AndroidJUnit4::class)
class ExampleInstrumentedTest {
@Test
fun useAppContext() {
// Context of the app under test.
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
assertEquals("com.quyunshuo.main.test", appContext.packageName)
}
}

View File

@ -1,16 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.quyunshuo.main">
<application>
<activity android:name=".MainActivity2" />
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>

View File

@ -1,66 +0,0 @@
package com.quyunshuo.main
import android.Manifest
import android.os.Handler
import android.widget.Toast
import com.alibaba.android.arouter.facade.annotation.Route
import com.alibaba.android.arouter.launcher.ARouter
import com.permissionx.guolindev.PermissionX
import com.quyunshuo.base.ktx.toast
import com.quyunshuo.base.utils.EventBusRegister
import com.quyunshuo.base.utils.sendEvent
import com.quyunshuo.common.bean.TestBean
import com.quyunshuo.common.constant.RouteKey
import com.quyunshuo.common.constant.RouteUrl
import com.quyunshuo.common.ui.BaseActivity
import com.quyunshuo.main.databinding.MainActivityMainBinding
import org.greenrobot.eventbus.Subscribe
/**
* @Author: QuYunShuo
* @Time: 2020/8/27
* @Class: MainActivity
* @Remark: 主界面Activity
*/
@EventBusRegister
@Route(path = RouteUrl.MainActivity)
class MainActivity :
BaseActivity<MainActivityMainBinding, MainViewModel>(MainViewModel::class.java) {
lateinit var handle: Handler
override fun initViewBinding(): MainActivityMainBinding =
MainActivityMainBinding.inflate(layoutInflater)
override fun initView() {
PermissionX.init(this)
.permissions(Manifest.permission.READ_PHONE_STATE)
.request { allGranted, grantedList, deniedList ->
if (allGranted) {
toast("权限全部授予")
} else {
toast("您拒绝了权限")
}
}
mViewModel.msg.observe(this, {
mBinding.mTv.text = it
Toast.makeText(this, it, Toast.LENGTH_SHORT).show()
})
mBinding.mBtn.setOnClickListener { mViewModel.getString() }
mBinding.mIntentBtn.setOnClickListener {
ARouter.getInstance().build(RouteUrl.MainActivity2)
.withString(RouteKey.KEY_NAME, "ARouter").navigation()
}
mBinding.mDebacle.setOnClickListener {
handle.post {
toast("")
}
}
sendEvent(TestBean("EventBus"))
}
@Subscribe
fun onEvent(event: TestBean) {
toast(event.msgTest)
}
}

View File

@ -1,25 +0,0 @@
package com.quyunshuo.main
import com.alibaba.android.arouter.facade.annotation.Autowired
import com.alibaba.android.arouter.facade.annotation.Route
import com.quyunshuo.base.ktx.toast
import com.quyunshuo.common.constant.RouteKey
import com.quyunshuo.common.constant.RouteUrl
import com.quyunshuo.common.ui.BaseActivity
import com.quyunshuo.main.databinding.MainActivityMain2Binding
@Route(path = RouteUrl.MainActivity2)
class MainActivity2 :
BaseActivity<MainActivityMain2Binding, MainViewModel>(MainViewModel::class.java) {
// 通过name来映射URL中的不同参数
@Autowired(name = RouteKey.KEY_NAME)
lateinit var name: String
override fun initViewBinding(): MainActivityMain2Binding =
MainActivityMain2Binding.inflate(layoutInflater)
override fun initView() {
toast(name)
}
}

View File

@ -1,52 +0,0 @@
package com.quyunshuo.main
import com.quyunshuo.base.mvvm.m.BaseRepository
import com.quyunshuo.common.net.NetRequest
/**
* @Author: QuYunShuo
* @Time: 2020/8/28
* @Class: MainRepository
* @Remark:
*/
class MainRepository : BaseRepository() {
/**
* 模拟请求或读取数据库
*/
suspend fun getString() =
flowRequest<String> {
emit("嘿嘿")
}
/**
* 模拟使用网络请求接口
* 需要写成挂起函数
*/
suspend fun mockRequest() =
flowRequest<String> {
// 发起请求
// 并行请求可以使用 async await
// 例如
// // 创建一个新的协程进行请求
// val deferredRealtime = async {
// SendRequest.getRealtimeWeather(lng, lat)
// }
// // 创建一个新的协程进行请求
// val deferredDaily = async {
// SendRequest.getDailyWeather(lng, lat)
// }
// // 对两个请求获取结果
// val realtimeResponse = deferredRealtime.await()
// val dailyResponse = deferredDaily.await()
// 这两个协程是并行的 不是串行
val testData = NetRequest.homeService.getTestData("mock")
// 处理请求结果
// {if testData ... }
// 将请求结果或者是调用者需要的数据进行发射出去
emit(testData.msgTest)
}
}

View File

@ -1,55 +0,0 @@
package com.quyunshuo.main
import android.util.Log
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.viewModelScope
import com.quyunshuo.base.mvvm.vm.BaseViewModel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.onCompletion
import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.launch
/**
* @Author: QuYunShuo
* @Time: 2020/8/28
* @Class: MainViewModel
* @Remark:
*/
class MainViewModel : BaseViewModel<MainRepository>() {
val msg: MutableLiveData<String> = MutableLiveData<String>()
override fun initRepository(): MainRepository = MainRepository()
fun getString() {
viewModelScope.launch(Dispatchers.IO) {
mRepository.getString().collectLatest {
msg.postValue(it)
}
}
}
fun getTestString() {
viewModelScope.launch {
mRepository.getString()
.onStart {
// 获取数据之前
// 可以做loading图之类的
}
.catch {
// 处理异常 获取数据产生的异常
}
.onCompletion {
// 获取数据完成时
}
.collectLatest {
// 拿到想要的数据
Log.d("qqq", "getTestString: $it")
}
// onStart() catch() onCompletion() 都是可选的 是flow的操作符
// 例如 mRepository.getString().collectLatest { // 拿到想要的结果 }
}
}
}

View File

@ -1,19 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.quyunshuo.main">
<application
android:name="debug.MainApplication"
android:allowBackup="true"
android:label="@string/main_app_name"
android:theme="@style/base_AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>

View File

@ -1,11 +0,0 @@
package debug
import com.quyunshuo.common.CommonApplication
/**
* @Author: QuYunShuo
* @Time: 2020/8/28
* @Class: MainApplication
* @Remark: 作为app模式时的Application
*/
class MainApplication : CommonApplication()

View File

@ -1,86 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:id="@+id/mTv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Main"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/mBtn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="获取值"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/mTv" />
<Button
android:id="@+id/mIntentBtn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="跳转"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/mBtn" />
<Button
android:id="@+id/mDebacle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="崩溃"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/mIntentBtn" />
<FrameLayout
android:layout_width="200dp"
android:layout_height="200dp"
android:background="#333"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<FrameLayout
android:layout_width="300dp"
android:layout_height="100dp"
android:background="#03A9F4"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<FrameLayout
android:layout_width="300dp"
android:layout_height="100dp"
android:background="#9BE446"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<FrameLayout
android:layout_width="200dp"
android:layout_height="300dp"
android:background="#FFEB3B"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<FrameLayout
android:layout_width="200dp"
android:layout_height="300dp"
android:background="#E317CE"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -1,9 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity2">
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -1,3 +0,0 @@
<resources>
<string name="main_app_name">Lib_Main</string>
</resources>

View File

@ -1,17 +0,0 @@
package com.quyunshuo.main
import org.junit.Test
import org.junit.Assert.*
/**
* Example local unit test, which will execute on the development machine (host).
*
* See [testing documentation](http://d.android.com/tools/testing).
*/
class ExampleUnitTest {
@Test
fun addition_isCorrect() {
assertEquals(4, 2 + 2)
}
}

View File

@ -1,7 +1,5 @@
# Android项目框架(组件化 + Kotlin + MVVM + Jetpack )
note: 1. 对比开源项目flow的封装
资源文件相关{
资源相关文件属于项目相关的因此需要放在Common组件内不要放在Base组件里
String、Color、Style、layout、drawable、mipmap 公用的 放在Common组件内不公用的放在各自组件内命名以各组件的规则命名(build文件设置了规则)

View File

@ -70,7 +70,8 @@ android {
dependencies {
implementation fileTree(dir: "libs", include: ["*.jar"])
if (!BuildConfig.isAppMode) {
implementation project(path: ':Lib_Main')
// 有业务组件时 把这个去掉 这里只是为了使用base里的依赖库
implementation project(path: ':Lib_Common')
} else {
implementation project(path: ':Lib_Common')
}

View File

@ -28,9 +28,6 @@
<meta-data
android:name="design_height_in_dp"
android:value="640" />
<!-- <meta-data-->
<!-- android:name="design_height_in_dp"-->
<!-- android:value="400" />-->
</application>
</manifest>

View File

@ -1,6 +1,5 @@
package com.quyunshuo.androidbaseframemvvm
import com.quyunshuo.androidbaseframemvvm.eventbus.index.MainEventIndex
import com.quyunshuo.common.CommonApplication
import org.greenrobot.eventbus.EventBus
@ -16,7 +15,7 @@ class AppApplication : CommonApplication() {
// 开启EventBusAPT,优化反射效率
EventBus
.builder()
.addIndex(MainEventIndex())
// .addIndex()
.installDefaultEventBus()
super.initialize()
}

View File

@ -1,5 +1,4 @@
include ':Lib_Common'
include ':Lib_Main'
include ':Lib_Base'
include ':app'
rootProject.name = "AndroidBaseFrameMVVM"