| @@ -7,6 +7,7 @@ | |||
| <option name="testRunner" value="GRADLE" /> | |||
| <option name="distributionType" value="DEFAULT_WRAPPED" /> | |||
| <option name="externalProjectPath" value="$PROJECT_DIR$" /> | |||
| <option name="gradleJvm" value="Embedded JDK" /> | |||
| <option name="modules"> | |||
| <set> | |||
| <option value="$PROJECT_DIR$" /> | |||
| @@ -3,8 +3,10 @@ | |||
| <component name="DesignSurface"> | |||
| <option name="filePathToZoomLevelMap"> | |||
| <map> | |||
| <entry key="..\:/Work/XKL/XklLocal/app/src/main/res/drawable/theme_splash_bg.xml" value="0.22" /> | |||
| <entry key="..\:/Work/XKL/XklLocal/app/src/main/res/layout/activity_fullscreen.xml" value="0.10144927536231885" /> | |||
| <entry key="..\:/Work/XKL/XklLocal/app/src/main/res/layout/activity_main.xml" value="0.1" /> | |||
| <entry key="..\:/Work/XKL/XklLocal/app/src/main/res/layout/activity_splash.xml" value="0.1" /> | |||
| </map> | |||
| </option> | |||
| </component> | |||
| @@ -0,0 +1,4 @@ | |||
| 项目中遇到的错误: | |||
| 使用jectPack时的依赖: | |||
| · androidx.appcompat: appcompat 依赖中已经带了livedata、viewmodel等,可以不用再依赖,再依赖时出现了异常编译错误,未解决 | |||
| 且 依赖版本不同,对应的livedata等版本也不同 | |||
| @@ -7,6 +7,8 @@ ext.dependencies_testImplementation : 测试依赖 | |||
| ext.dependencies_androidTestImplementation : 测试依赖 | |||
| ext.dependencies_custom : 自己添加的依赖项,按需定制 | |||
| androidx.appcompat:appcompat 自带jetpack中的lifecycle、viewmodel、livedata | |||
| app: | |||
| module : 按模块进行业务划分 | |||
| @@ -1,6 +1,7 @@ | |||
| plugins { | |||
| id 'com.android.application' | |||
| id 'kotlin-android' | |||
| id 'kotlin-kapt' | |||
| } | |||
| def androidConfig = rootProject.ext.android | |||
| android { | |||
| @@ -26,27 +27,27 @@ android { | |||
| //配置产品变种 与 构建变体 | |||
| //flavorDimensions :变种维度 | |||
| flavorDimensions "version" | |||
| productFlavors{ //产品变种 | |||
| demo{ | |||
| dimension "version" | |||
| //applicationId后追加 .demo 也可以重新定义applicationId 属性 | |||
| applicationIdSuffix ".demo" | |||
| versionNameSuffix "-demo" | |||
| } | |||
| full { | |||
| dimension "version" | |||
| applicationIdSuffix ".full" | |||
| versionNameSuffix '-full' | |||
| } | |||
| } | |||
| // flavorDimensions "version" | |||
| // productFlavors{ //产品变种 | |||
| // demo{ | |||
| // dimension "version" | |||
| // //applicationId后追加 .demo 也可以重新定义applicationId 属性 | |||
| // applicationIdSuffix ".demo" | |||
| // versionNameSuffix "-demo" | |||
| // } | |||
| // full { | |||
| // dimension "version" | |||
| // applicationIdSuffix ".full" | |||
| // versionNameSuffix '-full' | |||
| // } | |||
| // } | |||
| //变体过滤器 | |||
| variantFilter { variant -> | |||
| def names = variant.flavors*.name | |||
| if (name.contains("demo")){ | |||
| setIgnore(true) | |||
| } | |||
| } | |||
| // variantFilter { variant -> | |||
| // def names = variant.flavors*.name | |||
| // if (name.contains("demo")){ | |||
| // setIgnore(true) | |||
| // } | |||
| // } | |||
| compileOptions { | |||
| sourceCompatibility JavaVersion.VERSION_1_8 | |||
| @@ -57,15 +58,46 @@ android { | |||
| } | |||
| buildFeatures { | |||
| viewBinding true | |||
| dataBinding true | |||
| } | |||
| } | |||
| dependencies { | |||
| implementation 'androidx.appcompat:appcompat:1.2.0' | |||
| implementation 'com.google.android.material:material:1.3.0' | |||
| implementation 'androidx.constraintlayout:constraintlayout:2.0.4' | |||
| implementation 'androidx.legacy:legacy-support-v4:1.0.0' | |||
| implementation project(path: ':lib:common') | |||
| rootProject.ext.dependencies_required.each{ k, v -> implementation v} | |||
| testImplementation rootProject.ext.dependencies_testImplementation.junit | |||
| rootProject.ext.dependencies_androidTestImplementation.each{ k,v -> androidTestImplementation v} | |||
| // kapt rootProject.ext.dependencies_kapt.lifecycle_compiler | |||
| def lifecycle_version = "2.5.0-alpha02" | |||
| def arch_version = "2.1.0" | |||
| // | |||
| // // ViewModel | |||
| // implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version" | |||
| // // ViewModel utilities for Compose | |||
| // implementation "androidx.lifecycle:lifecycle-viewmodel-compose:$lifecycle_version" | |||
| // // LiveData | |||
| // implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version" | |||
| // // Lifecycles only (without ViewModel or LiveData) | |||
| // implementation "androidx.lifecycle:lifecycle-runtime-ktx:$lifecycle_version" | |||
| // | |||
| // // Saved state module for ViewModel | |||
| // implementation "androidx.lifecycle:lifecycle-viewmodel-savedstate:$lifecycle_version" | |||
| // | |||
| // // Annotation processor | |||
| //// kapt "androidx.lifecycle:lifecycle-compiler:$lifecycle_version" | |||
| // // alternately - if using Java8, use the following instead of lifecycle-compiler | |||
| // implementation "androidx.lifecycle:lifecycle-common-java8:$lifecycle_version" | |||
| // // optional - helpers for implementing LifecycleOwner in a Service | |||
| // implementation "androidx.lifecycle:lifecycle-service:$lifecycle_version" | |||
| // | |||
| // // optional - ProcessLifecycleOwner provides a lifecycle for the whole application process | |||
| // implementation "androidx.lifecycle:lifecycle-process:$lifecycle_version" | |||
| // | |||
| // // optional - ReactiveStreams support for LiveData | |||
| // implementation "androidx.lifecycle:lifecycle-reactivestreams-ktx:$lifecycle_version" | |||
| // | |||
| // // optional - Test helpers for LiveData | |||
| // testImplementation "androidx.arch.core:core-testing:$arch_version" | |||
| } | |||
| @@ -10,14 +10,18 @@ | |||
| android:supportsRtl="true" | |||
| android:theme="@style/Theme.XklLocal"> | |||
| <activity | |||
| android:name=".module.main.MainActivity" | |||
| android:name=".module.splash.SplashActivity" | |||
| android:configChanges="orientation|keyboardHidden|screenSize" | |||
| android:exported="true" > | |||
| android:exported="true" | |||
| android:theme="@style/Theme.Splash"> | |||
| <intent-filter> | |||
| <action android:name="android.intent.action.MAIN" /> | |||
| <category android:name="android.intent.category.LAUNCHER" /> | |||
| </intent-filter> | |||
| </activity> | |||
| <activity | |||
| android:name=".module.main.MainActivity" | |||
| android:configChanges="orientation|keyboardHidden|screenSize"/> | |||
| </application> | |||
| </manifest> | |||
| @@ -1,4 +1,4 @@ | |||
| package com.xkl.cdl.module.center_learn | |||
| package com.xkl.cdl.module.m_center_learn | |||
| import android.os.Bundle | |||
| import androidx.fragment.app.Fragment | |||
| @@ -1,4 +1,4 @@ | |||
| package com.xkl.cdl.module.memo | |||
| package com.xkl.cdl.module.m_memo | |||
| import android.os.Bundle | |||
| import androidx.fragment.app.Fragment | |||
| @@ -1,4 +1,4 @@ | |||
| package com.xkl.cdl.module.my | |||
| package com.xkl.cdl.module.m_my | |||
| import android.os.Bundle | |||
| import androidx.fragment.app.Fragment | |||
| @@ -1,4 +1,4 @@ | |||
| package com.xkl.cdl.module.statics | |||
| package com.xkl.cdl.module.m_statics | |||
| import android.os.Bundle | |||
| import androidx.fragment.app.Fragment | |||
| @@ -0,0 +1,46 @@ | |||
| package com.xkl.cdl.module.splash | |||
| import android.os.Bundle | |||
| import android.os.Handler | |||
| import android.os.Looper | |||
| import android.os.Message | |||
| import androidx.databinding.ObservableField | |||
| import com.suliang.common.base.activity.BaseActivity | |||
| import com.xkl.cdl.databinding.ActivitySplashBinding | |||
| class SplashActivity : BaseActivity<ActivitySplashBinding>() { | |||
| val textvalue = ObservableField<String>() | |||
| private val handler = object : Handler(Looper.getMainLooper()){ | |||
| override fun handleMessage(msg: Message) { | |||
| super.handleMessage(msg) | |||
| binding.text.text = textvalue.get() | |||
| } | |||
| } | |||
| override fun onCreate(savedInstanceState: Bundle?) { | |||
| if(!isTaskRoot){ | |||
| finish() | |||
| return | |||
| } | |||
| super.onCreate(savedInstanceState) | |||
| } | |||
| var count = 1 | |||
| override fun initActivity(savedInstanceState: Bundle?) { | |||
| val x = Tvalue(textvalue) | |||
| binding.name = x | |||
| handler.postDelayed(object : Runnable{ | |||
| override fun run() { | |||
| count ++ | |||
| textvalue.set("$count") | |||
| handler.postDelayed(this,1000) | |||
| } | |||
| },1000) | |||
| } | |||
| } | |||
| data class Tvalue(val value : ObservableField<String>) | |||
| @@ -0,0 +1,12 @@ | |||
| <?xml version="1.0" encoding="utf-8"?> | |||
| <layer-list xmlns:android="http://schemas.android.com/apk/res/android"> | |||
| <item android:drawable="@color/white"/> | |||
| <item android:gravity="center" android:bottom="100dp"> | |||
| <bitmap | |||
| android:src="@mipmap/splash_logo" | |||
| android:scaleType="centerInside"/> | |||
| </item> | |||
| </layer-list> | |||
| @@ -0,0 +1,40 @@ | |||
| <?xml version="1.0" encoding="utf-8"?> | |||
| <layout 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"> | |||
| <data> | |||
| <variable | |||
| name="name" | |||
| type="com.xkl.cdl.module.splash.Tvalue" /> | |||
| </data> | |||
| <androidx.constraintlayout.widget.ConstraintLayout | |||
| android:layout_width="match_parent" | |||
| android:layout_height="match_parent" | |||
| tools:context=".module.splash.SplashActivity"> | |||
| <ImageView | |||
| android:id="@+id/img" | |||
| android:layout_width="match_parent" | |||
| android:layout_height="0dp" | |||
| app:layout_constraintLeft_toLeftOf="parent" | |||
| app:layout_constraintRight_toRightOf="parent" | |||
| app:layout_constraintTop_toTopOf="parent" | |||
| app:layout_constraintBottom_toBottomOf="parent" | |||
| app:layout_constraintVertical_bias="0.6" | |||
| app:layout_constraintDimensionRatio="1125:813" | |||
| android:src="@drawable/illustration_splash" | |||
| /> | |||
| <TextView | |||
| android:id="@+id/text" | |||
| android:layout_width="wrap_content" | |||
| android:layout_height="wrap_content" | |||
| android:text="@={name.value}" | |||
| android:textSize="18dp" | |||
| app:layout_constraintBottom_toBottomOf="parent" | |||
| app:layout_constraintStart_toStartOf="parent" | |||
| app:layout_constraintEnd_toEndOf="parent"/> | |||
| </androidx.constraintlayout.widget.ConstraintLayout> | |||
| </layout> | |||
| @@ -3,7 +3,7 @@ | |||
| xmlns:tools="http://schemas.android.com/tools" | |||
| android:layout_width="match_parent" | |||
| android:layout_height="match_parent" | |||
| tools:context=".module.center_learn.LearnCenterFragment"> | |||
| tools:context=".module.m_center_learn.LearnCenterFragment"> | |||
| <!-- TODO: Update blank fragment layout --> | |||
| <TextView | |||
| @@ -3,7 +3,7 @@ | |||
| xmlns:tools="http://schemas.android.com/tools" | |||
| android:layout_width="match_parent" | |||
| android:layout_height="match_parent" | |||
| tools:context=".module.memo.MemoFragment"> | |||
| tools:context=".module.m_memo.MemoFragment"> | |||
| <!-- TODO: Update blank fragment layout --> | |||
| <TextView | |||
| @@ -3,7 +3,7 @@ | |||
| xmlns:tools="http://schemas.android.com/tools" | |||
| android:layout_width="match_parent" | |||
| android:layout_height="match_parent" | |||
| tools:context=".module.my.MyFragment"> | |||
| tools:context=".module.m_my.MyFragment"> | |||
| <!-- TODO: Update blank fragment layout --> | |||
| <TextView | |||
| @@ -3,7 +3,7 @@ | |||
| xmlns:tools="http://schemas.android.com/tools" | |||
| android:layout_width="match_parent" | |||
| android:layout_height="match_parent" | |||
| tools:context=".module.statics.StaticsFragment"> | |||
| tools:context=".module.m_statics.StaticsFragment"> | |||
| <!-- TODO: Update blank fragment layout --> | |||
| <TextView | |||
| @@ -1,17 +1,33 @@ | |||
| <resources xmlns:tools="http://schemas.android.com/tools"> | |||
| <!-- Base application theme. --> | |||
| <style name="Theme.XklLocal" parent="Theme.MaterialComponents.DayNight.DarkActionBar"> | |||
| <style name="Theme.XklLocal" parent="Theme.MaterialComponents.Light.DarkActionBar"> | |||
| <!-- Primary brand color. --> | |||
| <item name="colorPrimary">@color/purple_500</item> | |||
| <item name="colorPrimaryVariant">@color/purple_700</item> | |||
| <item name="colorOnPrimary">@color/white</item> | |||
| <!-- Secondary brand color. --> | |||
| <item name="colorSecondary">@color/teal_200</item> | |||
| <item name="colorSecondaryVariant">@color/teal_700</item> | |||
| <item name="colorOnSecondary">@color/black</item> | |||
| <!-- Status bar color. --> | |||
| <item name="android:statusBarColor" tools:targetApi="l">?attr/colorPrimaryVariant</item> | |||
| <item name="colorPrimary">@color/white</item> <!--AppBar背景色--> | |||
| <!-- <item name="colorPrimaryVariant">@color/white</item>--> | |||
| <item name="colorOnPrimary">@color/black</item> | |||
| <!-- <!– Secondary brand color. –>--> | |||
| <!-- <item name="colorSecondary">@color/white</item>--> | |||
| <!-- <item name="colorSecondaryVariant">@color/white</item>--> | |||
| <!-- <item name="colorOnSecondary">@color/white</item>--> | |||
| <!-- <!– Status bar color. –>--> | |||
| <item name="android:statusBarColor" tools:targetApi="l">@color/white</item> | |||
| <!-- Customize your theme here. --> | |||
| <item name="android:textAllCaps">false</item> | |||
| <item name="android:windowActionBar">false</item> | |||
| <item name="windowActionBar">false</item> | |||
| <item name="windowNoTitle">true</item> | |||
| <item name="android:windowNoTitle">true</item> | |||
| <item name="android:windowIsTranslucent">true</item> | |||
| <item name="android:windowDrawsSystemBarBackgrounds">true</item> | |||
| <item name="android:windowEnableSplitTouch">false</item> | |||
| <item name="android:splitMotionEvents">false</item> | |||
| <item name="android:windowBackground">@android:color/transparent</item> | |||
| </style> | |||
| <!--启动页背景图层--> | |||
| <style name="Theme.Splash" parent="Theme.XklLocal"> | |||
| <item name="android:windowBackground">@drawable/theme_splash_bg</item> | |||
| </style> | |||
| </resources> | |||
| @@ -3,6 +3,8 @@ buildscript { | |||
| repositories { | |||
| google() | |||
| mavenCentral() | |||
| maven { url 'https://jitpack.io' } | |||
| } | |||
| dependencies { | |||
| classpath "com.android.tools.build:gradle:7.0.1" | |||
| @@ -20,27 +22,40 @@ task clean(type: Delete) { | |||
| //在项目级别定义某些属性并在所有模块之间共享这些属性 | |||
| ext { | |||
| android = [ | |||
| compile_sdk_version: 30, //使用rootProject.ext.android.compile_sdk_version | |||
| compile_sdk_version: 31, //使用rootProject.ext.android.compile_sdk_version | |||
| build_tools_version: "30.0.2", | |||
| min_sdk_version : 21, | |||
| target_sdk_version : 30, | |||
| target_sdk_version : 31, | |||
| version_code : 100, | |||
| version_name : "100", | |||
| applicationId : "com.xkl.cdl" | |||
| ] | |||
| versions = [ | |||
| core_ktx_version : "1.3.2", | |||
| appcompat_version: "1.2.0", | |||
| appcompat_version: "1.4.1", | |||
| material_version : "1.3.0", | |||
| lifecycle_version: "2.5.0-alpha02" | |||
| ] | |||
| //必须依赖 | |||
| dependencies_required = [ | |||
| //为属于Android框架的通用库提供扩展程序 | |||
| core_ktx : "androidx.core:core-ktx:${versions.core_ktx_version}", | |||
| core_ktx : "androidx.core:core-ktx:${versions.core_ktx_version}", | |||
| //Androidx 依赖 | |||
| appcompat: "androidx.appcompat:appcompat:${versions.appcompat_version}", | |||
| appcompat : "androidx.appcompat:appcompat:${versions.appcompat_version}", | |||
| //material_design | |||
| material : "com.google.android.material:material:${versions.material_version}", | |||
| material : "com.google.android.material:material:${versions.material_version}", | |||
| //constraintlayout | |||
| constraintlayout : "androidx.constraintlayout:constraintlayout:2.0.4", | |||
| //lifecycle | |||
| // lifecycle : "androidx.lifecycle:lifecycle-runtime-ktx:${versions.lifecycle_version}", | |||
| // //lifecycle saved state module for viewmodel | |||
| //// lifecycle_viewmodel_savestate: "androidx.lifecycle:lifecycle-viewmodel-savedstate:${versions.lifecycle_version}", | |||
| // //ViewModel | |||
| // viewmodel : "androidx.lifecycle:lifecycle-viewmodel-ktx:${versions.lifecycle_version}", | |||
| // //livedata | |||
| // livedata : "androidx.lifecycle:lifecycle-livedata-ktx:${versions.lifecycle_version}", | |||
| //java8 lifecycle_compiler | |||
| // lifecycle_compiler : "androidx.lifecycle:lifecycle-common-java8:${versions.lifecycle_version}" | |||
| ] | |||
| dependencies_testImplementation = [ | |||
| junit: "junit:junit:4.+" | |||
| @@ -49,8 +64,16 @@ ext { | |||
| test_ext_junit : "androidx.test.ext:junit:1.1.2", | |||
| test_espresson_core: "androidx.test.espresso:espresso-core:3.3.0" | |||
| ] | |||
| //按需依赖项 | |||
| dependencies_custom = [] | |||
| //依赖项 | |||
| dependencies_custom = [ | |||
| //设置状态栏和导航栏的框架 https://github.com/Zackratos/UltimateBarX | |||
| UltimateBarX: "com.gitee.zackratos:UltimateBarX:0.8.0", | |||
| ] | |||
| //注解 | |||
| // dependencies_kapt = [ | |||
| // lifecycle_compiler: "androidx.lifecycle:lifecycle-compiler:${versions.lifecycle_version}", | |||
| // | |||
| // ] | |||
| } | |||
| @@ -30,11 +30,9 @@ android { | |||
| kotlinOptions { | |||
| jvmTarget = '1.8' | |||
| } | |||
| viewBinding{ | |||
| enabled true | |||
| } | |||
| dataBinding{ | |||
| enabled true | |||
| buildFeatures { | |||
| viewBinding true | |||
| dataBinding true | |||
| } | |||
| } | |||
| @@ -42,4 +40,39 @@ dependencies { | |||
| rootProject.ext.dependencies_required.each{ k,v -> implementation v} | |||
| testImplementation rootProject.ext.dependencies_testImplementation.junit | |||
| rootProject.ext.dependencies_androidTestImplementation.each{ k,v -> androidTestImplementation v} | |||
| // api rootProject.ext.dependencies_custom.UltimateBarX | |||
| // kapt rootProject.ext.dependencies_kapt.lifecycle_compiler | |||
| def lifecycle_version = "2.5.0-alpha02" | |||
| def arch_version = "2.1.0" | |||
| // // ViewModel | |||
| // implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version" | |||
| // // ViewModel utilities for Compose | |||
| // implementation "androidx.lifecycle:lifecycle-viewmodel-compose:$lifecycle_version" | |||
| // // LiveData | |||
| // implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version" | |||
| // // Lifecycles only (without ViewModel or LiveData) | |||
| // implementation "androidx.lifecycle:lifecycle-runtime-ktx:$lifecycle_version" | |||
| // | |||
| // // Saved state module for ViewModel | |||
| // implementation "androidx.lifecycle:lifecycle-viewmodel-savedstate:$lifecycle_version" | |||
| // | |||
| // // Annotation processor | |||
| //// kapt "androidx.lifecycle:lifecycle-compiler:$lifecycle_version" | |||
| // // alternately - if using Java8, use the following instead of lifecycle-compiler | |||
| // implementation "androidx.lifecycle:lifecycle-common-java8:$lifecycle_version" | |||
| // // optional - helpers for implementing LifecycleOwner in a Service | |||
| // implementation "androidx.lifecycle:lifecycle-service:$lifecycle_version" | |||
| // | |||
| // // optional - ProcessLifecycleOwner provides a lifecycle for the whole application process | |||
| // implementation "androidx.lifecycle:lifecycle-process:$lifecycle_version" | |||
| // | |||
| // // optional - ReactiveStreams support for LiveData | |||
| // implementation "androidx.lifecycle:lifecycle-reactivestreams-ktx:$lifecycle_version" | |||
| // | |||
| // // optional - Test helpers for LiveData | |||
| // testImplementation "androidx.arch.core:core-testing:$arch_version" | |||
| } | |||
| @@ -1,48 +1,82 @@ | |||
| package com.suliang.common.base.activity | |||
| import android.os.Bundle | |||
| import android.view.LayoutInflater | |||
| import androidx.appcompat.app.AppCompatActivity | |||
| import androidx.databinding.DataBindingUtil | |||
| import androidx.databinding.ViewDataBinding | |||
| import androidx.databinding.ViewDataBindingKtx | |||
| import java.lang.reflect.Method | |||
| import androidx.lifecycle.ViewModelProvider | |||
| import androidx.lifecycle.ViewModelProviders | |||
| import androidx.viewbinding.ViewBinding | |||
| import com.suliang.common.extension.initBinding | |||
| import com.suliang.common.util.ActivityStackManager | |||
| import java.lang.reflect.ParameterizedType | |||
| /** | |||
| * 基类Activity | |||
| */ | |||
| abstract class BaseActivity<VB : ViewDataBinding> : AppCompatActivity() { | |||
| lateinit var databinding: VB | |||
| abstract class BaseActivity<VB : ViewBinding> : AppCompatActivity() { | |||
| lateinit var binding: VB | |||
| override fun onCreate(savedInstanceState: Bundle?) { | |||
| super.onCreate(savedInstanceState) | |||
| addStackManager() | |||
| initFirst() | |||
| initActivity(savedInstanceState) } | |||
| protected open fun initFirst() { | |||
| setLayoutBefore() | |||
| initBinding() | |||
| binding = initBinding(layoutInflater) | |||
| setContentView(binding.root) | |||
| initStatusBar() | |||
| setLayoutAfter() | |||
| } | |||
| /** | |||
| * 状态栏初始化方法 | |||
| */ | |||
| open fun initStatusBar() { | |||
| // statusBarOnly { | |||
| // fitWindow = true | |||
| // color = Color.WHITE | |||
| // light = true | |||
| // } | |||
| } | |||
| override fun onDestroy() { | |||
| super.onDestroy() | |||
| ActivityStackManager.removeActivity(this) | |||
| } | |||
| private fun addStackManager() { | |||
| ActivityStackManager.addActivity(this) | |||
| } | |||
| /** 布局前操作 : 空实现 */ | |||
| public fun setLayoutBefore() { | |||
| public open fun setLayoutBefore() { | |||
| } | |||
| /** | |||
| * 实例化 binding和 设置布局 | |||
| * 布局后操作:空实现 | |||
| */ | |||
| private fun initBinding() { | |||
| // https://www.jianshu.com/p/e3d2421a0277 | |||
| // val genericSuperClass = this::class.java.genericSuperclass as ParameterizedType //超类 | |||
| // val type = genericSuperClass.actualTypeArguments[0].javaClass | |||
| // val infate: Method = type.getDeclaredMethod("inflate") | |||
| public open fun setLayoutAfter() { | |||
| } | |||
| /** | |||
| * 布局后操作:空实现 | |||
| * onCreate中给与app中用户的具体实现 | |||
| * @param savedInstanceState Bundle? | |||
| */ | |||
| public fun setLayoutAfter() { | |||
| abstract fun initActivity(savedInstanceState: Bundle?) | |||
| } | |||
| // @SuppressWarnings("unchecked") | |||
| // fun initBinding(inflater: LayoutInflater): VB { | |||
| // val vbClass = | |||
| // (javaClass.genericSuperclass as ParameterizedType).actualTypeArguments.filterIsInstance<Class<VB>>() | |||
| // val inflate = vbClass[0].getDeclaredMethod("inflate", LayoutInflater::class.java) | |||
| // return inflate.invoke(null, inflater) as VB | |||
| // } | |||
| public abstract fun layoutRes(): Int | |||
| } | |||
| @@ -0,0 +1,25 @@ | |||
| package com.suliang.common.base.activity | |||
| import android.os.Bundle | |||
| import androidx.databinding.ViewDataBinding | |||
| import androidx.lifecycle.ViewModel | |||
| import androidx.viewbinding.ViewBinding | |||
| /** | |||
| * Activity DataBinding 与 ViewModel基类,封装DataBinding和ViewModel | |||
| * @property VB : ViewDataBinding | |||
| * @property VM: ViewModel | |||
| */ | |||
| abstract class BaseActivityVM<VB : ViewDataBinding, VM:ViewModel> : BaseActivity<VB>() { | |||
| private lateinit var vm : VM | |||
| override fun initFirst() { | |||
| vm = initViewModel() | |||
| super.initFirst() | |||
| binding.lifecycleOwner = this | |||
| } | |||
| abstract fun initViewModel() : VM | |||
| } | |||
| @@ -0,0 +1,129 @@ | |||
| package com.suliang.common.base.adapter | |||
| import android.view.ViewGroup | |||
| import androidx.recyclerview.widget.RecyclerView | |||
| abstract class BaseAdapter<T> : | |||
| RecyclerView.Adapter<BaseAdapterViewHolder>() { | |||
| companion object{ | |||
| val TYPE_EMPTY = -1 | |||
| } | |||
| //数据源 | |||
| private var mData: MutableList<T> = mutableListOf<T>() | |||
| /** 是否需要显示空布局 */ | |||
| var needShowEmptyView = false | |||
| /** | |||
| * 当前位置是否需要显示空布局,主要是为0的时候,这个判断才会有效 | |||
| * @param position Int | |||
| */ | |||
| private fun enableEmptyPosition(position:Int): Boolean{ | |||
| return position == 0 && mData.isEmpty() && needShowEmptyView | |||
| } | |||
| override fun getItemCount(): Int { | |||
| return if (needShowEmptyView && mData.isEmpty()) 1 else mData.size | |||
| } | |||
| override fun getItemViewType(position: Int): Int { | |||
| if (enableEmptyPosition(position)){ | |||
| return TYPE_EMPTY | |||
| } | |||
| return super.getItemViewType(position) | |||
| } | |||
| override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BaseAdapterViewHolder { | |||
| return when(viewType){ | |||
| TYPE_EMPTY -> coverEmptyViewHolder(parent) | |||
| else -> coverViewHolder(parent,viewType) | |||
| } | |||
| } | |||
| override fun onBindViewHolder(holder: BaseAdapterViewHolder, position: Int) { | |||
| if (enableEmptyPosition(position)){ | |||
| onBindEmptyViewHolder(holder) | |||
| }else{ | |||
| onBindVH(holder,position) | |||
| } | |||
| } | |||
| /** 创建空布局的ViewHolder 如果needShowEmpty = false 则可以不创建 */ | |||
| abstract fun coverEmptyViewHolder(parent: ViewGroup): BaseAdapterViewHolder | |||
| /** 空布局的数据绑定 */ | |||
| abstract fun onBindEmptyViewHolder(holder: BaseAdapterViewHolder) | |||
| /** 创建 正常item的 ViewHolder */ | |||
| abstract fun coverViewHolder(parent: ViewGroup,viewType: Int): BaseAdapterViewHolder | |||
| /** 绑定 正常item 的数据 */ | |||
| abstract fun onBindVH(holder: BaseAdapterViewHolder,position: Int) | |||
| /** | |||
| * 设置数据,并更新列表 | |||
| * @param data List<T>? | |||
| */ | |||
| fun setData(data: MutableList<T>?) { | |||
| data?.let { it -> //不为空 | |||
| mData = it | |||
| } ?: let { //为空 | |||
| mData = mutableListOf() | |||
| } | |||
| notifyItemRangeChanged(0, mData.size) | |||
| } | |||
| /** | |||
| * 添加单条数据 | |||
| * @param data T? | |||
| * @param position Int? | |||
| */ | |||
| fun addData(data: T?, position: Int?) { | |||
| data?.let { | |||
| val size = mData.size | |||
| val startPosition = position?.let { it -> | |||
| when { | |||
| it < 0 -> 0 | |||
| it >= size -> size | |||
| else -> it | |||
| } | |||
| } ?: size | |||
| mData.add(startPosition,data) | |||
| notifyItemInserted(startPosition) | |||
| notifyItemRangeChanged(startPosition,mData.size + 1) | |||
| } | |||
| } | |||
| /** | |||
| * 添加数据集 | |||
| * @param data List<T>? 数据集 | |||
| * @param position Int? 添加到指定位置,可空 | |||
| */ | |||
| fun addData(data: List<T>?, position: Int? = null) { | |||
| if (!data.isNullOrEmpty()) { | |||
| val size = mData.size | |||
| val startPosition = position?.let { it -> | |||
| when { | |||
| it < 0 -> 0 | |||
| it >= size -> size | |||
| else -> it | |||
| } | |||
| } ?: size | |||
| mData.addAll(startPosition, data) | |||
| //通知有新的item插入进来了 | |||
| notifyItemInserted(startPosition) | |||
| //范围性更新,直接调用onBindViewHolder | |||
| notifyItemRangeChanged(startPosition, mData.size + 1 ) | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,6 @@ | |||
| package com.suliang.common.base.adapter | |||
| import androidx.databinding.ViewDataBinding | |||
| import androidx.recyclerview.widget.RecyclerView | |||
| class BaseAdapterViewHolder(binding: ViewDataBinding) : RecyclerView.ViewHolder(binding.root) | |||
| @@ -1,4 +1,36 @@ | |||
| package com.suliang.common.base.fragment | |||
| class BaseFragment { | |||
| import android.os.Bundle | |||
| import android.view.LayoutInflater | |||
| import android.view.View | |||
| import android.view.ViewGroup | |||
| import androidx.databinding.ViewDataBinding | |||
| import androidx.fragment.app.Fragment | |||
| import com.suliang.common.extension.initBinding | |||
| /** | |||
| * Fragment ViewBinding基类,封装ViewDataBinding | |||
| * @property VB : ViewDataBinding | |||
| * @property VM: ViewModel | |||
| */ | |||
| abstract class BaseFragment<VB: ViewDataBinding>: Fragment(){ | |||
| lateinit var binding: VB | |||
| override fun onCreateView( | |||
| inflater: LayoutInflater, | |||
| container: ViewGroup?, | |||
| savedInstanceState: Bundle? | |||
| ): View? { | |||
| binding = initBinding(inflater,container) | |||
| return super.onCreateView(inflater, container, savedInstanceState) | |||
| } | |||
| override fun onViewCreated(view: View, savedInstanceState: Bundle?) { | |||
| super.onViewCreated(view, savedInstanceState) | |||
| initFirst() | |||
| initFragment() | |||
| } | |||
| abstract fun initFirst() | |||
| abstract fun initFragment() | |||
| } | |||
| @@ -0,0 +1,17 @@ | |||
| package com.suliang.common.base.fragment | |||
| import androidx.databinding.ViewDataBinding | |||
| import androidx.lifecycle.ViewModel | |||
| /** | |||
| * Fragment DataBinding 与 ViewModel基类,封装DataBinding和ViewModel | |||
| * @property VB : ViewDataBinding | |||
| * @property VM: ViewModel | |||
| */ | |||
| abstract class BaseFragmentVM<VB:ViewDataBinding,VM:ViewModel>:BaseFragment<VB>() { | |||
| lateinit var viewModel: VM | |||
| override fun initFirst() { | |||
| viewModel = initViewModel() | |||
| } | |||
| abstract fun initViewModel():VM | |||
| } | |||
| @@ -0,0 +1,36 @@ | |||
| package com.suliang.common.extension | |||
| import android.view.LayoutInflater | |||
| import android.view.ViewGroup | |||
| import androidx.viewbinding.ViewBinding | |||
| import java.lang.reflect.ParameterizedType | |||
| /** | |||
| * 扩展方法,获取到ViewBinding的子类VB实例,主要用于Activity | |||
| * @receiver VB | |||
| * @param inflater LayoutInflater | |||
| * @param vbPosition Int 在超类泛型中的vb位置 | |||
| * @return VB | |||
| */ | |||
| @SuppressWarnings("unchecked") | |||
| inline fun <VB : ViewBinding> Any.initBinding(inflater: LayoutInflater,vbPosition:Int = 0): VB { | |||
| val vbClass = | |||
| (javaClass.genericSuperclass as ParameterizedType).actualTypeArguments.filterIsInstance<Class<VB>>() | |||
| val inflate = vbClass[vbPosition].getDeclaredMethod("inflate", LayoutInflater::class.java) | |||
| return inflate.invoke(null, inflater) as VB | |||
| } | |||
| /** | |||
| * 扩展方法,获取ViewBinding的实例 主要用于Fragment、ListItem等 | |||
| * @receiver Any | |||
| * @param inflater LayoutInflater | |||
| * @param container ViewGroup? | |||
| * @param vbPosition Int | |||
| * @return VB | |||
| */ | |||
| @SuppressWarnings("unchecked") | |||
| inline fun <VB: ViewBinding> Any.initBinding(inflater: LayoutInflater, container:ViewGroup?,vbPosition:Int = 0):VB{ | |||
| val vbClass = (javaClass.genericSuperclass as ParameterizedType).actualTypeArguments.filterIsInstance<Class<VB>>() | |||
| val inflater = vbClass[vbPosition].getDeclaredMethod("inflate",LayoutInflater::class.java,ViewGroup::class.java,Boolean::class.java) | |||
| return inflater.invoke(null,inflater,container,false) as VB | |||
| } | |||
| @@ -0,0 +1,44 @@ | |||
| package com.suliang.common.util | |||
| import android.app.Activity | |||
| import java.util.* | |||
| /** | |||
| * Activity 栈管理 | |||
| */ | |||
| object ActivityStackManager { | |||
| @Volatile | |||
| private var activityStack: Stack<Activity> = Stack() | |||
| /** | |||
| * 入栈 | |||
| * @param activity Activity | |||
| */ | |||
| fun addActivity(activity: Activity) { | |||
| activityStack.add(activity) | |||
| } | |||
| /** | |||
| * 出栈 | |||
| * @param activity Activity | |||
| */ | |||
| fun removeActivity(activity: Activity) { | |||
| activityStack.remove(activity) | |||
| } | |||
| /** | |||
| * 结束指定类名的Activity | |||
| * @param cls Class<*> | |||
| */ | |||
| fun finishActivity(cls: Class<*>) { | |||
| run { | |||
| activityStack.forEach { activity -> | |||
| if (activity.javaClass == cls) { | |||
| activity.finish() | |||
| return@run | |||
| } | |||
| } | |||
| } | |||
| } | |||
| } | |||
| @@ -1,200 +0,0 @@ | |||
| package com.suliang.common.util | |||
| import java.io.File | |||
| /** | |||
| * author suliang | |||
| * create 2020/12/11 9:43 | |||
| * Describe: 常量类 | |||
| */ | |||
| object Constants { | |||
| const val PLATFORM = "android" //平台 | |||
| const val YOUTH_VERSION = 1 //青少版 | |||
| const val CHILDREN_VERSION = 2 //幼儿版 | |||
| // public static final String ENVIRONMENT_PRODUCTION = "production" ; //正式环境 | |||
| // public static final String ENVIRONMENT_DEVELOPMENT = "development"; //开发环境 | |||
| // public static final String ENVIRONMENT_TEST = "test"; //测试环境 | |||
| const val ACCOUNT = "account" | |||
| const val USER_INFO = "userinfo" | |||
| const val TOKEN = "token" | |||
| /** 默认发音 */ | |||
| const val DEFAULT_SOUND = "default_sound" | |||
| /** 更换fragment中的颜色 */ | |||
| const val ACTION_NOTIFY_FRAGMENT_SKIN = "notify_skin" | |||
| //项目subjectId | |||
| const val SUBJECT_ENGLISH: Long = 3 //英语 | |||
| const val SUBJECT_CHINESE: Long = 1 //语文 | |||
| //课程类型的coursepack --> categoryId | |||
| const val CATEGORY_ENGLISH_WORD: Long = 1 //英语: 单词速记 | |||
| const val CATEGORY_ENGLISH_SOUNDMARK: Long = 4 //英语: 音标 | |||
| const val CATEGORY_ENGLISH_SPOKEN: Long = 13 //英语: 口语 | |||
| const val CATEGORY_CHINESE_COMPOSITION: Long = 2 //语文: 作文 | |||
| const val CATEGORY_CHINESE_LITERACY: Long = 3 //语文: 识字 | |||
| const val CATEGORY_CHINESE_PINYIN: Long = 5 //语文: 拼音 | |||
| //项目的课程类型: course --> typeId | |||
| const val COURSE_TYPE_DISCERN = 1 //认读、口语 | |||
| const val COURSE_TYPE_VOICE = 2 //辨音 | |||
| const val COURSE_TYPE_SPELL = 3 //拼写 | |||
| const val COURSE_TYPE_POINTS = 4 //作文知识点 | |||
| const val COURSE_TYPE_LITERACY = 5 //识字 | |||
| const val COURSE_TYPE_SOUNDMARK = 6 //音标 | |||
| const val COURSE_TYPE_PINYIN = 7 //拼音 | |||
| const val COURSE_TYPE_SPOKEN = 8 //口语 | |||
| //作文课时类型 | |||
| const val COMPOSITION_TYPE_VIDEO = 1 //视频 | |||
| const val COMPOSITION_TYPE_KNOWLEDGE = 2 //知识点学习 | |||
| const val COMPOSITION_TYPE_EXAM = 3 //知识点测试 | |||
| const val COMPOSITION_TYPE_READING = 4 //课堂练习 | |||
| const val COMPOSITION_TYPE_TASK = 5 //课外练习 | |||
| //口语课时类型 | |||
| const val SPOKEN_LESSON_TYPE_WORD = 1 //口语词汇 | |||
| const val SPOKEN_LESSON_TYPE_SENTENCE = 2 //口语句型 | |||
| const val SPOKEN_LESSON_TYPE_DIALOGUE = 3 //口语对话 | |||
| //课程包过期信息状态值 | |||
| const val EXPIRY_NOMAL = 1 //正常态 | |||
| const val EXPIRY_WILL_OVER = 2 //快过期 小于39天 | |||
| const val EXPIRY_OVER = 3 //已过期 | |||
| //课程包内容是否下载状态值 | |||
| const val CONTENT_NOT_DOWN = 0 //未下载 | |||
| const val CONTENT_DOWNING = 1 //下载中 | |||
| const val CONTENT_NOMAL = 2 //正常态(已下载) | |||
| val FILE_ENGLISH = "english" + File.separator + "pack" //英语项目包 | |||
| val FILE_CHINESE = "chinese" + File.separator + "pack" //作文项目包 | |||
| //课程数据包解压后保存的名称 | |||
| const val DBFILENAME = "course_data.db" | |||
| const val FILE_VOICE = "voice" //音频地址 | |||
| const val VOICE_COMMON_KONGGE = "kongge.mp3" | |||
| const val VOICE_COMMON_MISTAKE = "mistake.mp3" | |||
| const val VOICE_COMMON_DI = "di.mp3" //叮咚 | |||
| const val FILE_UPLOAD_FAIL = "error" //上传失败地址 | |||
| const val FILE_IMG = "glide" //图片缓存地址 | |||
| /********发音默认type */ | |||
| const val SOUND_TYPE_US = 1 //美 | |||
| const val SOUND_TYPE_UK = 2 //英 | |||
| const val SOUND_TYPE_CN = 3 //中文 | |||
| const val TEST_QUEST_TYPE_FIELD = 1 //测试题选项类型 :字段名 | |||
| const val TEST_QUEST_TYPE_ID = 2 //测试题选项类型: 选项id | |||
| // 分组(1:普通测试(词汇测试,不做redis统计关联) 2:章节学前测试 3:章节学后测试 4:学前总测试 5:学后总测试 6:备忘录测试(不做redis统计关联);7:作文知识点测试,8:服务中心的课程测试) | |||
| const val TEST_TYPE_NORMAL = 1 //普通测试(词汇测试,不做redis统计关联) | |||
| const val TEST_TYPE_BEFORE = 2 //学前测试 | |||
| const val TEST_TYPE_AFTER = 3 //学后测试 | |||
| const val TEST_TYPE_BEFORE_TOTAL = 4 //学前总测试 | |||
| const val TEST_TYPE_AFTER_TOTAL = 5 //学后总测试 | |||
| const val TEST_TYPE_MEMO = 6 //备忘录测试 | |||
| const val TEST_TYPE_COMPOSITION = 7 //作文知识点测试 | |||
| const val TEST_TYPE_SERVICE_CENTER = 8 //服务中心的课程测试 | |||
| const val TEST_DB_DATA_WORD = 1 // data_word | |||
| const val TEST_DB_DATA_EXAM = 2 // data_exam | |||
| const val TEST_CORRECT = 1 //答题正确 | |||
| const val TEST_ERROR = -1 //答题错误 | |||
| const val TEST_UNANSWER = 0 //答题未答 | |||
| const val TEST_TO_NEXT_TIME_CORRECT = 500 //认读辨音 正确 0.5秒跳下一题 | |||
| const val TEST_TO_NEXT_TIME_ERROR = 2000 //认读辨音 答错 2秒 | |||
| const val TEST_TO_NEXT_TIME_UNANSWER = 2000 //认读辨音 未答 2秒 | |||
| const val TEST_TO_NEXT_TIME_SPELL = 1500 //辨音错误到下一题需要1.5秒 | |||
| const val TEST_WORD_COUNT_DOWN_TIME_DISCERN = 6000 //认读单个单词倒计时时间 6秒 | |||
| const val TEST_WORD_COUNT_DOWN_TIME_SPELL_SINGLE = 1600 //拼写单个单词字母的倒计时时间 | |||
| const val TEST_WORD_COUNT_DOWN_TOME_COMPOSITION = 15000 //作文测试倒计时时间 | |||
| const val SCORE_1 = 80 //小于score_1 悲伤 | |||
| const val SCORE_2 = 90 //大于等于score1 小于 score_2 加油 | |||
| const val SCORE_SPOKEN_DIALOGUE_1 = 60 //口语对话练习课时后测试通过标准 80以上优秀,中间良好 | |||
| const val TEST_COUNT_TOTAL = 25 //总测试 50题 | |||
| const val TEST_COUNT_NORAM = 20 //章节测试 25题 | |||
| const val TEST_COUNT_VOCABULARY = 100 //词汇量测试 | |||
| //测试的题目类型 | |||
| const val TEST_QUEST_TYPE_CHOICE = 1 //选择题 | |||
| const val TEST_QUEST_TYPE_GAP_FILLING = 2 //填空题 | |||
| const val TEST_QUEST_TYPE_JUDGE = 3 //判断题 | |||
| const val TEST_QUEST_TYPE_SPOKEN_DIALOGUE = 4 //口语对话测试 | |||
| //课时状态 | |||
| const val LESSON_STATE_NORMAL = 0 //普通状态 | |||
| // public static final int LESSON_STATE_SELECT = 1 ; //选中状态 | |||
| const val LESSON_STATE_LOCKED = 1 //锁定状态 | |||
| //答题左侧按钮状态 | |||
| const val ANSWER = 0 //答案 | |||
| const val CORRECT = 1 //正确 | |||
| const val NEXT = 2 //下一条 | |||
| //有效时间 : 18秒 | |||
| const val VALID_TIME: Long = 18000 | |||
| //最后一课时 虚拟下一课时标记(主要用于判断最后一课时学后测试是否有通过) | |||
| const val LAST_LESSON_NEXT_FLAG = "-1_-1" | |||
| //学习 | |||
| const val LEARN_FLAG = 1 | |||
| //复习 | |||
| const val REVIEW_FLAG = 2 | |||
| //拼写中 | |||
| const val STATE_SPELLING = 1 | |||
| //纠错中 | |||
| const val STATE_MODIFYING = 2 | |||
| //不可操作状态 | |||
| const val STATE_UNENABLE = 3 | |||
| //拼写结果: 全对 | |||
| const val RESULT_ALL_RIGHT = 1 | |||
| //拼写结果:错误;可容错 | |||
| const val RESULT_ERROR_CAN_MODIFY = 2 | |||
| //拼写结果: 错误,无容错 | |||
| const val RESULT_ERROR = 3 | |||
| //拼写修改完成 | |||
| const val RESULT_MODIFY_OVER = 4 | |||
| // 0: 自己按顺序加载状态页 1复习页 2学前总测页 3 目录页 4学后总测未测 5、学后总测未通过 6、学后总测已通过 | |||
| const val PAGE_LOADING_NORAML = 0 | |||
| const val PAGE_LOADING_REVIEW = 1 | |||
| const val PAGE_LOADING_BEFORE = 2 | |||
| const val PAGE_LOADING_CATALOG = 3 | |||
| const val PAGE_LOADING_AFTER_NOT = 4 | |||
| const val PAGE_LOADING_AFTER_NO_PASS = 5 | |||
| const val PAGE_LOADING_AFTER_PASS = 6 | |||
| //收藏类型 | |||
| const val COMPOSITON_COLLECT_VIDEO_BLACK_BOOK = 1 //收藏类型:视频版本 | |||
| const val COMPOSITON_COLLECT_READING = 2 //阅读材料 | |||
| //模块联通通知类型 | |||
| const val NOTIFY_ENGLISH_REVIEW = 1 //英语有复习 | |||
| const val NOTIFY_ENGLISH_ERROR = 2 //英语学习有错误 | |||
| const val NOTIFY_COMPOSITION_REVIEW = 3 //作文有复习 | |||
| const val NOTIFY_COMPOSITION_ERROR = 4 //作文学习有错误 | |||
| const val NOTIFY_LEARN_RECORD_CHANGE = 5 //学习记录有变化 | |||
| //游戏 | |||
| const val GAME_GAPFILLING = 1 //填空 | |||
| const val GAME_CHOOSE = 2 //消消乐 | |||
| const val GAME_TRANSLATE = 3 //翻译排序 | |||
| //口语自动播放模式 | |||
| const val SPOKEN_AUTO_PLAY_MODEL = 1 //自动播放模式 | |||
| const val SPOKEN_AUTO_FLOWER_MODEL = 2 //跟读模式 | |||
| //收藏本: 句子type 2 | |||
| const val COLLECT_TYPE_SENTENCE: Long = 2 | |||
| } | |||
| @@ -5,6 +5,8 @@ dependencyResolutionManagement { | |||
| google() | |||
| mavenCentral() | |||
| jcenter() // Warning: this repository is going to shut down soon | |||
| maven { url 'https://jitpack.io' } | |||
| } | |||
| } | |||
| rootProject.name = "XklLocal" | |||