3636import androidx .fragment .app .DialogFragment ;
3737import androidx .fragment .app .Fragment ;
3838import androidx .fragment .app .FragmentManager ;
39+ import androidx .lifecycle .DefaultLifecycleObserver ;
40+ import androidx .lifecycle .Lifecycle ;
41+ import androidx .lifecycle .LifecycleOwner ;
3942import androidx .preference .PreferenceManager ;
4043
4144import org .schabi .newpipe .database .stream .model .StreamEntity ;
8891import java .util .ArrayList ;
8992import java .util .Arrays ;
9093import java .util .List ;
91- import java .util .Vector ;
9294
9395import icepick .Icepick ;
9496import icepick .State ;
@@ -213,6 +215,7 @@ protected void onDestroy() {
213215 if (dismissListener != null ) {
214216 getSupportFragmentManager ().unregisterFragmentLifecycleCallbacks (dismissListener );
215217 }
218+
216219 disposables .clear ();
217220 }
218221
@@ -699,9 +702,20 @@ private boolean canHandleChoiceLikeShowInfo(final String selectedChoiceKey) {
699702
700703 public static class PersistentFragment extends Fragment {
701704 private WeakReference <AppCompatActivity > context ;
702- private boolean isPaused = true ;
703- private final Vector <ResultRunnable > buffer = new Vector <>();
704705 private final CompositeDisposable disposables = new CompositeDisposable ();
706+ private int running = 0 ;
707+
708+ private synchronized void inFlight (final boolean started ) {
709+ if (started ) {
710+ running ++;
711+ } else {
712+ running --;
713+ if (running <= 0 && getActivityContext () != null ) {
714+ getActivityContext ().getSupportFragmentManager ()
715+ .beginTransaction ().remove (this ).commit ();
716+ }
717+ }
718+ }
705719
706720 public interface ResultRunnable {
707721 void run (AppCompatActivity context );
@@ -726,59 +740,44 @@ public void onDestroy() {
726740 disposables .clear ();
727741 }
728742
729- @ Override
730- public void onPause () {
731- isPaused = true ;
732- super .onPause ();
733- }
734-
735- @ Override
736- public void onResume () {
737- isPaused = false ;
738- playback ();
739- super .onResume ();
740- }
741-
742743 private AppCompatActivity getActivityContext () {
743744 return context == null ? null : context .get ();
744745 }
745746
747+ private boolean activityGone () {
748+ return getActivityContext () == null || getActivityContext ().isFinishing ();
749+ }
750+
746751 // guard against IllegalStateException in calling DialogFragment.show() whilst in background
747752 // (which could happen, say, when the user pressed the home button while waiting for
748753 // the network request to return) when it internally calls FragmentTransaction.commit()
749754 // after the FragmentManager has saved its states (isStateSaved() == true)
750755 // (ref: https://stackoverflow.com/a/39813506)
751- private void playback () {
752- if (activityGone ()) {
753- done ();
754- return ;
755- }
756- if (buffer .size () == 0 || isPaused ) {
757- return ;
758- }
759- while (buffer .size () > 0 ) {
760- final ResultRunnable runnable = buffer .elementAt (0 );
761- buffer .removeElementAt (0 );
762- getActivityContext ().runOnUiThread (() ->
763- // execute queued task with new context, in case activity has been recreated
764- runnable .run (getActivityContext ())
765- );
766- }
767- done ();
768- }
769- private boolean activityGone () {
770- return getActivityContext () == null || getActivityContext ().isFinishing ();
771- }
772-
773- // a DefaultLifecycleObserver is probably a good candidate here, but for now
774- // let's stick with a vanilla approach to avoid pulling in an extra artifact just for this
775756 private void runOnVisible (final ResultRunnable runnable ) {
776757 if (activityGone ()) {
777- done ( );
758+ inFlight ( false );
778759 return ;
779760 }
780- if (isPaused ) {
781- buffer .add (runnable );
761+ if (getLifecycle ().getCurrentState ().isAtLeast (Lifecycle .State .STARTED )) {
762+ getActivityContext ().runOnUiThread (() -> {
763+ runnable .run (getActivityContext ());
764+ inFlight (false );
765+ });
766+ } else {
767+ getLifecycle ().addObserver (new DefaultLifecycleObserver () {
768+ @ Override
769+ public void onResume (@ NonNull final LifecycleOwner owner ) {
770+ getLifecycle ().removeObserver (this );
771+ if (activityGone ()) {
772+ inFlight (false );
773+ return ;
774+ }
775+ getActivityContext ().runOnUiThread (() -> {
776+ runnable .run (getActivityContext ());
777+ inFlight (false );
778+ });
779+ }
780+ });
782781 // this trick doesn't seem to work on Android 10+ (API 29)
783782 // which places restrictions on starting activities from the background
784783 if (Build .VERSION .SDK_INT < Build .VERSION_CODES .Q
@@ -788,23 +787,12 @@ private void runOnVisible(final ResultRunnable runnable) {
788787 i .setFlags (Intent .FLAG_ACTIVITY_REORDER_TO_FRONT );
789788 startActivity (i );
790789 }
791- } else {
792- getActivityContext ().runOnUiThread (() -> {
793- runnable .run (getActivityContext ());
794- done ();
795- });
796- }
797- }
798-
799- private void done () {
800- if (getActivityContext () != null ) {
801- getActivityContext ().getSupportFragmentManager ()
802- .beginTransaction ().remove (this ).commit ();
803790 }
804791 }
805792
806793 @ SuppressLint ("CheckResult" )
807- protected void openDownloadDialog (final int currentServiceId , final String currentUrl ) {
794+ private void openDownloadDialog (final int currentServiceId , final String currentUrl ) {
795+ inFlight (true );
808796 disposables .add (ExtractorHelper .getStreamInfo (currentServiceId , currentUrl , true )
809797 .subscribeOn (Schedulers .io ())
810798 .observeOn (AndroidSchedulers .mainThread ())
@@ -820,6 +808,7 @@ protected void openDownloadDialog(final int currentServiceId, final String curre
820808 }
821809
822810 private void openAddToPlaylistDialog (final int currentServiceId , final String currentUrl ) {
811+ inFlight (true );
823812 disposables .add (ExtractorHelper .getStreamInfo (currentServiceId , currentUrl , false )
824813 .subscribeOn (Schedulers .io ())
825814 .observeOn (AndroidSchedulers .mainThread ())
@@ -870,7 +859,7 @@ private PersistentFragment getPersistFragment() {
870859 return persistFragment ;
871860 }
872861
873- protected void pleaseWait () {
862+ private void pleaseWait () {
874863 // Getting the stream info usually takes a moment
875864 // Notifying the user here to ensure that no confusion arises
876865 Toast .makeText (
0 commit comments