@@ -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" |