Bagaimana cara mengetahui apakah emisi yang dapat diamati adalah nilai BehaviourSubject yang di-cache?

Saya menggunakan BehaviourRelay sebagai sumber yang dapat diamati, saya suka itu akan mengeluarkan nilai cache terakhir saat berlangganan, jadi saya tidak perlu memanggil showPlayingState(mPlayStateManager.getCurrentState()) secara manual.

Namun hal ini menimbulkan masalah ketika saya ingin bereaksi dengan animasi dalam berlangganan, karena saya tidak ingin menjalankan animasi pada emisi yang di-cache ini, yang dipancarkan ketika saya berlangganan di onCreate, UI seharusnya melompat ke keadaan bukan menganimasikannya. Animasi harus dijalankan hanya jika terjadi emisi "segar".

Setidaknya ini adalah kasus penggunaan yang cukup umum bagi saya, tetapi saya kesulitan memahaminya di rx

class Activity {

   PlayStateManager mPlayStateManager;
   Button mButton;

   void onCreate(SavedinstanceState state) {
      mPlayStateManager.playState()
        .subscribe(state -> {
           switch(state) {
            case PlayState.PLAYING:
                showPlayingState(true, ???);
                break;
            case PlayState.PAUSED:
                showPlayingState(false, ???);
                break;
           }
        }
   }

   void showPlayingState(boolean isPlay, boolean animate) {
     if(!animate) {
         mButton.setText(isPlay ? "Playing" : "Paused");
     } else {
         mButton.animate()
           .rotate(360)
           .onAnimationEnd(() -> {
              mButton.setText(isPlay ? "Playing" : "Paused");
           })
      }
   }
}


class PlayStateManager {

    BehaviourRelay<PlayState> mSubject = new BehaviourRelay();

    public void set(PlayState state) {
       mSubject.accept(state);
    }

    public Observable<PlayState> playState() {
        return mSubject.hide();
    }
}

person urSus    schedule 20.10.2017    source sumber


Jawaban (1)


Jika saya memahami pertanyaan Anda dengan benar, Anda tidak ingin melakukan animasi jika playState() adalah informasi yang lebih lama, tetapi hanya jika statusnya berganti. Dengan kata lain, pada panggilan awal onCreate(), Anda tidak ingin melakukan animasi, namun ingin melakukan animasi jika nilainya berubah.

enum PlayStateExpanded {
  UNKNOWN,
  PLAYING,
  PAUSED
}

class PlayStateManager {

    BehaviourRelay<PlayStateExpanded> mSubject = 
       new BehaviourRelay(PlayStateExpanded.UNKNOWN);

    public void set(PlayState state) {
       mSubject.accept(
           state == PlayState.PLAYING ? PlayStateExpanded.PLAYING
                                      : PlayStateExpanded.PAUSED);
    }

    public Observable<PlayStateExpanded> playState() {
        return mSubject.hide();
    }
}

void onCreate(SavedinstanceState state) {
  AtomicBoolean firstTime = new AtomicBoolean(true); // note first time
  mPlayStateManager.playState()
    .subscribe(state -> {
       switch(state) {
        case PlayStateExpanded.PLAYING:
            showPlayingState(true, firstTime.get());
            break;
        case PlayStateExpanded.PAUSED:
            showPlayingState(true, firstTime.get());
            break;
       }
       firstTime.set(false); // no longer first time
    }
}

Dengan mendefinisikan ulang status pemutaran dengan nilai UNKNOWN, kondisi permulaan disederhanakan. Hanya menambahkan tanda untuk transisi pertama yang disetel ulang setelah penggunaan pertama akan mencapai tujuan yang Anda nyatakan.

person Bob Dalgleish    schedule 20.10.2017
comment
ya, tapi subjek bisa dimulai dengan kosong, tanpa nilai yang di-cache - person urSus; 21.10.2017
comment
Dan? Pertanyaan Anda tidak menggambarkan perilaku dalam kasus seperti itu. Kode menunjukkan bahwa Anda menunggu nilai ditentukan. - person Bob Dalgleish; 21.10.2017
comment
Apa maksudmu? behaviorrelay tidak memiliki nilai default awal, force dapat kosong, force tidak akan ada emisi yang di-cache saat berlangganan, dan emisi baru pertama akan diperlakukan secara salah. BTW itu tergantung pada fakta bahwa ini adalah relai perilaku, yang seharusnya tidak Anda ketahui, oleh karena itu hide(), mungkinkah ada cara untuk menyandikannya dalam data yang dipancarkan? - person urSus; 21.10.2017
comment
Mari kita kembali ke desainnya sedikit. Mengapa playState() yang dapat diamati tidak terdefinisi hingga disetel? Ini mungkin harus selalu didefinisikan, mungkin dengan UNKNOWN sebagai keadaan awalnya. - person Bob Dalgleish; 22.10.2017
comment
oke, itu akan berhasil. tapi saya tetap tidak menyukai kenyataan bahwa Anda harus mengetahui perilakunya - person urSus; 22.10.2017
comment
Anda tidak perlu mengetahui perilakunya. Anda harus menyediakan observasi yang statusnya selalu ditentukan. Ada perbedaan. - person Bob Dalgleish; 23.10.2017
comment
ya, itu bagus, maksud saya emisi pertama yang ditangani khusus di pelanggan, mungkin harusnya berasal dari aliran juga, emisi ini memerlukan penanganan seperti itu - person urSus; 23.10.2017
comment
Saya setuju. Terkadang kita tidak selalu mendapatkan data bagus yang pantas kita dapatkan dan harus menyesuaikan :) - person Bob Dalgleish; 23.10.2017
comment
Bagaimana saya melakukan itu? Subkelas BehaviorStream untuk memancarkan Pair‹Boolean, T› ? - person urSus; 23.10.2017
comment
Izinkan saya menulis ulang jawaban saya. - person Bob Dalgleish; 23.10.2017