屏幕旋转后Resume flowable转为实时数据
Resume flowable converted to live data after screen rotation
假设我有一个 activity 这样的:
public class TestActivity extends AppCompatActivity {
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
final TextView countdown = new TextView(this);
setContentView(countdown);
ViewModelProviders.of(this)
.get(TestViewModel.class)
.getCountdown()
.observe(this, countdown::setText);
}
}
视图模型是:
class TestViewModel extends ViewModel {
private final LiveData<String> countdown =
LiveDataReactiveStreams.fromPublisher(
Flowable.concat(
Flowable.just("Falcon Heavy rocket will launch in..."),
Flowable.intervalRange(0, 10, 3, 1, TimeUnit.SECONDS)
.map(x -> String.valueOf(10 - x)),
Flowable.timer(1, TimeUnit.SECONDS)
.map(ignored -> "Lift off!")
)
);
LiveData<String> getCountdown() {
return countdown;
}
}
我想正确处理旋转,所以如果用户在倒计时显示 5 时旋转他的设备,我希望旋转后的下一个值是 5(如果第二个已经过去,则为 4),只需在任何地方拿起倒计时应该是。
如果火箭已经升空了,我希望它在旋转后保持这种状态,我不希望重新开始倒计时。
目前,LiveDataReactiveStreams
在暂停时取消订阅并在恢复时重新订阅,因此倒计时重新开始。
我想我应该更改代码的 RxJava 部分中的某些内容才能使其正常工作。关于要更改的内容有什么想法吗?
感谢 Android United Slack channel 的 Svyatoslav Lebeckiy 向我指出 BehaviorSubject
和 BehaviorProcessor
并提出了解决此问题的想法。
我将视图模型更改为:
class TestViewModel extends ViewModel {
private LiveData<String> countdown;
LiveData<String> getCountdown() {
if (countdown == null) {
countdown = LiveDataReactiveStreams.fromPublisher(startCountdown());
}
return countdown;
}
private static Flowable<String> startCountdown() {
final BehaviorProcessor<String> processor = BehaviorProcessor.create();
Flowable.concat(
Flowable.just("Falcon Heavy rocket will launch in..."),
Flowable.intervalRange(0, 10, 3, 1, TimeUnit.SECONDS)
.map(x -> String.valueOf(10 - x)),
Flowable.timer(1, TimeUnit.SECONDS)
.map(ignored -> "Lift off!")
).subscribe(processor);
return processor;
}
}
这样我可以在 getCountdown
中只开始倒计时一次,而在 startCountdown
中创建的 BehaviorProcessor
负责将最后一个和随后发出的值传递给它的订阅者(LiveData
在这种情况下)。
因为LiveDataReactiveStreams
需要Flowable
,这里用BehaviorProcessor
代替BehaviorSubject
比较方便。
假设我有一个 activity 这样的:
public class TestActivity extends AppCompatActivity {
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
final TextView countdown = new TextView(this);
setContentView(countdown);
ViewModelProviders.of(this)
.get(TestViewModel.class)
.getCountdown()
.observe(this, countdown::setText);
}
}
视图模型是:
class TestViewModel extends ViewModel {
private final LiveData<String> countdown =
LiveDataReactiveStreams.fromPublisher(
Flowable.concat(
Flowable.just("Falcon Heavy rocket will launch in..."),
Flowable.intervalRange(0, 10, 3, 1, TimeUnit.SECONDS)
.map(x -> String.valueOf(10 - x)),
Flowable.timer(1, TimeUnit.SECONDS)
.map(ignored -> "Lift off!")
)
);
LiveData<String> getCountdown() {
return countdown;
}
}
我想正确处理旋转,所以如果用户在倒计时显示 5 时旋转他的设备,我希望旋转后的下一个值是 5(如果第二个已经过去,则为 4),只需在任何地方拿起倒计时应该是。
如果火箭已经升空了,我希望它在旋转后保持这种状态,我不希望重新开始倒计时。
目前,LiveDataReactiveStreams
在暂停时取消订阅并在恢复时重新订阅,因此倒计时重新开始。
我想我应该更改代码的 RxJava 部分中的某些内容才能使其正常工作。关于要更改的内容有什么想法吗?
感谢 Android United Slack channel 的 Svyatoslav Lebeckiy 向我指出 BehaviorSubject
和 BehaviorProcessor
并提出了解决此问题的想法。
我将视图模型更改为:
class TestViewModel extends ViewModel {
private LiveData<String> countdown;
LiveData<String> getCountdown() {
if (countdown == null) {
countdown = LiveDataReactiveStreams.fromPublisher(startCountdown());
}
return countdown;
}
private static Flowable<String> startCountdown() {
final BehaviorProcessor<String> processor = BehaviorProcessor.create();
Flowable.concat(
Flowable.just("Falcon Heavy rocket will launch in..."),
Flowable.intervalRange(0, 10, 3, 1, TimeUnit.SECONDS)
.map(x -> String.valueOf(10 - x)),
Flowable.timer(1, TimeUnit.SECONDS)
.map(ignored -> "Lift off!")
).subscribe(processor);
return processor;
}
}
这样我可以在 getCountdown
中只开始倒计时一次,而在 startCountdown
中创建的 BehaviorProcessor
负责将最后一个和随后发出的值传递给它的订阅者(LiveData
在这种情况下)。
因为LiveDataReactiveStreams
需要Flowable
,这里用BehaviorProcessor
代替BehaviorSubject
比较方便。