Android 动画只有在我将它从 UI 线程重新安排到 UI 线程时才有效

Android animation only works if I reschedule it from the UI thread to the UI thread

我执行网络调用,其中我

.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())

然后我将结果传递给一个 io.reactivex.function.Consumer,它试图为视图设置动画。

这些动画在我本地同步加载数据时有效,但在我引入此服务器调用时中断。

现在,当我为视图设置动画时,它根本不会更改任何属性,而是立即调用动画完成侦听器。

我确认我在 Looper.getMainLooper().isCurrentThread()

的主线程上

然而,我能够让动画再次运行的唯一方法是将其包装在 AndroidSchedulers.mainThread().scheduleDirect(() -> {})

如这段代码所示,实际上不应更改任何内容

 final Thread before = Thread.currentThread();
 AndroidSchedulers.mainThread().scheduleDirect(() -> {
     boolean nothingChanged = before == Thread.currentThread();
     //nothingChanged is true
 });

为什么我必须将动画重新安排到它已经在运行的线程上才能让它工作?

编辑:不涉及 RxJava,还有更奇怪的事情正在发生。 我删除了 RxJava,即使我将动画代码放在 onNavigationItemSelected() 中,问题仍在重现,当用户单击某些内容时 android 调用它,所以它肯定在正确的线程中。

我的动画是这样的。

alertBanner.clearAnimation();
alertBanner.animate()
        .alpha(0)
        .translationY(alertBanner.getHeight())
        .setDuration(500)
        .setListener(new AnimatorListenerBuilder().setOnAnimationEnd(animator -> {
            alertBanner.setVisibility(GONE);
        }))
        .start();

AnimatorListenerBuilder 只是一个实用程序 class,它包装了 AnimatorListener 并允许您只定义所需的回调。它适用于我的应用程序中的所有其他动画,并且几个月没有更改。

我明白了。这是一个竞争条件。

当用户点击按钮时,发生了两件事: 创建了一个新片段,并开始了动画。 但是,该片段有一个回调 onAttach(),除其他外,它会在我尝试设置动画的视图上调用 .clearAnimation()

通过将动画重新安排回主线程,我确保它发生在片段回调之后。

我通过从片段中删除回调并将该逻辑与启动动画的逻辑放在同一位置来解决它,从而允许我控制执行顺序。