Modify: ARouter、MMKV
This commit is contained in:
@ -67,6 +67,7 @@ dependencies {
|
||||
api GitHub.Glide
|
||||
api GitHub.ARoute
|
||||
api GitHub.RecyclerViewAdapter
|
||||
api GitHub.StatusBar
|
||||
|
||||
kapt GitHub.GlideCompiler
|
||||
kapt GitHub.ARouteCompiler
|
||||
|
||||
@ -1,6 +1,8 @@
|
||||
package com.quyunshuo.base
|
||||
|
||||
import android.app.Application
|
||||
import com.alibaba.android.arouter.launcher.ARouter
|
||||
import com.quyunshuo.base.utils.SpUtils
|
||||
|
||||
/**
|
||||
* @Author: QuYunShuo
|
||||
@ -12,5 +14,21 @@ open class BaseApplication : Application() {
|
||||
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
initialize()
|
||||
}
|
||||
|
||||
/**
|
||||
* 进行一些初始化的操作
|
||||
*/
|
||||
protected open fun initialize() {
|
||||
// 腾讯 MMKV 初始化
|
||||
SpUtils.initMMKV(this)
|
||||
|
||||
// 阿里路由 ARouter 初始化
|
||||
if (BuildConfig.DEBUG) {
|
||||
ARouter.openLog() // 打印日志
|
||||
ARouter.openDebug() // 开启调试模式(如果在InstantRun模式下运行,必须开启调试模式!线上版本需要关闭,否则有安全风险)
|
||||
}
|
||||
ARouter.init(this)
|
||||
}
|
||||
}
|
||||
81
Lib_Base/src/main/java/com/quyunshuo/base/ktx/ContextKtx.kt
Normal file
81
Lib_Base/src/main/java/com/quyunshuo/base/ktx/ContextKtx.kt
Normal file
@ -0,0 +1,81 @@
|
||||
package com.quyunshuo.base.ktx
|
||||
|
||||
import android.content.Context
|
||||
import android.view.Gravity
|
||||
import android.widget.Toast
|
||||
import androidx.annotation.StringRes
|
||||
|
||||
/**
|
||||
* @Author: QuYunShuo
|
||||
* @Time: 2020/8/17
|
||||
* @Class: ContextKtx
|
||||
* @Remark: Context相关的扩展方法
|
||||
*/
|
||||
|
||||
/**
|
||||
* Toast
|
||||
* @param text CharSequence 类型文本
|
||||
*/
|
||||
fun Context.toast(text: CharSequence, duration: Int = Toast.LENGTH_SHORT) {
|
||||
Toast.makeText(this, text, duration).show()
|
||||
}
|
||||
|
||||
/**
|
||||
* Toast
|
||||
* @param resId String 类型资源id
|
||||
*/
|
||||
fun Context.toast(@StringRes resId: Int, duration: Int = Toast.LENGTH_SHORT) {
|
||||
Toast.makeText(this, resId, duration).show()
|
||||
}
|
||||
|
||||
/**
|
||||
* 居中Toast
|
||||
* @param text CharSequence 类型文本
|
||||
*/
|
||||
fun Context.centerToast(text: CharSequence, duration: Int = Toast.LENGTH_SHORT) {
|
||||
val toast = Toast.makeText(this, text, duration)
|
||||
toast.setGravity(Gravity.CENTER, 0, 0)
|
||||
toast.show()
|
||||
}
|
||||
|
||||
/**
|
||||
* 居中Toast
|
||||
* @param resId String 类型资源id
|
||||
*/
|
||||
fun Context.centerToast(@StringRes resId: Int, duration: Int = Toast.LENGTH_SHORT) {
|
||||
val toast = Toast.makeText(this, resId, duration)
|
||||
toast.setGravity(Gravity.CENTER, 0, 0)
|
||||
toast.show()
|
||||
}
|
||||
|
||||
/**
|
||||
* dp 转 px
|
||||
*/
|
||||
fun Context.dp2px(dpValue: Float): Int {
|
||||
val scale = resources.displayMetrics.density
|
||||
return (dpValue * scale + 0.5f).toInt()
|
||||
}
|
||||
|
||||
/**
|
||||
* px 转 dp
|
||||
*/
|
||||
fun Context.px2dp(pxValue: Float): Int {
|
||||
val scale = resources.displayMetrics.density
|
||||
return (pxValue / scale + 0.5f).toInt()
|
||||
}
|
||||
|
||||
/**
|
||||
* sp 转 px
|
||||
*/
|
||||
fun Context.sp2px(spValue: Float): Int {
|
||||
val scale = resources.displayMetrics.scaledDensity
|
||||
return (spValue * scale + 0.5f).toInt()
|
||||
}
|
||||
|
||||
/**
|
||||
* px 转 sp
|
||||
*/
|
||||
fun Context.px2sp(pxValue: Float): Int {
|
||||
val scale = resources.displayMetrics.scaledDensity
|
||||
return (pxValue / scale + 0.5f).toInt()
|
||||
}
|
||||
23
Lib_Base/src/main/java/com/quyunshuo/base/ktx/ViewKtx.kt
Normal file
23
Lib_Base/src/main/java/com/quyunshuo/base/ktx/ViewKtx.kt
Normal file
@ -0,0 +1,23 @@
|
||||
package com.quyunshuo.base.ktx
|
||||
|
||||
import android.view.View
|
||||
|
||||
/**
|
||||
* @Author: QuYunShuo
|
||||
* @Time: 2020/8/17
|
||||
* @Class: ViewKtx
|
||||
* @Remark: View相关的扩展方法
|
||||
*/
|
||||
|
||||
|
||||
fun View.gone() {
|
||||
visibility = View.GONE
|
||||
}
|
||||
|
||||
fun View.visible() {
|
||||
visibility = View.VISIBLE
|
||||
}
|
||||
|
||||
fun View.invisible() {
|
||||
visibility = View.INVISIBLE
|
||||
}
|
||||
@ -5,6 +5,7 @@ import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.viewbinding.ViewBinding
|
||||
import com.alibaba.android.arouter.launcher.ARouter
|
||||
|
||||
/**
|
||||
* @Author: QuYunShuo
|
||||
@ -24,6 +25,8 @@ abstract class BaseFrameActivity<VB : ViewBinding, VM : ViewModel>(private val v
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(mBinding.root)
|
||||
// ARouter 依赖注入
|
||||
ARouter.getInstance().inject(this)
|
||||
initView()
|
||||
}
|
||||
|
||||
|
||||
59
Lib_Base/src/main/java/com/quyunshuo/base/utils/SpUtils.kt
Normal file
59
Lib_Base/src/main/java/com/quyunshuo/base/utils/SpUtils.kt
Normal file
@ -0,0 +1,59 @@
|
||||
package com.quyunshuo.base.utils
|
||||
|
||||
import android.content.Context
|
||||
import com.tencent.mmkv.MMKV
|
||||
|
||||
/**
|
||||
* @Author: QuYunShuo
|
||||
* @Time: 2020/8/28
|
||||
* @Class: SpUtils
|
||||
* @Remark: MMKV使用封装
|
||||
*/
|
||||
object SpUtils {
|
||||
|
||||
/**
|
||||
* 初始化
|
||||
*/
|
||||
fun initMMKV(context: Context): String? = MMKV.initialize(context)
|
||||
|
||||
/**
|
||||
* 保存数据(简化)
|
||||
* 根据value类型自动匹配需要执行的方法
|
||||
*/
|
||||
fun put(key: String, value: Any) =
|
||||
when (value) {
|
||||
is Int -> putInt(key, value)
|
||||
is Long -> putLong(key, value)
|
||||
is Float -> putFloat(key, value)
|
||||
is Double -> putDouble(key, value)
|
||||
is String -> putString(key, value)
|
||||
is Boolean -> putBoolean(key, value)
|
||||
else -> false
|
||||
}
|
||||
|
||||
fun putString(key: String, value: String): Boolean = MMKV.defaultMMKV().encode(key, value)
|
||||
|
||||
fun getString(key: String, defValue: String): String = MMKV.defaultMMKV().decodeString(key, defValue)
|
||||
|
||||
fun putInt(key: String, value: Int): Boolean = MMKV.defaultMMKV().encode(key, value)
|
||||
|
||||
fun getInt(key: String, defValue: Int): Int = MMKV.defaultMMKV().decodeInt(key, defValue)
|
||||
|
||||
fun putLong(key: String, value: Long): Boolean = MMKV.defaultMMKV().encode(key, value)
|
||||
|
||||
fun getLong(key: String, defValue: Long): Long = MMKV.defaultMMKV().decodeLong(key, defValue)
|
||||
|
||||
fun putDouble(key: String, value: Double): Boolean = MMKV.defaultMMKV().encode(key, value)
|
||||
|
||||
fun getDouble(key: String, defValue: Double): Double = MMKV.defaultMMKV().decodeDouble(key, defValue)
|
||||
|
||||
fun putFloat(key: String, value: Float): Boolean = MMKV.defaultMMKV().encode(key, value)
|
||||
|
||||
fun getFloat(key: String, defValue: Float): Float = MMKV.defaultMMKV().decodeFloat(key, defValue)
|
||||
|
||||
fun putBoolean(key: String, value: Boolean): Boolean = MMKV.defaultMMKV().encode(key, value)
|
||||
|
||||
fun getBoolean(key: String, defValue: Boolean): Boolean = MMKV.defaultMMKV().decodeBool(key, defValue)
|
||||
|
||||
fun contains(key: String): Boolean = MMKV.defaultMMKV().contains(key)
|
||||
}
|
||||
35
Lib_Base/src/main/java/com/quyunshuo/base/utils/Utils.kt
Normal file
35
Lib_Base/src/main/java/com/quyunshuo/base/utils/Utils.kt
Normal file
@ -0,0 +1,35 @@
|
||||
package com.quyunshuo.base.utils
|
||||
|
||||
import android.util.Log
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.InternalCoroutinesApi
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.catch
|
||||
import kotlinx.coroutines.flow.collect
|
||||
import kotlinx.coroutines.flow.flow
|
||||
import kotlinx.coroutines.flow.flowOn
|
||||
|
||||
/**
|
||||
* 以顶层函数存在的常用工具方法
|
||||
* startPolling() -> 开启一个轮询
|
||||
*/
|
||||
|
||||
/**
|
||||
* 使用 Flow 做的简单的轮询
|
||||
* 请使用单独的协程来进行管理该 Flow
|
||||
* Flow 仍有一些操作符是实验性的 使用时需添加 @InternalCoroutinesApi 注解
|
||||
* @param intervals 轮询间隔时间/毫秒
|
||||
* @param block 需要执行的代码块
|
||||
*/
|
||||
@InternalCoroutinesApi
|
||||
suspend fun startPolling(intervals: Long, block: () -> Unit) {
|
||||
flow {
|
||||
while (true) {
|
||||
delay(intervals)
|
||||
emit(0)
|
||||
}
|
||||
}
|
||||
.catch { Log.e("flow", "startPolling: $it") }
|
||||
.flowOn(Dispatchers.Main)
|
||||
.collect { block.invoke() }
|
||||
}
|
||||
@ -1,7 +1,7 @@
|
||||
<resources>
|
||||
|
||||
<!-- Base application theme. -->
|
||||
<style name="base_AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
|
||||
<style name="base_AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
|
||||
<!-- Customize your theme here. -->
|
||||
<item name="colorPrimary">@color/base_colorPrimary</item>
|
||||
<item name="colorPrimaryDark">@color/base_colorPrimaryDark</item>
|
||||
|
||||
@ -8,5 +8,4 @@ import com.quyunshuo.base.BaseApplication
|
||||
* @Class: CommonApplication
|
||||
* @Remark: 项目相关的Application
|
||||
*/
|
||||
open class CommonApplication : BaseApplication() {
|
||||
}
|
||||
open class CommonApplication : BaseApplication()
|
||||
@ -0,0 +1,11 @@
|
||||
package com.quyunshuo.common.constant
|
||||
|
||||
/**
|
||||
* @Author: QuYunShuo
|
||||
* @Time: 2020/8/28
|
||||
* @Class: RouteKey
|
||||
* @Remark: 路由使用中 用到的Key 统一写在此类中
|
||||
*/
|
||||
object RouteKey {
|
||||
const val KEY_NAME = "key_name"
|
||||
}
|
||||
@ -0,0 +1,16 @@
|
||||
package com.quyunshuo.common.constant
|
||||
|
||||
/**
|
||||
* @Author: QuYunShuo
|
||||
* @Time: 2020/8/28
|
||||
* @Class: RoutePath
|
||||
* @Remark: 路由地址
|
||||
*/
|
||||
object RouteUrl {
|
||||
|
||||
// MainActivity
|
||||
const val MainActivity: String = "/lib_splash/SplashActivity"
|
||||
|
||||
// MainActivity2
|
||||
const val MainActivity2: String = "/lib_splash/SplashActivity2"
|
||||
}
|
||||
@ -3,7 +3,10 @@
|
||||
package="com.quyunshuo.main">
|
||||
|
||||
<application>
|
||||
<activity android:name=".MainActivity">
|
||||
<activity android:name=".MainActivity2"></activity>
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:screenOrientation="sensorLandscape">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
||||
|
||||
@ -1,6 +1,10 @@
|
||||
package com.quyunshuo.main
|
||||
|
||||
import android.widget.Toast
|
||||
import com.alibaba.android.arouter.facade.annotation.Route
|
||||
import com.alibaba.android.arouter.launcher.ARouter
|
||||
import com.quyunshuo.common.constant.RouteKey
|
||||
import com.quyunshuo.common.constant.RouteUrl
|
||||
import com.quyunshuo.common.ui.BaseActivity
|
||||
import com.quyunshuo.main.databinding.MainActivityMainBinding
|
||||
|
||||
@ -10,6 +14,7 @@ import com.quyunshuo.main.databinding.MainActivityMainBinding
|
||||
* @Class: MainActivity
|
||||
* @Remark: 主界面Activity
|
||||
*/
|
||||
@Route(path = RouteUrl.MainActivity)
|
||||
class MainActivity :
|
||||
BaseActivity<MainActivityMainBinding, MainViewModel>(MainViewModel::class.java) {
|
||||
|
||||
@ -22,5 +27,9 @@ class MainActivity :
|
||||
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()
|
||||
}
|
||||
}
|
||||
}
|
||||
25
Lib_Main/src/main/java/com/quyunshuo/main/MainActivity2.kt
Normal file
25
Lib_Main/src/main/java/com/quyunshuo/main/MainActivity2.kt
Normal file
@ -0,0 +1,25 @@
|
||||
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)
|
||||
}
|
||||
}
|
||||
@ -24,4 +24,22 @@
|
||||
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" />
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="300dp"
|
||||
android:layout_height="300dp"
|
||||
android:background="#333"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
9
Lib_Main/src/main/res/layout/main_activity_main_2.xml
Normal file
9
Lib_Main/src/main/res/layout/main_activity_main_2.xml
Normal file
@ -0,0 +1,9 @@
|
||||
<?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>
|
||||
@ -1,6 +1,12 @@
|
||||
# Android项目框架(组件化 + Kotlin + MVVM + Jetpack )
|
||||
|
||||
note: 1. 测试打包脚本
|
||||
|
||||
资源文件相关{
|
||||
资源相关文件属于项目相关的,因此需要放在Common组件内,不要放在Base组件里
|
||||
String、Color、Style、layout、drawable、mipmap 公用的 放在Common组件内,不公用的放在各自组件内,命名以各组件的规则命名(build文件设置了规则)
|
||||
}
|
||||
|
||||
协程相关{
|
||||
Activity/Fragment 中 可以使用 lifecycleScope,与Activity/Fragment绑定了生命周期 无需手动取消
|
||||
ViewModel 中 可以使用 viewModelScope,它与ViewModel绑定了生命周期 无需手动取消
|
||||
|
||||
@ -9,6 +9,14 @@
|
||||
android:label="@string/app_name"
|
||||
android:roundIcon="@mipmap/ic_launcher_round"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/base_AppTheme" />
|
||||
android:theme="@style/base_AppTheme">
|
||||
<!-- <!– 屏幕适配基准DP –>-->
|
||||
<!-- <meta-data-->
|
||||
<!-- android:name="design_width_in_dp"-->
|
||||
<!-- android:value="640" />-->
|
||||
<!-- <meta-data-->
|
||||
<!-- android:name="design_height_in_dp"-->
|
||||
<!-- android:value="400" />-->
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
@ -11,8 +11,8 @@ import com.quyunshuo.common.CommonApplication
|
||||
*/
|
||||
class AppApplication : CommonApplication() {
|
||||
|
||||
override fun onCreate() {
|
||||
override fun initialize() {
|
||||
MultiDex.install(this)
|
||||
super.onCreate()
|
||||
super.initialize()
|
||||
}
|
||||
}
|
||||
@ -38,6 +38,7 @@ object Version {
|
||||
const val ARoute = "1.5.0" // 阿里路由
|
||||
const val ARouteCompiler = "1.2.2" // 阿里路由 APT
|
||||
const val RecyclerViewAdapter = "3.0.4" // RecyclerViewAdapter
|
||||
const val StatusBar = "1.5.1" // 状态栏
|
||||
}
|
||||
|
||||
object AndroidX {
|
||||
@ -89,4 +90,5 @@ object GitHub {
|
||||
const val ARouteCompiler = "com.alibaba:arouter-compiler:${Version.ARouteCompiler}"
|
||||
const val RecyclerViewAdapter =
|
||||
"com.github.CymChad:BaseRecyclerViewAdapterHelper:${Version.RecyclerViewAdapter}"
|
||||
const val StatusBar = "com.jaeger.statusbarutil:library:${Version.StatusBar}"
|
||||
}
|
||||
Reference in New Issue
Block a user