<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() | |||||
// } | |||||
} |