From 6c2e67eb06c0d1ef2db1073e5acb8fd1e647f015 Mon Sep 17 00:00:00 2001 From: Danielku15 Date: Thu, 9 Apr 2026 17:52:48 +0200 Subject: [PATCH] fix(android): interrupt handling and main looper usage --- .../src/main/java/alphaTab/AlphaTabView.kt | 2 +- .../platform/android/AndroidAudioWorker.kt | 25 +++++++++++-------- .../platform/android/AndroidUiFacade.kt | 6 ++++- 3 files changed, 21 insertions(+), 12 deletions(-) diff --git a/packages/kotlin/src/android/src/main/java/alphaTab/AlphaTabView.kt b/packages/kotlin/src/android/src/main/java/alphaTab/AlphaTabView.kt index 373fbfbd2..fbdc18c4a 100644 --- a/packages/kotlin/src/android/src/main/java/alphaTab/AlphaTabView.kt +++ b/packages/kotlin/src/android/src/main/java/alphaTab/AlphaTabView.kt @@ -78,8 +78,8 @@ class AlphaTabView : RelativeLayout { } override fun onDetachedFromWindow() { - super.onDetachedFromWindow() _api.destroy() + super.onDetachedFromWindow() } private fun init(context: Context) { diff --git a/packages/kotlin/src/android/src/main/java/alphaTab/platform/android/AndroidAudioWorker.kt b/packages/kotlin/src/android/src/main/java/alphaTab/platform/android/AndroidAudioWorker.kt index 3a5c8abb8..26af6404b 100644 --- a/packages/kotlin/src/android/src/main/java/alphaTab/platform/android/AndroidAudioWorker.kt +++ b/packages/kotlin/src/android/src/main/java/alphaTab/platform/android/AndroidAudioWorker.kt @@ -56,23 +56,28 @@ internal class AndroidAudioWorker( private fun writeSamples() { while (!_stopped) { - if (_track.playState == AudioTrack.PLAYSTATE_PLAYING) { - val samplesFromBuffer = _output.read(_buffer, 0, _buffer.size) - if (_previousPosition == -1) { - _previousPosition = _track.playbackHeadPosition - _track.getTimestamp(_timestamp) + try { + if (_track.playState == AudioTrack.PLAYSTATE_PLAYING) { + val samplesFromBuffer = _output.read(_buffer, 0, _buffer.size) + if (_previousPosition == -1) { + _previousPosition = _track.playbackHeadPosition + _track.getTimestamp(_timestamp) + } + _track.write(_buffer, 0, samplesFromBuffer, AudioTrack.WRITE_BLOCKING) + } else { + _playingSemaphore.acquire() // wait for playing to start + _playingSemaphore.release() // release semaphore for others } - _track.write(_buffer, 0, samplesFromBuffer, AudioTrack.WRITE_BLOCKING) - } else { - _playingSemaphore.acquire() // wait for playing to start - _playingSemaphore.release() // release semaphore for others + } catch (_: InterruptedException) { + Thread.currentThread().interrupt() + break; } } } fun close() { - _playingSemaphore.release() // proceed thread _stopped = true + _playingSemaphore.release() // proceed thread _track.stop() _writeThread!!.interrupt() _writeThread!!.join() diff --git a/packages/kotlin/src/android/src/main/java/alphaTab/platform/android/AndroidUiFacade.kt b/packages/kotlin/src/android/src/main/java/alphaTab/platform/android/AndroidUiFacade.kt index 5d4be7bcf..e8bca30eb 100644 --- a/packages/kotlin/src/android/src/main/java/alphaTab/platform/android/AndroidUiFacade.kt +++ b/packages/kotlin/src/android/src/main/java/alphaTab/platform/android/AndroidUiFacade.kt @@ -26,6 +26,7 @@ import alphaTab.synth.IAudioExporterWorker import android.annotation.SuppressLint import android.graphics.Bitmap import android.os.Handler +import android.os.Looper import android.view.MotionEvent import android.view.View import android.view.ViewGroup @@ -54,6 +55,8 @@ internal class AndroidUiFacade : IUiFacade { private val _renderSurface: AlphaTabRenderSurface private val _renderWrapper: RelativeLayout + private val _uiLooper:Handler; + public constructor( outerScroll: SuspendableHorizontalScrollView, innerScroll: SuspendableScrollView, @@ -64,6 +67,7 @@ internal class AndroidUiFacade : IUiFacade { _innerScroll = innerScroll _renderSurface = renderSurface _renderWrapper = renderWrapper + _uiLooper = Handler(Looper.getMainLooper()) rootContainer = AndroidRootViewContainer(outerScroll, innerScroll, renderSurface, this::beginInvoke) @@ -163,7 +167,7 @@ internal class AndroidUiFacade : IUiFacade { } private fun postToUIThread(action: () -> Unit) { - this._renderSurface.post(action) + _uiLooper.post(action) } private fun openDefaultSoundFont(): InputStream {