Browse Source

发音粘性事件处理,防数据丢失处理,统计显示异常处理

master
suliang 2 years ago
parent
commit
65516356f1

+ 2
- 0
.idea/misc.xml View File

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

+ 6
- 5
app/src/main/java/com/xkl/cdl/data/repository/AudioCache.kt View File

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
} }

+ 12
- 11
app/src/main/java/com/xkl/cdl/module/XKLApplication.kt View File

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

+ 14
- 10
app/src/main/java/com/xkl/cdl/module/m_statics/StatisticsTimeTopFragment.kt View File

//监听时间选项变化 //监听时间选项变化
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() {

+ 129
- 16
app/src/main/java/com/xkl/cdl/module/m_statics/StatisticsTimeTopFragmentViewModel.kt View File

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

+ 6
- 1
app/src/main/java/com/xkl/cdl/module/main/MainActivity.kt View File

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?) {
//点击事件 //点击事件

+ 3
- 2
app/src/main/java/com/xkl/cdl/module/splash/SplashActivity.kt View File

@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?) {

+ 66
- 0
lib/common/src/main/java/com/suliang/common/base/LibApplication.kt View File

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")
})
}
}

+ 30
- 7
lib/common/src/main/java/com/suliang/common/base/activity/UIBaseActivity.kt View File

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) {

+ 1
- 1
lib/common/src/main/java/com/suliang/common/eventbus/LiveDataBus.kt View File

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>

+ 0
- 81
lib/common/src/main/java/com/suliang/common/eventbus/NonStickyMutableLivedata.kt View File

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

+ 97
- 0
lib/common/src/main/java/com/suliang/common/eventbus/SingleLiveData.kt View File

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

Loading…
Cancel
Save