`onBackpressureDrop()`使用并且仍然是`MissingBackpressureException`抛出

时间:2015-06-17 19:23:12

标签: android rx-java

我有一个简单的Android应用程序。它有一个我可以触摸的全屏视图,并显示触摸。每3秒钟,所有触摸的数量(MotionEvents)和指针的总数量' (用于多点触控)显示3秒间隔。所有这些都是通过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>

使用的主题是&#39; android:Theme.Material.Light.NoActionBar.Fullscreen&#39; (我在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$0(MainActivity.java:50)
        ...

1 个答案:

答案 0 :(得分:1)

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

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