首页 > 解决方案 > 为什么我在 View Model 中的 observable 仅在第二次调用后才发出值

问题描述

我有observable的奇怪行为。我从ViewModel getData()中的SecondFragment void调用它应该逐秒发出值,但它不会。在日志中我只有:

getData called.
getData subscribe

当我返回到上一个片段(ViewModelFragment被销毁(一次性处置))并再次输入时,它会正常工作。此外,当我第二次从按钮调用此方法时。

有人知道为什么它不能正常工作吗?

BaseFragmentCompat

public abstract class PreferenceFragmentCompatBase extends PreferenceFragmentCompat {
    private static final String TAG = "PreferenceFragmentCompa";

    private final CompositeDisposable mCompositeDisposable = new CompositeDisposable();

    public void addCompositeDisposable(Disposable disposable) {
        mCompositeDisposable.add(disposable);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        mCompositeDisposable.dispose();
    }

    @Override
    public void onDestroyView() {
        super.onDestroyView();
        mCompositeDisposable.clear();
    }

    public DisposableObserver<String> preferenceSubscriber(Preference preference) {
        return new DisposableObserver<String>() {
            @Override
            public void onNext(@NonNull String s) {
                if (preference == null)
                    return;
                preference.setSummary(s);
            }

            @Override
            public void onError(@io.reactivex.rxjava3.annotations.NonNull Throwable e) {
                if (preference == null)
                    return;
                preference.setSummary(NO_DATA);
            }

            @Override
            public void onComplete() {
                Log.d(TAG, "onComplete: onComplete");
            }

            @Override
            protected void onStart() {
                if (preference == null)
                    return;
                preference.setSummary("Ładowanie...");
            }
        };
    }

    protected NavBackStackEntry navGraphViewModels(int navigation) {
        return NavHostFragment.findNavController(this).getBackStackEntry(navigation);
    }
}

第二片段

public class SecondFragment extends PreferenceFragmentCompatBase {
    private static final String TAG = "SettingsDataiCzasFragme";

    private SettingsDataiCzasViewModel mViewModel;
    private NavController navController;

    public SettingsDataiCzasFragment() {
    }

    @Override
    public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
        addPreferencesFromResource(R.xml.settings_dataiczas);
        mViewModel = new ViewModelProvider(navGraphViewModels(R.id.navigation_data_i_czas)).get(SettingsDataiCzasViewModel.class);
        navController = NavHostFragment.findNavController(this);

        observeData();
        mViewModel.getData(); // here I called void in ViewModel but nothing happends
    }

    private void observeData() {
        final Preference dateTime = findPreference(Constants.date_time_cash);

        addCompositeDisposable(
                mViewModel.getDateAndTime()
                        .doOnSubscribe(disposable -> Log.d(TAG, "observeData: subscribe."))
                        .doOnTerminate(() -> Log.d(TAG, "observeData: terminate"))
                        .doOnDispose(() -> Log.d(TAG, "observeData: disposed"))
                        .subscribeOn(Schedulers.io())
                        .observeOn(Schedulers.io())
                        .map(zonedDateTimeStr -> FormatHelper.convertInstanttoSimpleDate(zonedDateTimeStr, true, true, true))
                        .observeOn(AndroidSchedulers.mainThread())
                        .subscribeWith(preferenceSubscriber(dateTime))
        );
    }

    @Override
    public boolean onPreferenceTreeClick(Preference preference) {
        .....
}

基本视图模型

public abstract class SettingsAbstractViewModel extends AndroidViewModel {
    private static final String TAG = "SettingsServerAbstractV";

    public static final String NO_DATA = "Brak danych";

    private final CompositeDisposable mCompositeDisposable;


    public SettingsAbstractViewModel(@NonNull Application application) {
        super(application);
        mCompositeDisposable = new CompositeDisposable();
    }

    /**
     * Funkcja pobierająca dane z różnych źródeł przy utworzeniu ViewModelu
     */
    public abstract void getData();

    public void addCompositeDisposable(Disposable disposable) {
        mCompositeDisposable.add(disposable);
    }

    @Override
    public void onCleared() {
        super.onCleared();
        Log.i(TAG, "onCleared: called for: " + this);
        Log.i(TAG, "onCleared: disposable: " + mCompositeDisposable);
        mCompositeDisposable.clear();

    }
}

视图模型

public class VIEWMODEL extends SettingsAbstractViewModel {
    private static final String TAG = "SettingsDataiCzasViewModel";

    private TimeRepository mTimeRepository;
    private int[] zoneOffsets;
    private String[] zoneNames;
    private BehaviorSubject<ZonedDateTime> dateAndTime;
    public PublishSubjectDataRx3<ZonedDateTime> syncTimeResult;
    private Disposable getTimeDisposable;
    private Disposable subscribe;
    public SettingsDataiCzasViewModel(@NonNull Application application) {
        super(application);
        mTimeRepository = new TimeRepository(getApplication());
        dateAndTime = BehaviorSubject.create();
        syncTimeResult = new PublishSubjectDataRx3<>();
    }

    @Override
    public void getData() {
        Log.d(TAG, "getData: called.");
        if (subscribe != null)
            subscribe.dispose();
        subscribe = Observable.interval(0, 1000, TimeUnit.MILLISECONDS)
                .subscribeOn(Schedulers.computation())
                .doonSubscribe(ignore -> Log.d(TAG, "getData: subscribe))
                .doonDispose(() -> Log.d(TAG, "getData: dispose))
                .switchMapSingle(ignore ->
                        mTimeRepository.getZonedTime()
                                .subscribeOn(Schedulers.io())
                                .subscribeOn(Schedulers.io())
                                .observeOn(Schedulers.io()))
                .subscribe(
                        zonedDateTimeStr -> {
                            dateAndTime.onNext(zonedDateTimeStr);
                        },
                        e -> Log.e(TAG, "getData: ", e)
                );
    }

    @Override
    public void onCleared() {
        super.onCleared();
        if (subscribe != null)
            subscribe.dispose();
    }

    public void downloadTimeFromServer(int zoneOffset) {
        Log.d(TAG, "downloadTimeFromServer: called.");
        syncTimeResult.loading();
        getTimeDisposable = mTimeRepository.getDateAndTimeFromServer()
                .subscribeOn(Schedulers.io())
                .doOnEvent((aLong, throwable) -> Log.d(TAG, "downloadTimeFromServer: " + aLong + throwable))
                .flatMapCompletable(aLong -> mTimeRepository.setDateAndTimeFromUtc(aLong, zoneOffset))
                .doOnEvent(throwable -> Log.d(TAG, "downloadTimeFromServer: " + throwable))
                .andThen(Single.defer(() -> mTimeRepository.getZonedTime()))
                .doOnEvent((zonedDateTime, throwable) -> Log.d(TAG, "downloadTimeFromServer: " + zonedDateTime.toString() + throwable))
                .observeOn(Schedulers.io())
                .subscribe(
                        zonedDateTime -> {
                            syncTimeResult.success(zonedDateTime);
                        },
                        e -> {
                            Logs.e(TAG, "getTimeFromServer: ", e);
                            String errorMsg;
                            if (e instanceof UnknownHostException)
                                errorMsg = "Wystąpił błąd podczas próby komunikacji z serwerem.\nSprawdź połączenie z internetem.";
                            else
                                errorMsg = e.getMessage();
                            syncTimeResult.error(errorMsg);
                        }
                );
        addCompositeDisposable(getTimeDisposable);
    }

    public Observable<Resource<ZonedDateTime>> getSyncTimeResult() {
        return syncTimeResult.getOrigin();
    }

    public Observable<ZonedDateTime> getDateAndTime() {
        return dateAndTime;
    }
}

标签: androidrx-javaviewmodeldisposable

解决方案


推荐阅读