【问题标题】:RxJava runs on same blocking UI Thread and doesn't show AlertDialogRxJava 在相同的阻塞 UI 线程上运行并且不显示 AlertDialog
【发布时间】:2018-03-20 08:08:39
【问题描述】:

我正在尝试使用 RxJava 在加载某些方法期间显示 AlertDialog。它不起作用,UI 被阻塞了 2 秒,当使用 Debugger 单步执行它时,调试器显示它在 UI 线程上运行。我添加了 Schedulers.IO,我做错了什么?

boolean initialize() {
    try {
        Thread.sleep(2000);
    } catch (InterruptedException e) {
    }
    return true;
}

public AlertDialog showSomePopup(Context context, String msg) {
    return new AlertDialog.Builder(context)
            .setTitle("Loading...")
            .setMessage(msg)
            .setPositiveButton("Ok", null)
            .show();
}

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

    final AlertDialog dialog = showSomePopup(this, "Waiting ..");

    Single.just(initialize())
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(new Consumer<Boolean>() {
        @Override
        public void accept(@NonNull Boolean aBoolean) throws Exception {
            dialog.dismiss();
        }
    });
}

【问题讨论】:

  • 使用 Observable.interval(2000, TimeUnit.SECONDS) 代替 Single.just

标签: android multithreading rx-java


【解决方案1】:

问题在于 .subscribe() 直到 initialize() 方法没有发出时才会被调用(即当您使用 .just() 时,直到 initialize() 没有返回。

【讨论】:

  • 那我该如何重写呢?
  • 正如@Hans Wurst 建议的那样。
  • 澄清一下,即使我的回答描述的是真的,这也不是问题的解决方案。
【解决方案2】:

您的初始化函数应该返回调用者可以订阅的Observable。在您的情况下,您通过调用 initialize() 开始序列,然后等待结果返回。你应该做什么:

Single<Boolean> initialize() {
    return Single.fromCallable(new Callable<Boolean>() {
       @Override
        public Boolean call() throws Exception {
            try {
                Thread.sleep(2000);
                return true;
            } catch (Exception ex) {
                return false;
            }
        }
    });
}

现在您可以像这样输入您拥有的代码:

initialize()
    .subscribeOn(Schedulers.io())
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe(new Consumer<Boolean>() {
        @Override
        public void accept(@io.reactivex.annotations.NonNull Boolean aBoolean) throws Exception {
            if(aBoolean == true) {
                dialog.dismiss();
            }
        }
    });

它会按照你的意愿工作。

【讨论】:

  • 从 observable 使用 create 有点过头了。 Observable 确实为这种类型提供了其他工厂方法,例如“defer”或“fromCallable”。此外,Completeable 更适合此用例。
  • 将其更改为可完成。虽然作者提到他希望从后台获取数据,但 Observable 可能适合他的情况。但你是对的:)
  • 没有阅读有关获取数据的内容。只需调用一个返回 true/false 的方法。如果应该获取数据,建议使用 Single 来处理这种行为。
  • 谢谢大家。但是初始化方法确实返回一个布尔值。所以我应该把它改成 new Consumer() 我想?
  • 如果你认为真/假对你的返回值很重要,是的。然后在 initialize 中使用 Single 并使用 Consumer&lt;Boolean&gt; 订阅
【解决方案3】:

作为@Xavier Rubio Jansana 正确答案的后续回答。 将 Completeable 用于完成或失败的方法。

Completable.fromAction(() -> {
        init();
    })
            .subscribeOn(Schedulers.io())
            //.observeOn() AndroidScheduler
            .subscribe(() -> {
               // dismiss action
});

private void init() throws Exception {
    Thread.sleep(1000);
}

【讨论】:

    【解决方案4】:

    正确答案如下:

    Single<Boolean> initialize() {
        return Single.create(new SingleOnSubscribe<Boolean>() {
            @Override
            public void subscribe(@NonNull SingleEmitter<Boolean> e) throws Exception {
                e.onSuccess(true);
            }
        });
    }
    
    public AlertDialog showSomePopup(Context context, String msg) {
        return new AlertDialog.Builder(context)
                .setTitle("Loading...")
                .setMessage(msg)
                .setPositiveButton("Ok", null).create();
    }
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    
        final AlertDialog dialog = showSomePopup(this, "lol");
        dialog.show();
    
        initialize().subscribeOn(Schedulers.io())
                .doOnSuccess(new Consumer<Boolean>() {
                    @Override
                    public void accept(@NonNull Boolean aBoolean) throws Exception {
                        dialog.dismiss();
                    }
                })
                .subscribe();
    }
    

    【讨论】:

      【解决方案5】:

      在创建 AlertDialog() 时缺少 AlertDialog create()。在显示之前添加。

      return new AlertDialog.Builder(context)
              .setTitle("Loading...")
              .setMessage(msg)
              .setPositiveButton("Ok", null)
              .create()
              .show();
      

      【讨论】:

        猜你喜欢
        • 2018-03-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-09-12
        • 2017-03-07
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多