| <entry key="..\:/xuekaole/XKLLocal/app/src/main/res/layout/dictionary_floating_layout.xml" value="0.5" /> | <entry key="..\:/xuekaole/XKLLocal/app/src/main/res/layout/dictionary_floating_layout.xml" value="0.5" /> | ||||
| <entry key="..\:/xuekaole/XKLLocal/app/src/main/res/layout/fragment_course_pack.xml" value="0.3338541666666667" /> | <entry key="..\:/xuekaole/XKLLocal/app/src/main/res/layout/fragment_course_pack.xml" value="0.3338541666666667" /> | ||||
| <entry key="..\:/xuekaole/XKLLocal/app/src/main/res/layout/fragment_learn_center.xml" value="0.3338541666666667" /> | <entry key="..\:/xuekaole/XKLLocal/app/src/main/res/layout/fragment_learn_center.xml" value="0.3338541666666667" /> | ||||
| <entry key="..\:/xuekaole/XKLLocal/app/src/main/res/layout/fragment_statistics_time_top.xml" value="0.23385416666666667" /> | |||||
| <entry key="..\:/xuekaole/XKLLocal/app/src/main/res/layout/item_statics_for_time.xml" value="0.24791666666666667" /> | |||||
| <entry key="..\:/xuekaole/XKLLocal/lib/common/src/main/res/drawable/ic_search.xml" value="0.2212962962962963" /> | <entry key="..\:/xuekaole/XKLLocal/lib/common/src/main/res/drawable/ic_search.xml" value="0.2212962962962963" /> | ||||
| </map> | </map> | ||||
| </option> | </option> |
| package com.xkl.cdl.data.repository | package com.xkl.cdl.data.repository | ||||
| import android.net.IpPrefix | |||||
| import android.util.LruCache | import android.util.LruCache | ||||
| import androidx.lifecycle.MutableLiveData | |||||
| import com.suliang.common.AppConfig | import com.suliang.common.AppConfig | ||||
| import com.suliang.common.eventbus.SingleLiveData | |||||
| import com.suliang.common.extension.diskIo2Main | import com.suliang.common.extension.diskIo2Main | ||||
| import com.suliang.common.util.file.FileUtil | import com.suliang.common.util.file.FileUtil | ||||
| import com.xkl.cdl.data.AppConstants | import com.xkl.cdl.data.AppConstants | ||||
| } | } | ||||
| /** 通知查到的录音 */ | /** 通知查到的录音 */ | ||||
| private lateinit var audioLiveData : MutableLiveData<String?> | |||||
| private lateinit var audioLiveData : SingleLiveData<String?> | |||||
| fun initAudioLiveData() : MutableLiveData<String?> { | |||||
| audioLiveData = MutableLiveData<String?>() | |||||
| fun initAudioLiveData() : SingleLiveData<String?> { | |||||
| if (!this::audioLiveData.isInitialized){ | |||||
| audioLiveData = SingleLiveData<String?>() | |||||
| } | |||||
| return audioLiveData | return audioLiveData | ||||
| } | } | ||||
| import android.app.Activity | import android.app.Activity | ||||
| import android.app.Application | import android.app.Application | ||||
| import android.os.Bundle | import android.os.Bundle | ||||
| import com.suliang.common.base.LibApplication | |||||
| import com.suliang.common.util.ActivityStackManager | import com.suliang.common.util.ActivityStackManager | ||||
| import com.suliang.common.util.LogUtil | import com.suliang.common.util.LogUtil | ||||
| import com.suliang.common.util.file.FileUtil | import com.suliang.common.util.file.FileUtil | ||||
| * create 2022/3/14 11:27 | * create 2022/3/14 11:27 | ||||
| * Describe: | * Describe: | ||||
| */ | */ | ||||
| class XKLApplication : Application() { | |||||
| class XKLApplication : LibApplication() { | |||||
| companion object{ | companion object{ | ||||
| val mobileCache:MobileCache by lazy { | val mobileCache:MobileCache by lazy { | ||||
| val file : String = File(FileUtil.getSaveDirFile("db"), "mydb").absolutePath | val file : String = File(FileUtil.getSaveDirFile("db"), "mydb").absolutePath | ||||
| Mobile_cache.new_(file) | Mobile_cache.new_(file) | ||||
| } | } | ||||
| private var instance : XKLApplication by Delegates.notNull() | |||||
| fun instance() = instance | |||||
| // private var instance : XKLApplication by Delegates.notNull() | |||||
| fun instance() = LibApplication.instance() | |||||
| } | } | ||||
| override fun onCreate() { | override fun onCreate() { | ||||
| super.onCreate() | super.onCreate() | ||||
| instance = this | |||||
| // instance = this | |||||
| SQLiteDatabase.loadLibs(this) | SQLiteDatabase.loadLibs(this) | ||||
| LogUtil.e(UUID.randomUUID().toString().replace("-","")) | |||||
| // LogUtil.e(UUID.randomUUID().toString().replace("-","")) | |||||
| //初始MMKV存储 | //初始MMKV存储 | ||||
| val rootDir = MMKV.initialize(this) | |||||
| LogUtil.e(rootDir) | |||||
| setRxJavaErrorHandler() | |||||
| // val rootDir = MMKV.initialize(this) | |||||
| // LogUtil.e(rootDir) | |||||
| // setRxJavaErrorHandler() | |||||
| // HookMobileCache().hook() | // HookMobileCache().hook() | ||||
| // registerActivityLifecycleCallbacks(lifecycleCallback) | // registerActivityLifecycleCallbacks(lifecycleCallback) | ||||
| } | } | ||||
| /*** | |||||
| /* *//*** | |||||
| * 避免 调用多次onError。正常来说第一次onError会走正常的Observer处理,其他会走ErrorHandler。通过此方法捕捉多次的error | * 避免 调用多次onError。正常来说第一次onError会走正常的Observer处理,其他会走ErrorHandler。通过此方法捕捉多次的error | ||||
| */ | |||||
| *//* | |||||
| private fun setRxJavaErrorHandler(){ | private fun setRxJavaErrorHandler(){ | ||||
| RxJavaPlugins.setErrorHandler(Consumer { e -> | RxJavaPlugins.setErrorHandler(Consumer { e -> | ||||
| e.printStackTrace() | e.printStackTrace() | ||||
| }) | }) | ||||
| } | } | ||||
| */ | |||||
| private object lifecycleCallback : Application.ActivityLifecycleCallbacks { | private object lifecycleCallback : Application.ActivityLifecycleCallbacks { | ||||
| private var count = 0 | private var count = 0 |
| //监听时间选项变化 | //监听时间选项变化 | ||||
| vm.timeStatisticsPositionLiveData.observe(this) { position -> | vm.timeStatisticsPositionLiveData.observe(this) { position -> | ||||
| if (!vm.isInitStatisticsResponse()) { | |||||
| vm.getStatistics().observe(this) { | |||||
| if (it) { | |||||
| (binding.rvTime.adapter as AdapterStaticsTime).setData(vm.timeValuesList[position]) | |||||
| } | |||||
| } | |||||
| } else { | |||||
| // if (!vm.isInitStatisticsResponse()) { | |||||
| // vm.getStatistics().observe(this) { | |||||
| // if (it) { | |||||
| // (binding.rvTime.adapter as AdapterStaticsTime).setData(vm.timeValuesList[position]) | |||||
| // } | |||||
| // } | |||||
| // } else { | |||||
| (binding.rvTime.adapter as AdapterStaticsTime).setData(vm.timeValuesList[position]) | (binding.rvTime.adapter as AdapterStaticsTime).setData(vm.timeValuesList[position]) | ||||
| } | |||||
| // } | |||||
| } | } | ||||
| } | } | ||||
| override fun loadData() { | override fun loadData() { | ||||
| //设置选中加载数据 | //设置选中加载数据 | ||||
| vm.timeStatisticsPositionLiveData.value = binding.tabLayoutTime.selectedTabPosition | |||||
| // vm.timeStatisticsPositionLiveData.value = binding.tabLayoutTime.selectedTabPosition | |||||
| vm.getStatistics().observe(this) { | |||||
| if (it) { | |||||
| (binding.rvTime.adapter as AdapterStaticsTime).setData(vm.timeValuesList[binding.tabLayoutTime.selectedTabPosition]) | |||||
| } | |||||
| } | |||||
| } | } | ||||
| private fun initTabLayout() { | private fun initTabLayout() { |
| protected fun initTimeStaticItem(statistics : AppApi.Statistics) : MutableList<TimeStatisticItem> { | protected fun initTimeStaticItem(statistics : AppApi.Statistics) : MutableList<TimeStatisticItem> { | ||||
| val result = mutableListOf<TimeStatisticItem>() | val result = mutableListOf<TimeStatisticItem>() | ||||
| //有效学习时长 | |||||
| result.add(initValideTime(statistics)) //添加有效学习时常 | |||||
| result.add(initEfficiency(statistics)) //效率 | |||||
| result.add(initCourseCount(statistics)) //课程 | |||||
| result.add(initLearnProgress(statistics)) //已学进度 | |||||
| /* //有效学习时长 | |||||
| val timeStaticItem_1 = TimeStatisticItem().apply { | val timeStaticItem_1 = TimeStatisticItem().apply { | ||||
| name = "有效学习时长" | name = "有效学习时长" | ||||
| backGround = R.drawable.shape_rounder_4_red_a5 | backGround = R.drawable.shape_rounder_4_red_a5 | ||||
| } | } | ||||
| } | } | ||||
| }else{ | }else{ | ||||
| timeStaticItem_1.time = "0" | |||||
| timeStaticItem_1.unit = "" | |||||
| timeStaticItem_1.time = "" | |||||
| timeStaticItem_1.unit = "不足1分钟" | |||||
| } | } | ||||
| initIncr(timeStaticItem_1,statistics.sdIncr.toDouble()) | |||||
| //增量不为0 | //增量不为0 | ||||
| if (statistics.sdIncr != 0L ){ | if (statistics.sdIncr != 0L ){ | ||||
| val hour_1 = statistics.sdIncr / 3600000.0 | val hour_1 = statistics.sdIncr / 3600000.0 | ||||
| //小于1分钟 秒数 | //小于1分钟 秒数 | ||||
| else -> timeStaticItem_1.incr = "${sencond}秒" | else -> timeStaticItem_1.incr = "${sencond}秒" | ||||
| } | } | ||||
| if (statistics.sdIncr > 0){ | |||||
| timeStaticItem_1.incr = "+${timeStaticItem_1.incr}" | |||||
| } | |||||
| }else{ | |||||
| timeStaticItem_1.incr = "" | |||||
| } | } | ||||
| initIncr(timeStaticItem_1,statistics.sdIncr.toDouble()) | |||||
| result.add(timeStaticItem_1) | |||||
| result.add(timeStaticItem_1)*/ | |||||
| //综合学习效率 | |||||
| /* //综合学习效率 | |||||
| val timeStaticItem_2 = TimeStatisticItem().apply { | val timeStaticItem_2 = TimeStatisticItem().apply { | ||||
| backGround = R.drawable.shape_rounder_4_theme_a5 | backGround = R.drawable.shape_rounder_4_theme_a5 | ||||
| name = "综合学习效率" | name = "综合学习效率" | ||||
| time = initShow(statistics.ts) | time = initShow(statistics.ts) | ||||
| initIncr(this,statistics.tsIncr) | initIncr(this,statistics.tsIncr) | ||||
| } | } | ||||
| result.add(timeStaticItem_4) | |||||
| result.add(timeStaticItem_4)*/ | |||||
| return result | return result | ||||
| } | } | ||||
| private fun initValideTime(statistics : AppApi.Statistics) : TimeStatisticItem { | |||||
| val result = TimeStatisticItem().apply { | |||||
| name = "有效学习时长" | |||||
| backGround = R.drawable.shape_rounder_4_red_a5 | |||||
| //时长显示 | |||||
| if (statistics.sd != 0L) { | |||||
| val hour = statistics.sd / 3600000.0 | |||||
| val minute = statistics.sd / 60000.0 | |||||
| when { | |||||
| //大于1小时 | |||||
| hour > 1 -> { | |||||
| time =initShow(hour) | |||||
| unit = "小时" | |||||
| } | |||||
| //大于1分钟 | |||||
| minute > 1 -> { | |||||
| //取整和保留一位小数的值相同,则使用取整的值显示,否则使用保留小数的值显示 | |||||
| time =initShow(minute) | |||||
| unit = "分钟" | |||||
| } | |||||
| //小于1分钟 | |||||
| else -> { | |||||
| time = "" | |||||
| unit = "不足1分钟" | |||||
| } | |||||
| } | |||||
| }else{ | |||||
| time = "" | |||||
| unit = "不足1分钟" | |||||
| } | |||||
| //增量处理 | |||||
| incr = if (statistics.sdIncr != 0L ) { | |||||
| val hour_1 = statistics.sdIncr / 3600000.0 | |||||
| val minute_1 = statistics.sdIncr / 60000.0 | |||||
| val sencond = statistics.sdIncr / 1000 | |||||
| val temp : String = when { | |||||
| //大于1小时 | |||||
| abs(hour_1) > 1 -> if(statistics.sdIncr > 0) "${initShow(hour_1)}小时" else "-${initShow(abs(hour_1))}小时" | |||||
| //大于1分钟 | |||||
| abs(minute_1) > 1 ->if(statistics.sdIncr > 0) "${initShow(minute_1)}分钟" else "-${initShow(abs(minute_1))}分钟" | |||||
| //小于1分钟 秒数 | |||||
| else -> "${sencond}秒" | |||||
| } | |||||
| if (statistics.sdIncr > 0){ | |||||
| "+${temp}" | |||||
| } else temp | |||||
| } else "" | |||||
| //增量颜色和箭头处理 | |||||
| initIncr(this,statistics.sdIncr.toDouble()) | |||||
| } | |||||
| return result | |||||
| } | |||||
| private fun initEfficiency(statistics : AppApi.Statistics) : TimeStatisticItem { | |||||
| val result = TimeStatisticItem().apply { | |||||
| backGround = R.drawable.shape_rounder_4_theme_a5 | |||||
| name = "综合学习效率" | |||||
| unit = "%" | |||||
| time = initShow(statistics.se) | |||||
| initIncr(this,statistics.seIncr) | |||||
| //增量 | |||||
| incr = when { | |||||
| statistics.seIncr == 0.0 -> "" | |||||
| statistics.seIncr > 0 -> "+${initShow(statistics.seIncr)}$unit" | |||||
| else -> "${initShow(statistics.seIncr)}$unit" | |||||
| } | |||||
| } | |||||
| return result | |||||
| } | |||||
| private fun initCourseCount(statistics : AppApi.Statistics) : TimeStatisticItem { | |||||
| val result = TimeStatisticItem().apply { | |||||
| backGround = R.drawable.shape_rounder_4_green_a5 | |||||
| name = "已学课程" | |||||
| unit = "/${CourseManager.getTotalCourseSize()}个" | |||||
| time = "${statistics.sc}" | |||||
| initIncr(this,statistics.scIncr.toDouble()) | |||||
| //增量 | |||||
| incr = when { | |||||
| statistics.scIncr == 0L -> "" | |||||
| statistics.scIncr > 0 -> "+${statistics.scIncr}" | |||||
| else -> "${statistics.scIncr}" | |||||
| } | |||||
| } | |||||
| return result | |||||
| } | |||||
| private fun initLearnProgress(statistics : AppApi.Statistics) : TimeStatisticItem { | |||||
| val result = TimeStatisticItem().apply { | |||||
| backGround = R.drawable.shape_rounder_4_purple_a5 | |||||
| name = "已学进度" | |||||
| unit = "%" | |||||
| time = initShow(statistics.ts) | |||||
| initIncr(this,statistics.tsIncr) | |||||
| //增量 | |||||
| incr = when { | |||||
| statistics.tsIncr == 0.0 -> "" | |||||
| statistics.tsIncr > 0 -> "+${initShow(statistics.tsIncr)}$unit" | |||||
| else -> "${initShow(statistics.tsIncr)}$unit" | |||||
| } | |||||
| } | |||||
| return result | |||||
| } | |||||
| /** 格式化数据,决定显示小数还是不显示 */ | /** 格式化数据,决定显示小数还是不显示 */ | ||||
| private fun initShow(value:Double):String{ | private fun initShow(value:Double):String{ | ||||
| val temp = abs(value) | |||||
| //保留一位小数 向下取舍 | //保留一位小数 向下取舍 | ||||
| val formatFloor = NumberUtils.formatFloor(value, "0.0") | |||||
| val formatFloor = NumberUtils.formatFloor(temp, "0.0") | |||||
| val toDouble = formatFloor.toDouble() | val toDouble = formatFloor.toDouble() | ||||
| //取整 | //取整 | ||||
| val formatFloor_1 = NumberUtils.formatFloor(value, "0") | |||||
| val toDouble_1 = formatFloor.toDouble() | |||||
| val formatFloor_1 = NumberUtils.formatFloor(temp, "0") | |||||
| val toDouble_1 = formatFloor_1.toDouble() | |||||
| //取整和保留一位小数的值相同,则使用取整的值显示,否则使用保留小数的值显示 | //取整和保留一位小数的值相同,则使用取整的值显示,否则使用保留小数的值显示 | ||||
| return when (toDouble_1) { | |||||
| return (if (value < 0 ) "-" else "") + when (toDouble_1) { | |||||
| toDouble -> formatFloor_1 | toDouble -> formatFloor_1 | ||||
| else -> formatFloor | else -> formatFloor | ||||
| } | } | ||||
| private fun initIncr(timeStaticItem_1 : TimeStatisticItem, sdIncr : Double) { | private fun initIncr(timeStaticItem_1 : TimeStatisticItem, sdIncr : Double) { | ||||
| timeStaticItem_1.run { | timeStaticItem_1.run { | ||||
| when{ | when{ | ||||
| sdIncr == 0.0 -> { | |||||
| incr = "" | |||||
| imgDrawable = R.drawable.ic_keep | |||||
| } | |||||
| sdIncr == 0.0 -> imgDrawable = R.drawable.ic_keep | |||||
| sdIncr > 0 -> { | sdIncr > 0 -> { | ||||
| imgDrawable = R.drawable.ic_rise | imgDrawable = R.drawable.ic_rise | ||||
| incrTextColor = R.color.green_1 | incrTextColor = R.color.green_1 | ||||
| incr = "+$incr" | |||||
| } | } | ||||
| else -> { | else -> { | ||||
| imgDrawable = R.drawable.ic_decline | imgDrawable = R.drawable.ic_decline |
| import com.xkl.cdl.module.m_my.MyFragment | import com.xkl.cdl.module.m_my.MyFragment | ||||
| import com.xkl.cdl.module.m_service_center.ServiceCenterFragment | import com.xkl.cdl.module.m_service_center.ServiceCenterFragment | ||||
| import com.xkl.cdl.module.m_statics.StaticsFragment | import com.xkl.cdl.module.m_statics.StaticsFragment | ||||
| import com.xkl.cdl.module.splash.SplashActivity | |||||
| import com.zackratos.ultimatebarx.ultimatebarx.java.UltimateBarX | import com.zackratos.ultimatebarx.ultimatebarx.java.UltimateBarX | ||||
| import com.zackratos.ultimatebarx.ultimatebarx.statusBarOnly | import com.zackratos.ultimatebarx.ultimatebarx.statusBarOnly | ||||
| override fun initViewModel(): MainActivityViewModel { | override fun initViewModel(): MainActivityViewModel { | ||||
| return ViewModelProvider(this)[MainActivityViewModel::class.java] | return ViewModelProvider(this)[MainActivityViewModel::class.java] | ||||
| } | } | ||||
| override fun protectApp() { | |||||
| startActivity(SplashActivity::class.java) | |||||
| finish() | |||||
| } | |||||
| override fun initActivity(savedInstanceState: Bundle?) { | override fun initActivity(savedInstanceState: Bundle?) { | ||||
| //点击事件 | //点击事件 |
| @SuppressLint("CustomSplashScreen") | @SuppressLint("CustomSplashScreen") | ||||
| class SplashActivity : BaseActivity<ActivitySplashBinding>() { | class SplashActivity : BaseActivity<ActivitySplashBinding>() { | ||||
| override fun onCreate(savedInstanceState : Bundle?) { | |||||
| override fun onCreateOwn(savedInstanceState : Bundle?) { | |||||
| if (!isTaskRoot) { | if (!isTaskRoot) { | ||||
| finish() | finish() | ||||
| return | return | ||||
| } | } | ||||
| super.onCreate(savedInstanceState) | |||||
| XKLApplication.instance().isLaunch = true | |||||
| super.onCreateOwn(savedInstanceState) | |||||
| } | } | ||||
| override fun initActivity(savedInstanceState : Bundle?) { | override fun initActivity(savedInstanceState : Bundle?) { |
| package com.suliang.common.base | |||||
| import android.app.Application | |||||
| import android.database.sqlite.SQLiteDatabase | |||||
| import com.suliang.common.util.LogUtil | |||||
| import com.tencent.mmkv.MMKV | |||||
| import io.reactivex.rxjava3.exceptions.UndeliverableException | |||||
| import io.reactivex.rxjava3.functions.Consumer | |||||
| import io.reactivex.rxjava3.plugins.RxJavaPlugins | |||||
| import java.io.IOException | |||||
| import java.util.* | |||||
| import kotlin.properties.Delegates | |||||
| /** | |||||
| * @Author: suliang | |||||
| * @create: 2022/8/23 11:07 | |||||
| * @Description: | |||||
| */ | |||||
| open class LibApplication : Application(){ | |||||
| //是否启动标记,用于避免应用重启时的问题 | |||||
| var isLaunch = false | |||||
| companion object { | |||||
| protected var instance : LibApplication by Delegates.notNull() | |||||
| @JvmStatic | |||||
| fun instance() = instance | |||||
| } | |||||
| override fun onCreate() { | |||||
| super.onCreate() | |||||
| instance = this | |||||
| //初始MMKV存储 | |||||
| val rootDir = MMKV.initialize(this) | |||||
| LogUtil.e(rootDir) | |||||
| setRxJavaErrorHandler() | |||||
| // HookMobileCache().hook() | |||||
| // registerActivityLifecycleCallbacks(lifecycleCallback) | |||||
| } | |||||
| /*** | |||||
| * 避免 调用多次onError。正常来说第一次onError会走正常的Observer处理,其他会走ErrorHandler。通过此方法捕捉多次的error | |||||
| */ | |||||
| private fun setRxJavaErrorHandler(){ | |||||
| RxJavaPlugins.setErrorHandler(Consumer { e -> | |||||
| e.printStackTrace() | |||||
| LogUtil.e( "RxJavaErrorHandler --> \n $e") | |||||
| if (e is UndeliverableException) { | |||||
| return@Consumer | |||||
| } else if (e is IOException) { | |||||
| // fine, irrelevant network problem or API that throws on cancellation | |||||
| return@Consumer | |||||
| } else if (e is InterruptedException) { | |||||
| // fine, some blocking code was interrupted by a dispose call | |||||
| return@Consumer | |||||
| } else if (e is NullPointerException || e is IllegalArgumentException) { | |||||
| // that's likely a bug in the application | |||||
| Thread.currentThread().uncaughtExceptionHandler.uncaughtException(Thread.currentThread(), e) | |||||
| return@Consumer | |||||
| } else if (e is IllegalStateException) { | |||||
| // that's a bug in RxJava or in a custom operator | |||||
| Thread.currentThread().uncaughtExceptionHandler.uncaughtException(Thread.currentThread(), e) | |||||
| return@Consumer | |||||
| } | |||||
| LogUtil.e( "RxJavaErrorHandler --> unknown exception = \n $e") | |||||
| }) | |||||
| } | |||||
| } |
| package com.suliang.common.base.activity | package com.suliang.common.base.activity | ||||
| import android.content.ComponentName | |||||
| import android.content.Intent | import android.content.Intent | ||||
| import android.graphics.Color | import android.graphics.Color | ||||
| import android.os.Bundle | import android.os.Bundle | ||||
| import android.widget.Toast | import android.widget.Toast | ||||
| import androidx.annotation.StringRes | import androidx.annotation.StringRes | ||||
| import com.suliang.common.base.LibApplication | |||||
| import com.suliang.common.base.LoadingDialog | import com.suliang.common.base.LoadingDialog | ||||
| import com.suliang.common.base.ViewBehavior | import com.suliang.common.base.ViewBehavior | ||||
| import com.suliang.common.util.ActivityStackManager | import com.suliang.common.util.ActivityStackManager | ||||
| override fun onCreate(savedInstanceState : Bundle?) { | override fun onCreate(savedInstanceState : Bundle?) { | ||||
| super.onCreate(savedInstanceState) | super.onCreate(savedInstanceState) | ||||
| onCreateOwn(savedInstanceState) | |||||
| } | |||||
| protected open fun onCreateOwn(savedInstanceState : Bundle?) { | |||||
| if (!LibApplication.instance().isLaunch) { | |||||
| protectApp() | |||||
| return | |||||
| } | |||||
| //入栈 | //入栈 | ||||
| ActivityStackManager.addActivity(this) | ActivityStackManager.addActivity(this) | ||||
| initFirst() | initFirst() | ||||
| loadData() | loadData() | ||||
| } | } | ||||
| /** | |||||
| * 当Application启动的时候, LibApplication的isLaunch为false | |||||
| * 在SplashActivity启动的时候改变该值为true | |||||
| * 当为true时,app回到前台,即 应用没有重启 | |||||
| * 当为false时,即应用重启了 | |||||
| */ | |||||
| protected open fun protectApp() { | |||||
| startActivity(Intent().apply { | |||||
| component = ComponentName(applicationContext, "com.xkl.cdl.module.main.MainActivity") | |||||
| addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP) //清空栈里MainActivity之上的所有Activity | |||||
| }) | |||||
| finish() | |||||
| } | |||||
| /*** | /*** | ||||
| * 实例化binding, | * 实例化binding, | ||||
| */ | */ | ||||
| val showTime = if (event.showLong) Toast.LENGTH_LONG else Toast.LENGTH_LONG | val showTime = if (event.showLong) Toast.LENGTH_LONG else Toast.LENGTH_LONG | ||||
| event.content?.let { | event.content?.let { | ||||
| Toast.makeText(this, it, showTime).show() | Toast.makeText(this, it, showTime).show() | ||||
| } ?: let { | |||||
| Toast.makeText(this, event.contentResId!!, showTime).show() | |||||
| } | } | ||||
| ?: let { | |||||
| Toast.makeText(this, event.contentResId!!, showTime).show() | |||||
| } | |||||
| } | } | ||||
| protected fun showToast(text : String, showLong : Boolean = false) { | protected fun showToast(text : String, showLong : Boolean = false) { | ||||
| if (findFragment is LoadingDialog) { | if (findFragment is LoadingDialog) { | ||||
| findFragment.dialog?.show() | findFragment.dialog?.show() | ||||
| } | } | ||||
| } ?: let { | |||||
| val loadingDialog = LoadingDialog.newInstance("") | |||||
| loadingDialog.show(supportFragmentManager, "loading") | |||||
| } | } | ||||
| ?: let { | |||||
| val loadingDialog = LoadingDialog.newInstance("") | |||||
| loadingDialog.show(supportFragmentManager, "loading") | |||||
| } | |||||
| } else { //关闭 | } else { //关闭 | ||||
| findFragment?.let { | findFragment?.let { | ||||
| if (it is LoadingDialog) { | if (it is LoadingDialog) { |
| if (isSticky){ | if (isSticky){ | ||||
| bus[key] = MutableLiveData() | bus[key] = MutableLiveData() | ||||
| }else{ | }else{ | ||||
| bus[key] = NonStickyMutableLivedata() | |||||
| bus[key] = SingleLiveData() | |||||
| } | } | ||||
| } | } | ||||
| return bus[key] as MutableLiveData<T> | return bus[key] as MutableLiveData<T> |
| package com.suliang.common.eventbus | |||||
| import androidx.lifecycle.LifecycleOwner | |||||
| import androidx.lifecycle.LiveData | |||||
| import androidx.lifecycle.MutableLiveData | |||||
| import androidx.lifecycle.Observer | |||||
| import java.lang.Exception | |||||
| import java.lang.NullPointerException | |||||
| import java.lang.reflect.Method | |||||
| /** | |||||
| * author suliang | |||||
| * create 2022/3/15 10:51 | |||||
| * Describe: 非粘性LiveData ,需要先设置监听再发送数据,即后注册的监听收不到以前的监听 | |||||
| * 事件总线的LiveData 非粘性事件传false(刚注册时如果有事件则不发送) 粘性事件传true | |||||
| * @param isSticky false非粘性事件 true粘性事件 | |||||
| */ | |||||
| internal class NonStickyMutableLivedata<T> : MutableLiveData<T>() { | |||||
| // override fun observe(owner : LifecycleOwner, observer : Observer<in T>) { | |||||
| // super.observe(owner, ObserverWrapper<T>(observer)) | |||||
| // } | |||||
| // | |||||
| // class ObserverWrapper<T>(var observer:Observer<in T>) : Observer<T> { | |||||
| // var isSticky = false | |||||
| // override fun onChanged(t : T) { | |||||
| // if (isSticky){ | |||||
| // observer.onChanged(t) | |||||
| // }else{ | |||||
| // isSticky = true | |||||
| // } | |||||
| // } | |||||
| // } | |||||
| override fun observe(owner: LifecycleOwner, observer: Observer<in T>) { | |||||
| super.observe(owner, observer) | |||||
| hook(observer) | |||||
| } | |||||
| override fun removeObserver(observer : Observer<in T>) { | |||||
| super.removeObserver(observer) | |||||
| } | |||||
| private fun hook(observer : Observer<in T>) = try { | |||||
| //得到 mLastVersion | |||||
| //获取到LiveData的类中的mObserver对象 | |||||
| // SafeIterableMap<Observer<? super T> , ObserverWrapper> mObservers | |||||
| val liveDataClass = LiveData::class.java | |||||
| val declaredField = liveDataClass.getDeclaredField("mObservers") | |||||
| declaredField.isAccessible = true | |||||
| //获取到这个成员变量的对象 | |||||
| val mObserVersObject = declaredField.get(this) | |||||
| //得到map对应的class对象 | |||||
| val mObserversClass = mObserVersObject.javaClass | |||||
| //获取到mObservers对象的get方法 | |||||
| val get : Method = mObserversClass.getDeclaredMethod("get", Any::class.java) | |||||
| get.isAccessible = true | |||||
| //执行get方法,获取到对象 | |||||
| val invokeEntry = get.invoke(mObserVersObject, observer) | |||||
| //定义一个空的对象 | |||||
| val observerWrapper = if (invokeEntry is Map.Entry<*, *>) { | |||||
| invokeEntry.value | |||||
| } else throw NullPointerException("observerWrapper is null") | |||||
| //得到observerWrapper的对象,编译擦除问题会引起多态冲突,所以用getSupperClass | |||||
| //getClass 返回对应的当前正在运行是的类所对应的 | |||||
| val mLastVersion = observerWrapper!!::class.java.superclass.getDeclaredField("mLastVersion") | |||||
| mLastVersion.isAccessible = true | |||||
| //得到mVersion | |||||
| val mVersion = liveDataClass.getDeclaredField("mVersion") | |||||
| mVersion.isAccessible = true | |||||
| //把mVersion数据填入到mLastVersion中 | |||||
| val mVersionValue = mVersion.get(this) | |||||
| mLastVersion.set(observerWrapper, mVersionValue) | |||||
| } catch (e : Exception) { | |||||
| e.printStackTrace() | |||||
| } | |||||
| } |
| package com.suliang.common.eventbus | |||||
| import androidx.lifecycle.LifecycleOwner | |||||
| import androidx.lifecycle.LiveData | |||||
| import androidx.lifecycle.MutableLiveData | |||||
| import androidx.lifecycle.Observer | |||||
| import java.lang.Exception | |||||
| import java.lang.NullPointerException | |||||
| import java.lang.reflect.Method | |||||
| import java.util.concurrent.atomic.AtomicBoolean | |||||
| /** | |||||
| * author suliang | |||||
| * create 2022/3/15 10:51 | |||||
| * Describe: https://blog.csdn.net/bzb123321/article/details/98210342 | |||||
| */ | |||||
| class SingleLiveData<T> : MutableLiveData<T>() { | |||||
| /*非粘性LiveData ,需要先设置监听再发送数据,即后注册的监听收不到以前的监听 | |||||
| * 事件总线的LiveData 非粘性事件传false(刚注册时如果有事件则不发送) 粘性事件传true | |||||
| * @param isSticky false非粘性事件 true粘性事件*/ | |||||
| // override fun observe(owner : LifecycleOwner, observer : Observer<in T>) { | |||||
| // super.observe(owner, ObserverWrapper<T>(observer)) | |||||
| // } | |||||
| // | |||||
| // class ObserverWrapper<T>(var observer:Observer<in T>) : Observer<T> { | |||||
| // var isSticky = false | |||||
| // override fun onChanged(t : T) { | |||||
| // if (isSticky){ | |||||
| // observer.onChanged(t) | |||||
| // }else{ | |||||
| // isSticky = true | |||||
| // } | |||||
| // } | |||||
| // } | |||||
| companion object{ | |||||
| private val mPending : AtomicBoolean = AtomicBoolean(false) | |||||
| } | |||||
| override fun observe(owner: LifecycleOwner, observer: Observer<in T>) { | |||||
| super.observe(owner, Observer { | |||||
| if (mPending.compareAndSet(true,false)){ | |||||
| observer.onChanged(it) | |||||
| } | |||||
| }) | |||||
| // hook(observer) | |||||
| } | |||||
| override fun setValue(value : T?) { | |||||
| mPending.set(true) | |||||
| super.setValue(value) | |||||
| } | |||||
| public fun call(){ | |||||
| setValue(null) | |||||
| } | |||||
| // override fun removeObserver(observer : Observer<in T>) { | |||||
| // super.removeObserver(observer) | |||||
| // } | |||||
| // private fun hook(observer : Observer<in T>) = try { | |||||
| // //得到 mLastVersion | |||||
| // //获取到LiveData的类中的mObserver对象 | |||||
| // // SafeIterableMap<Observer<? super T> , ObserverWrapper> mObservers | |||||
| // val liveDataClass = LiveData::class.java | |||||
| // val declaredField = liveDataClass.getDeclaredField("mObservers") | |||||
| // declaredField.isAccessible = true | |||||
| // //获取到这个成员变量的对象 | |||||
| // val mObserVersObject = declaredField.get(this) | |||||
| // //得到map对应的class对象 | |||||
| // val mObserversClass = mObserVersObject.javaClass | |||||
| // //获取到mObservers对象的get方法 | |||||
| // val get : Method = mObserversClass.getDeclaredMethod("get", Any::class.java) | |||||
| // get.isAccessible = true | |||||
| // //执行get方法,获取到对象 | |||||
| // val invokeEntry = get.invoke(mObserVersObject, observer) | |||||
| // //定义一个空的对象 | |||||
| // val observerWrapper = if (invokeEntry is Map.Entry<*, *>) { | |||||
| // invokeEntry.value | |||||
| // } else throw NullPointerException("observerWrapper is null") | |||||
| // | |||||
| // //得到observerWrapper的对象,编译擦除问题会引起多态冲突,所以用getSupperClass | |||||
| // //getClass 返回对应的当前正在运行是的类所对应的 | |||||
| // val mLastVersion = observerWrapper!!::class.java.superclass.getDeclaredField("mLastVersion") | |||||
| // mLastVersion.isAccessible = true | |||||
| // //得到mVersion | |||||
| // val mVersion = liveDataClass.getDeclaredField("mVersion") | |||||
| // mVersion.isAccessible = true | |||||
| // //把mVersion数据填入到mLastVersion中 | |||||
| // val mVersionValue = mVersion.get(this) | |||||
| // mLastVersion.set(observerWrapper, mVersionValue) | |||||
| // | |||||
| // } catch (e : Exception) { | |||||
| // e.printStackTrace() | |||||
| // } | |||||
| } |