mirror of
https://git.citron-emu.org/citron/emulator
synced 2025-12-19 10:43:33 +00:00
Fix Android RAM overlay instant crash
Use getMainLooper() instead of myLooper() in Handler initialization and add view attachment checks to prevent crashes. Reported-by: Shadai (theonlyshadai) on Discord Signed-off-by: Zephyron <zephyron@citron-emu.org>
This commit is contained in:
@@ -526,11 +526,16 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
|||||||
if (emulationViewModel.emulationStarted.value &&
|
if (emulationViewModel.emulationStarted.value &&
|
||||||
!emulationViewModel.isEmulationStopping.value
|
!emulationViewModel.isEmulationStopping.value
|
||||||
) {
|
) {
|
||||||
val perfStats = NativeLibrary.getPerfStats()
|
if (_binding != null && binding.fpsIndicatorView.isAttachedToWindow) {
|
||||||
if (_binding != null) {
|
val perfStats = NativeLibrary.getPerfStats()
|
||||||
binding.fpsIndicatorView.updateFps(perfStats[FPS].toFloat())
|
binding.fpsIndicatorView.updateFps(perfStats[FPS].toFloat())
|
||||||
|
perfStatsUpdateHandler.postDelayed(perfStatsUpdater!!, 800)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Stop the updater if emulation is stopping
|
||||||
|
if (perfStatsUpdater != null) {
|
||||||
|
perfStatsUpdateHandler.removeCallbacks(perfStatsUpdater!!)
|
||||||
}
|
}
|
||||||
perfStatsUpdateHandler.postDelayed(perfStatsUpdater!!, 800)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
perfStatsUpdateHandler.post(perfStatsUpdater!!)
|
perfStatsUpdateHandler.post(perfStatsUpdater!!)
|
||||||
@@ -549,11 +554,16 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
|||||||
if (emulationViewModel.emulationStarted.value &&
|
if (emulationViewModel.emulationStarted.value &&
|
||||||
!emulationViewModel.isEmulationStopping.value
|
!emulationViewModel.isEmulationStopping.value
|
||||||
) {
|
) {
|
||||||
if (_binding != null) {
|
if (_binding != null && binding.thermalIndicatorView.isAttachedToWindow) {
|
||||||
val temperature = getBatteryTemperature(requireContext())
|
val temperature = getBatteryTemperature(requireContext())
|
||||||
binding.thermalIndicatorView.updateTemperature(temperature)
|
binding.thermalIndicatorView.updateTemperature(temperature)
|
||||||
|
thermalStatsUpdateHandler.postDelayed(thermalStatsUpdater!!, 2000)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Stop the updater if emulation is stopping
|
||||||
|
if (thermalStatsUpdater != null) {
|
||||||
|
thermalStatsUpdateHandler.removeCallbacks(thermalStatsUpdater!!)
|
||||||
}
|
}
|
||||||
thermalStatsUpdateHandler.postDelayed(thermalStatsUpdater!!, 2000)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
thermalStatsUpdateHandler.post(thermalStatsUpdater!!)
|
thermalStatsUpdateHandler.post(thermalStatsUpdater!!)
|
||||||
@@ -572,10 +582,15 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
|||||||
if (emulationViewModel.emulationStarted.value &&
|
if (emulationViewModel.emulationStarted.value &&
|
||||||
!emulationViewModel.isEmulationStopping.value
|
!emulationViewModel.isEmulationStopping.value
|
||||||
) {
|
) {
|
||||||
if (_binding != null) {
|
if (_binding != null && binding.ramMeterView.isAttachedToWindow) {
|
||||||
binding.ramMeterView.updateRamUsage()
|
binding.ramMeterView.updateRamUsage()
|
||||||
|
ramStatsUpdateHandler.postDelayed(ramStatsUpdater!!, 1500)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Stop the updater if emulation is stopping
|
||||||
|
if (ramStatsUpdater != null) {
|
||||||
|
ramStatsUpdateHandler.removeCallbacks(ramStatsUpdater!!)
|
||||||
}
|
}
|
||||||
ramStatsUpdateHandler.postDelayed(ramStatsUpdater!!, 1500)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ramStatsUpdateHandler.post(ramStatsUpdater!!)
|
ramStatsUpdateHandler.post(ramStatsUpdater!!)
|
||||||
@@ -1161,9 +1176,9 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
|||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private val perfStatsUpdateHandler = Handler(Looper.myLooper()!!)
|
private val perfStatsUpdateHandler = Handler(Looper.getMainLooper())
|
||||||
private val thermalStatsUpdateHandler = Handler(Looper.myLooper()!!)
|
private val thermalStatsUpdateHandler = Handler(Looper.getMainLooper())
|
||||||
private val ramStatsUpdateHandler = Handler(Looper.myLooper()!!)
|
private val ramStatsUpdateHandler = Handler(Looper.getMainLooper())
|
||||||
private val shaderStatsUpdateHandler = Handler(Looper.myLooper()!!)
|
private val shaderStatsUpdateHandler = Handler(Looper.getMainLooper())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,7 +35,18 @@ class RamMeterView @JvmOverloads constructor(
|
|||||||
|
|
||||||
fun updateRamUsage() {
|
fun updateRamUsage() {
|
||||||
try {
|
try {
|
||||||
val activityManager = context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
|
// Safety check: ensure view is attached and has valid dimensions
|
||||||
|
if (!isAttachedToWindow || width <= 0 || height <= 0) {
|
||||||
|
Log.w("RamMeter", "View not ready for update (attached: $isAttachedToWindow, width: $width, height: $height)")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
val activityManager = context.getSystemService(Context.ACTIVITY_SERVICE) as? ActivityManager
|
||||||
|
if (activityManager == null) {
|
||||||
|
Log.e("RamMeter", "ActivityManager service not available")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
val memoryInfo = ActivityManager.MemoryInfo()
|
val memoryInfo = ActivityManager.MemoryInfo()
|
||||||
activityManager.getMemoryInfo(memoryInfo)
|
activityManager.getMemoryInfo(memoryInfo)
|
||||||
|
|
||||||
@@ -61,7 +72,6 @@ class RamMeterView @JvmOverloads constructor(
|
|||||||
ramUsagePercent = 0f
|
ramUsagePercent = 0f
|
||||||
usedRamMB = 0L
|
usedRamMB = 0L
|
||||||
totalRamMB = 0L
|
totalRamMB = 0L
|
||||||
invalidate()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -92,16 +102,26 @@ class RamMeterView @JvmOverloads constructor(
|
|||||||
override fun onDraw(canvas: Canvas) {
|
override fun onDraw(canvas: Canvas) {
|
||||||
super.onDraw(canvas)
|
super.onDraw(canvas)
|
||||||
|
|
||||||
// Draw simple text-based RAM display
|
// Safety check: ensure view has valid dimensions
|
||||||
val usedGB = usedRamMB / 1024f
|
if (width <= 0 || height <= 0) {
|
||||||
val totalGB = totalRamMB / 1024f
|
Log.w("RamMeter", "onDraw called with invalid dimensions (width: $width, height: $height)")
|
||||||
val ramText = if (totalGB >= 1.0f) {
|
return
|
||||||
"RAM: ${ramUsagePercent.roundToInt()}% (%.1fGB/%.1fGB)".format(usedGB, totalGB)
|
|
||||||
} else {
|
|
||||||
"RAM: ${ramUsagePercent.roundToInt()}% (${usedRamMB}MB/${totalRamMB}MB)"
|
|
||||||
}
|
}
|
||||||
canvas.drawText(ramText, 8f, height - 8f, textPaint)
|
|
||||||
|
|
||||||
Log.d("RamMeter", "onDraw called - RAM: $ramText")
|
try {
|
||||||
|
// Draw simple text-based RAM display
|
||||||
|
val usedGB = usedRamMB / 1024f
|
||||||
|
val totalGB = totalRamMB / 1024f
|
||||||
|
val ramText = if (totalGB >= 1.0f) {
|
||||||
|
"RAM: ${ramUsagePercent.roundToInt()}% (%.1fGB/%.1fGB)".format(usedGB, totalGB)
|
||||||
|
} else {
|
||||||
|
"RAM: ${ramUsagePercent.roundToInt()}% (${usedRamMB}MB/${totalRamMB}MB)"
|
||||||
|
}
|
||||||
|
canvas.drawText(ramText, 8f, height - 8f, textPaint)
|
||||||
|
|
||||||
|
Log.d("RamMeter", "onDraw called - RAM: $ramText")
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Log.e("RamMeter", "Error in onDraw", e)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user