Правильное использование планировщиков - PullRequest
0 голосов
/ 06 ноября 2018

Я пытаюсь прочитать файл из файловой системы, обновить базу данных комнаты и обновить пользовательский интерфейс в конце. Это кажется особенно простой задачей, но я борюсь с правильным использованием Android и RxJava Schedulers.

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_welcome);

    this.loadingTextView = this.findViewById(R.id.tvLoading);

    this.subscription = Observable.just(0)
            .subscribeOn(Schedulers.io())
            .flatMap(ignore -> engine.checkEngineRequirements())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(ignore-> Log.e("glog", "Received on thread " + Thread.currentThread().getName()),
                    throwable -> Log.e("glog", "[WelcomeActivity.onCreate()]:" + throwable.getMessage()),
                    () -> {
                        this.loadingTextView.setText("Loaded");
                        Log.d("glog", "[WelcomeActivity] Launching new activity");
                        Intent intent = new Intent(this, PlayGameActivity.class);
                        this.startActivity(intent);
                    }
            );
}   

В checkEngineRequirements я загружаю файлы из файла и заполняю базу данных комнаты:

private Observable<Long> checkEngineRequirements() {
    return new OfflineDataLoad().load(this.context)                
            .observeOn(Schedulers.io())
            .flatMap(data -> this.dataRepository.addData(data));
}

public Observable<String> load(Context context) {
    return Observable.create(emitter -> {
        try {
            BufferedReader bufferedReader = new BufferedReader(
                    new InputStreamReader(
                            context.getAssets().open(DB_FILE_NAME), "UTF-8"));
            (...)
            while (lineAvailabe) {
                emitter.onNext(line)
            }
            emitter.onComplete();
        }
        catch (Exception e) {
            emitter.onError(e);
        }
    });
}

Мой источник данных (хранилище) реализован следующим образом:

@Override
public Observable<Long> addData(Data newDataItem) {
    return Observable.fromCallable(() -> this.dataDao.insertData(newDataItem));
}

Проблема в том, что событие onComplete никогда не вызывается. Есть идеи, что я делаю не так?

1 Ответ

0 голосов
/ 06 ноября 2018

На основании комментариев:

Общий способ устранения неисправностей - использовать операторы doOnXXXX и регистрировать различные события.

В этом случае описанный поток не подразумевал каких-либо бесконечных последовательностей (поскольку это очень часто встречается в запросах Room) и не делал ничего особенно сложного. Таким образом, остается сохраненная переменная subscription и тот факт, что основная часть кода выполняется в фоновом режиме при запуске из onCreate в главном потоке и может в конечном итоге снова вернуться в основной поток .

Это дает достаточно времени, чтобы пользовательский интерфейс был уничтожен, а вместе с ним и вышеупомянутый subscription. Конечно, конечно, применение doOnDispose() с регистрацией как можно ближе к конечному потребителю должно выявить, что это действительно так:

this.subscription = Observable.just(0)
        .subscribeOn(Schedulers.io())
        .flatMap(ignore -> engine.checkEngineRequirements())
        .observeOn(AndroidSchedulers.mainThread())
        // v---------------------------------v-----------------------------------v----
        .doOnDispose(() -> Log.e("glog", "[WelcomeActivity.onCreate()]: Disposed"))
        // ^---------------------------------^-----------------------------------^--
        .subscribe(ignore-> Log.e("glog", "Received on thread " 
                     + Thread.currentThread().getName()),
                throwable -> Log.e("glog", "[WelcomeActivity.onCreate()]:" 
                     + throwable.getMessage()),
                () -> {
                    this.loadingTextView.setText("Loaded");
                    Log.d("glog", "[WelcomeActivity] Launching new activity");
                    Intent intent = new Intent(this, PlayGameActivity.class);
                    this.startActivity(intent);
                }
        );
...