使用了 `onBackpressureDrop()` 但仍抛出 `MissingBackpressureException`

`onBackpressureDrop()` used and still `MissingBackpressureException` thrown

我有一个简单的 Android 应用程序。它有一个我可以触摸的全屏视图,并且显示了触摸。每 3 秒,将显示 3 秒间隔内所有触摸 (MotionEvents) 的计数和 'pointers'(对于多点触摸)的总计数。所有这些都是通过 RxAndroid 完成的。问题是,当我用 10 个手指敲击触摸屏时,我得到了一个 MissingBackpressureException - 我猜事件对于订阅者来说生成得太快了。我尝试添加 onBackpressureDrop() 但它没有任何改变。我想我遗漏了一些重要的东西,但是什么?

这是代码(我正在使用 Retrolambda,所以不要对 Android 上的 lambda 感到困惑,这是可能的)。 RX部分是onCreate().

public class MainActivity extends Activity {

    private ViewGroup viewGroup;

    private TextView touchCountIndicator;

    @Override
    public void onWindowFocusChanged(boolean hasFocus) {
        super.onWindowFocusChanged(hasFocus);

        if (hasFocus) {
            getWindow().getDecorView().setSystemUiVisibility(
                    View.SYSTEM_UI_FLAG_LAYOUT_STABLE
                            | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
                            | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
                            | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
                            | View.SYSTEM_UI_FLAG_FULLSCREEN
                            | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
        }
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);
        touchCountIndicator = (TextView) findViewById(R.id.touchCountIndicator);

        PublishSubject<MotionEvent> touchPublishSubject = PublishSubject.create();

        viewGroup = (ViewGroup) findViewById(android.R.id.content);
        viewGroup.setOnTouchListener((v, event) -> {
            touchPublishSubject.onNext(event);

            return true;
        });

        ViewObservable
                .bindView(viewGroup, touchPublishSubject)
                .onBackpressureDrop()
                .filter(motionEvent -> {
                    int action = motionEvent.getActionMasked();
                    return action == MotionEvent.ACTION_DOWN
                            || action == MotionEvent.ACTION_POINTER_DOWN
                            || action == MotionEvent.ACTION_MOVE;
                })
                .doOnNext(this::showTouch)
                .map(motionEvent -> MotionEvent.obtain(motionEvent))
                .buffer(3L, TimeUnit.SECONDS)
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(this::showTouchCount);
    }

    private void showTouch(MotionEvent motionEvent) {
        for (int i = 0; i < motionEvent.getPointerCount(); ++i) {
            float x = motionEvent.getX(i);
            float y = motionEvent.getY(i);

            ImageView touchIndicator = new ImageView(MainActivity.this);
            touchIndicator.setImageResource(R.drawable.touch);
            FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(10, 10);
            params.leftMargin = (int) (x - 5);
            params.topMargin = (int) (y - 5);
            viewGroup.addView(touchIndicator, params);

            touchIndicator
                    .animate()
                    .alpha(0F)
                    .scaleXBy(25F)
                    .scaleYBy(25F)
                    .setDuration(1000L)
                    .setListener(new AnimatorListenerAdapter() {

                        @Override
                        public void onAnimationEnd(Animator animation) {
                            viewGroup.removeView(touchIndicator);
                        }
                    });
        }
    }

    private void showTouchCount(List<MotionEvent> motionEvents) {
        Observable
                .from(motionEvents)
                .doOnNext(MotionEvent::recycle)
                .scan(0, (integer, motionEvent) -> integer + motionEvent.getPointerCount())
                .last()
                .subscribe(pointerCount -> {
                    touchCountIndicator.setText("" + motionEvents.size() + " " + pointerCount);

                    touchCountIndicator
                            .animate()
                            .alpha(0F)
                            .scaleXBy(15F)
                            .scaleYBy(15F)
                            .setDuration(1000L)
                            .setListener(new AnimatorListenerAdapter() {

                                @Override
                                public void onAnimationEnd(Animator animation) {
                                    touchCountIndicator.setText(null);
                                    touchCountIndicator.setAlpha(1F);
                                    touchCountIndicator.setScaleX(1F);
                                    touchCountIndicator.setScaleY(1F);
                                }
                            });
                });
    }
}

以及 XML 布局:

<FrameLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.test.rxandroid.MainActivity">

    <TextView
        android:id="@+id/touchCountIndicator"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"/>

</FrameLayout>

使用的主题是'android:Theme.Material.Light.NoActionBar.Fullscreen'(我是5.1.1)

堆栈跟踪部分是:

     Caused by: rx.exceptions.MissingBackpressureException
        at rx.internal.util.RxRingBuffer.onNext(RxRingBuffer.java:338)
        at rx.internal.operators.OperatorObserveOn$ObserveOnSubscriber.onNext(OperatorObserveOn.java:115)
        at rx.observers.SerializedObserver.onNext(SerializedObserver.java:159)
        at rx.observers.SerializedSubscriber.onNext(SerializedSubscriber.java:81)
        at rx.subjects.SubjectSubscriptionManager$SubjectObserver.onNext(SubjectSubscriptionManager.java:224)
        at rx.subjects.PublishSubject.onNext(PublishSubject.java:121)
        at com.test.rxandroid.MainActivity.lambda$onCreate[=12=](MainActivity.java:50)
        ...

您必须在绑定前对主题应用 onBackpressureDrop 运算符:

.bindView(viewGroup, touchPublishSubject.onBackpressureDrop()).filter(...)