@@ -238,6 +238,8 @@ | |||
<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_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" /> | |||
</map> | |||
</option> |
@@ -1,9 +1,8 @@ | |||
package com.xkl.cdl.data.repository | |||
import android.net.IpPrefix | |||
import android.util.LruCache | |||
import androidx.lifecycle.MutableLiveData | |||
import com.suliang.common.AppConfig | |||
import com.suliang.common.eventbus.SingleLiveData | |||
import com.suliang.common.extension.diskIo2Main | |||
import com.suliang.common.util.file.FileUtil | |||
import com.xkl.cdl.data.AppConstants | |||
@@ -33,10 +32,12 @@ object AudioCache { | |||
} | |||
/** 通知查到的录音 */ | |||
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 | |||
} | |||
@@ -3,6 +3,7 @@ package com.xkl.cdl.module | |||
import android.app.Activity | |||
import android.app.Application | |||
import android.os.Bundle | |||
import com.suliang.common.base.LibApplication | |||
import com.suliang.common.util.ActivityStackManager | |||
import com.suliang.common.util.LogUtil | |||
import com.suliang.common.util.file.FileUtil | |||
@@ -25,34 +26,34 @@ import kotlin.properties.Delegates | |||
* create 2022/3/14 11:27 | |||
* Describe: | |||
*/ | |||
class XKLApplication : Application() { | |||
class XKLApplication : LibApplication() { | |||
companion object{ | |||
val mobileCache:MobileCache by lazy { | |||
val file : String = File(FileUtil.getSaveDirFile("db"), "mydb").absolutePath | |||
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() { | |||
super.onCreate() | |||
instance = this | |||
// instance = this | |||
SQLiteDatabase.loadLibs(this) | |||
LogUtil.e(UUID.randomUUID().toString().replace("-","")) | |||
// LogUtil.e(UUID.randomUUID().toString().replace("-","")) | |||
//初始MMKV存储 | |||
val rootDir = MMKV.initialize(this) | |||
LogUtil.e(rootDir) | |||
setRxJavaErrorHandler() | |||
// 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() | |||
@@ -78,7 +79,7 @@ class XKLApplication : Application() { | |||
}) | |||
} | |||
*/ | |||
private object lifecycleCallback : Application.ActivityLifecycleCallbacks { | |||
private var count = 0 |
@@ -44,22 +44,26 @@ class StatisticsTimeTopFragment : BaseFragmentVM<FragmentStatisticsTimeTopBindin | |||
//监听时间选项变化 | |||
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]) | |||
} | |||
// } | |||
} | |||
} | |||
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() { |
@@ -55,7 +55,11 @@ open class StatisticsTimeTopFragmentViewModel : BaseViewModel() { | |||
protected fun initTimeStaticItem(statistics : AppApi.Statistics) : MutableList<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 { | |||
name = "有效学习时长" | |||
backGround = R.drawable.shape_rounder_4_red_a5 | |||
@@ -83,9 +87,10 @@ open class StatisticsTimeTopFragmentViewModel : BaseViewModel() { | |||
} | |||
} | |||
}else{ | |||
timeStaticItem_1.time = "0" | |||
timeStaticItem_1.unit = "" | |||
timeStaticItem_1.time = "" | |||
timeStaticItem_1.unit = "不足1分钟" | |||
} | |||
initIncr(timeStaticItem_1,statistics.sdIncr.toDouble()) | |||
//增量不为0 | |||
if (statistics.sdIncr != 0L ){ | |||
val hour_1 = statistics.sdIncr / 3600000.0 | |||
@@ -99,11 +104,15 @@ open class StatisticsTimeTopFragmentViewModel : BaseViewModel() { | |||
//小于1分钟 秒数 | |||
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 { | |||
backGround = R.drawable.shape_rounder_4_theme_a5 | |||
name = "综合学习效率" | |||
@@ -131,20 +140,128 @@ open class StatisticsTimeTopFragmentViewModel : BaseViewModel() { | |||
time = initShow(statistics.ts) | |||
initIncr(this,statistics.tsIncr) | |||
} | |||
result.add(timeStaticItem_4) | |||
result.add(timeStaticItem_4)*/ | |||
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{ | |||
val temp = abs(value) | |||
//保留一位小数 向下取舍 | |||
val formatFloor = NumberUtils.formatFloor(value, "0.0") | |||
val formatFloor = NumberUtils.formatFloor(temp, "0.0") | |||
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 | |||
else -> formatFloor | |||
} | |||
@@ -154,14 +271,10 @@ open class StatisticsTimeTopFragmentViewModel : BaseViewModel() { | |||
private fun initIncr(timeStaticItem_1 : TimeStatisticItem, sdIncr : Double) { | |||
timeStaticItem_1.run { | |||
when{ | |||
sdIncr == 0.0 -> { | |||
incr = "" | |||
imgDrawable = R.drawable.ic_keep | |||
} | |||
sdIncr == 0.0 -> imgDrawable = R.drawable.ic_keep | |||
sdIncr > 0 -> { | |||
imgDrawable = R.drawable.ic_rise | |||
incrTextColor = R.color.green_1 | |||
incr = "+$incr" | |||
} | |||
else -> { | |||
imgDrawable = R.drawable.ic_decline |
@@ -18,6 +18,7 @@ import com.xkl.cdl.module.m_memo.MemoFragment | |||
import com.xkl.cdl.module.m_my.MyFragment | |||
import com.xkl.cdl.module.m_service_center.ServiceCenterFragment | |||
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.statusBarOnly | |||
@@ -41,7 +42,11 @@ class MainActivity : BaseActivityVM<ActivityMainBinding, MainActivityViewModel>( | |||
override fun initViewModel(): MainActivityViewModel { | |||
return ViewModelProvider(this)[MainActivityViewModel::class.java] | |||
} | |||
override fun protectApp() { | |||
startActivity(SplashActivity::class.java) | |||
finish() | |||
} | |||
override fun initActivity(savedInstanceState: Bundle?) { | |||
//点击事件 |
@@ -25,12 +25,13 @@ import java.util.concurrent.TimeUnit | |||
@SuppressLint("CustomSplashScreen") | |||
class SplashActivity : BaseActivity<ActivitySplashBinding>() { | |||
override fun onCreate(savedInstanceState : Bundle?) { | |||
override fun onCreateOwn(savedInstanceState : Bundle?) { | |||
if (!isTaskRoot) { | |||
finish() | |||
return | |||
} | |||
super.onCreate(savedInstanceState) | |||
XKLApplication.instance().isLaunch = true | |||
super.onCreateOwn(savedInstanceState) | |||
} | |||
override fun initActivity(savedInstanceState : Bundle?) { |
@@ -0,0 +1,66 @@ | |||
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") | |||
}) | |||
} | |||
} |
@@ -1,10 +1,12 @@ | |||
package com.suliang.common.base.activity | |||
import android.content.ComponentName | |||
import android.content.Intent | |||
import android.graphics.Color | |||
import android.os.Bundle | |||
import android.widget.Toast | |||
import androidx.annotation.StringRes | |||
import com.suliang.common.base.LibApplication | |||
import com.suliang.common.base.LoadingDialog | |||
import com.suliang.common.base.ViewBehavior | |||
import com.suliang.common.util.ActivityStackManager | |||
@@ -20,6 +22,14 @@ abstract class UIBaseActivity : LifecycleLogActivity(), ViewBehavior { | |||
override fun onCreate(savedInstanceState : Bundle?) { | |||
super.onCreate(savedInstanceState) | |||
onCreateOwn(savedInstanceState) | |||
} | |||
protected open fun onCreateOwn(savedInstanceState : Bundle?) { | |||
if (!LibApplication.instance().isLaunch) { | |||
protectApp() | |||
return | |||
} | |||
//入栈 | |||
ActivityStackManager.addActivity(this) | |||
initFirst() | |||
@@ -27,6 +37,21 @@ abstract class UIBaseActivity : LifecycleLogActivity(), ViewBehavior { | |||
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, | |||
*/ | |||
@@ -86,10 +111,9 @@ abstract class UIBaseActivity : LifecycleLogActivity(), ViewBehavior { | |||
val showTime = if (event.showLong) Toast.LENGTH_LONG else Toast.LENGTH_LONG | |||
event.content?.let { | |||
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) { | |||
@@ -108,11 +132,10 @@ abstract class UIBaseActivity : LifecycleLogActivity(), ViewBehavior { | |||
if (findFragment is LoadingDialog) { | |||
findFragment.dialog?.show() | |||
} | |||
} ?: let { | |||
val loadingDialog = LoadingDialog.newInstance("") | |||
loadingDialog.show(supportFragmentManager, "loading") | |||
} | |||
?: let { | |||
val loadingDialog = LoadingDialog.newInstance("") | |||
loadingDialog.show(supportFragmentManager, "loading") | |||
} | |||
} else { //关闭 | |||
findFragment?.let { | |||
if (it is LoadingDialog) { |
@@ -40,7 +40,7 @@ object LiveDataBus { | |||
if (isSticky){ | |||
bus[key] = MutableLiveData() | |||
}else{ | |||
bus[key] = NonStickyMutableLivedata() | |||
bus[key] = SingleLiveData() | |||
} | |||
} | |||
return bus[key] as MutableLiveData<T> |
@@ -1,81 +0,0 @@ | |||
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() | |||
} | |||
} |
@@ -0,0 +1,97 @@ | |||
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() | |||
// } | |||
} |