Fix some cases of doing I/O in main thread (#8091)

This commit is contained in:
Hans-Peter Lehmann
2025-11-14 07:53:28 +01:00
committed by GitHub
parent 458d8732c6
commit 2c65402a9b
2 changed files with 90 additions and 53 deletions

View File

@ -3,6 +3,7 @@ package de.danoeh.antennapod.ui.screen.playback;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@ -20,6 +21,10 @@ import de.danoeh.antennapod.event.playback.SpeedChangedEvent;
import de.danoeh.antennapod.playback.service.PlaybackController;
import de.danoeh.antennapod.storage.preferences.UserPreferences;
import de.danoeh.antennapod.ui.view.ItemOffsetDecoration;
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
import io.reactivex.rxjava3.core.Observable;
import io.reactivex.rxjava3.disposables.Disposable;
import io.reactivex.rxjava3.schedulers.Schedulers;
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
@ -31,12 +36,14 @@ import java.util.List;
import java.util.Locale;
public class VariableSpeedDialog extends BottomSheetDialogFragment {
private static final String TAG = "VariableSpeedDialog";
private SpeedSelectionAdapter adapter;
private PlaybackController controller;
private final List<Float> selectedSpeeds;
private PlaybackSpeedSeekBar speedSeekBar;
private Chip addCurrentSpeedChip;
private CheckBox skipSilenceCheckbox;
private Disposable disposable;
public VariableSpeedDialog() {
DecimalFormatSymbols format = new DecimalFormatSymbols(Locale.US);
@ -50,14 +57,12 @@ public class VariableSpeedDialog extends BottomSheetDialogFragment {
controller = new PlaybackController(getActivity()) {
@Override
public void loadMediaInfo() {
updateSpeed(new SpeedChangedEvent(controller.getCurrentPlaybackSpeedMultiplier()));
updateSkipSilence(controller.getCurrentPlaybackSkipSilence());
VariableSpeedDialog.this.loadMediaInfo();
}
};
controller.init();
EventBus.getDefault().register(this);
updateSpeed(new SpeedChangedEvent(controller.getCurrentPlaybackSpeedMultiplier()));
updateSkipSilence(controller.getCurrentPlaybackSkipSilence());
loadMediaInfo();
}
@Override
@ -66,6 +71,32 @@ public class VariableSpeedDialog extends BottomSheetDialogFragment {
controller.release();
controller = null;
EventBus.getDefault().unregister(this);
if (disposable != null) {
disposable.dispose();
}
}
private void loadMediaInfo() {
if (disposable != null) {
disposable.dispose();
}
disposable = Observable.fromCallable(() -> {
if (controller == null) {
return null;
}
// Make sure the media is loaded in case getCurrentPlaybackSpeedMultiplier has to access it
return controller.getMedia();
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(pair -> {
if (controller == null) {
return;
}
updateSpeed(new SpeedChangedEvent(controller.getCurrentPlaybackSpeedMultiplier()));
updateSkipSilence(controller.getCurrentPlaybackSkipSilence());
}, error -> Log.e(TAG, Log.getStackTraceString(error)));
}
@Subscribe(threadMode = ThreadMode.MAIN)

View File

@ -68,7 +68,7 @@ import de.danoeh.antennapod.ui.screen.playback.MediaPlayerErrorDialog;
import de.danoeh.antennapod.ui.screen.playback.PlaybackControlsDialog;
import de.danoeh.antennapod.ui.screen.playback.SleepTimerDialog;
import de.danoeh.antennapod.ui.screen.playback.VariableSpeedDialog;
import io.reactivex.rxjava3.core.Observable;
import io.reactivex.rxjava3.core.Maybe;
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
import io.reactivex.rxjava3.disposables.Disposable;
import io.reactivex.rxjava3.schedulers.Schedulers;
@ -189,7 +189,6 @@ public class VideoplayerActivity extends CastEnabledActivity implements SeekBar.
controller = newPlaybackController();
controller.init();
loadMediaInfo();
onPositionObserverUpdate();
EventBus.getDefault().register(this);
}
@ -266,24 +265,55 @@ public class VideoplayerActivity extends CastEnabledActivity implements SeekBar.
protected void loadMediaInfo() {
Log.d(TAG, "loadMediaInfo()");
if (controller == null || controller.getMedia() == null) {
return;
}
if (controller.getStatus() == PlayerStatus.PLAYING && !controller.isPlayingVideoLocally()) {
Log.d(TAG, "Closing, no longer video");
destroyingDueToReload = true;
finish();
new MainActivityStarter(this).withOpenPlayer().start();
return;
}
showTimeLeft = UserPreferences.shouldShowRemainingTime();
onPositionObserverUpdate();
checkFavorite();
Playable media = controller.getMedia();
if (media != null) {
getSupportActionBar().setSubtitle(media.getEpisodeTitle());
getSupportActionBar().setTitle(media.getFeedTitle());
if (disposable != null) {
disposable.dispose();
}
disposable = Maybe.<Pair<Playable, FeedItem>>create(emitter -> {
if (controller == null) {
emitter.onComplete();
return;
}
Playable media = controller.getMedia();
if (media == null) {
emitter.onComplete();
return;
}
FeedItem feedItem = getFeedItem(controller.getMedia());
if (feedItem != null) {
feedItem = DBReader.getFeedItem(feedItem.getId());
}
emitter.onSuccess(new Pair<>(media, feedItem));
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
result -> {
final Playable media = result.first;
final FeedItem item = result.second;
if (controller.getStatus() == PlayerStatus.PLAYING
&& !controller.isPlayingVideoLocally()) {
Log.d(TAG, "Closing, no longer video");
destroyingDueToReload = true;
finish();
new MainActivityStarter(this).withOpenPlayer().start();
return;
}
showTimeLeft = UserPreferences.shouldShowRemainingTime();
onPositionObserverUpdate(
new PlaybackPositionEvent(controller.getPosition(), controller.getDuration()));
if (media != null) {
getSupportActionBar().setSubtitle(media.getEpisodeTitle());
getSupportActionBar().setTitle(media.getFeedTitle());
}
boolean isFav = item.isTagged(FeedItem.TAG_FAVORITE);
if (isFavorite != isFav) {
isFavorite = isFav;
invalidateOptionsMenu();
}
}, error -> Log.e(TAG, Log.getStackTraceString(error))
);
}
protected void setupView() {
@ -532,7 +562,7 @@ public class VideoplayerActivity extends CastEnabledActivity implements SeekBar.
@Subscribe(threadMode = ThreadMode.MAIN)
public void onEventMainThread(PlaybackPositionEvent event) {
onPositionObserverUpdate();
onPositionObserverUpdate(event);
}
@Subscribe(threadMode = ThreadMode.MAIN)
@ -659,24 +689,21 @@ public class VideoplayerActivity extends CastEnabledActivity implements SeekBar.
return null;
}
void onPositionObserverUpdate() {
void onPositionObserverUpdate(PlaybackPositionEvent event) {
if (controller == null) {
return;
}
TimeSpeedConverter converter = new TimeSpeedConverter(controller.getCurrentPlaybackSpeedMultiplier());
int currentPosition = converter.convert(controller.getPosition());
int duration = converter.convert(controller.getDuration());
int remainingTime = converter.convert(
controller.getDuration() - controller.getPosition());
int currentPosition = converter.convert(event.getPosition());
int duration = converter.convert(event.getDuration());
Log.d(TAG, "currentPosition " + Converter.getDurationStringLong(currentPosition));
if (currentPosition == Playable.INVALID_TIME
|| duration == Playable.INVALID_TIME) {
if (currentPosition == Playable.INVALID_TIME || duration == Playable.INVALID_TIME) {
Log.w(TAG, "Could not react to position observer update because of invalid time");
return;
}
viewBinding.positionLabel.setText(Converter.getDurationStringLong(currentPosition));
if (showTimeLeft) {
int remainingTime = converter.convert(event.getDuration() - event.getPosition());
viewBinding.durationLabel.setText("-" + Converter.getDurationStringLong(remainingTime));
} else {
viewBinding.durationLabel.setText(Converter.getDurationStringLong(duration));
@ -730,27 +757,6 @@ public class VideoplayerActivity extends CastEnabledActivity implements SeekBar.
setupVideoControlsToggler();
}
private void checkFavorite() {
FeedItem feedItem = getFeedItem(controller.getMedia());
if (feedItem == null) {
return;
}
if (disposable != null) {
disposable.dispose();
}
disposable = Observable.fromCallable(() -> DBReader.getFeedItem(feedItem.getId()))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
item -> {
boolean isFav = item.isTagged(FeedItem.TAG_FAVORITE);
if (isFavorite != isFav) {
isFavorite = isFav;
invalidateOptionsMenu();
}
}, error -> Log.e(TAG, Log.getStackTraceString(error)));
}
@Nullable
private static FeedItem getFeedItem(@Nullable Playable playable) {
if (playable instanceof FeedMedia) {