无法在onDraw内调用removeOnDrawListener

问题描述 投票:1回答:1

我正在编写代码以在特定时刻从应用程序的屏幕保存位图。

我正在通过侦听某些组件的onDraw()事件并检查条件是否为真来进行此操作

     @Override
     public void onDraw() {



        if (checkConditions()) {
                            Canvas canv = new Canvas(tmpBitmap);
                            canvasView.draw(canv);
                            saveBitmapToImage(tmpBitmap, Bitmap.CompressFormat.JPEG);
                            this.lastDraw = System.currentTimeMillis();

                            AsyncTask.THREAD_POOL_EXECUTOR.execute(() -> {
                            viewKonfetti.getViewTreeObserver().removeOnDrawListener(listener);

                        });                   
    }

                    }

但是有时候删除监听器时出现异常

    Fatal Exception: java.lang.IllegalStateException: Cannot call removeOnDrawListener inside of onDraw
           at android.view.ViewTreeObserver.removeOnDrawListener(ViewTreeObserver.java:736)
           at com.tomatedigital.lottogram.dialogs.ShuffleWinnerDialog$Shuffler$2.lambda$onParticleSystemEnded$1(ShuffleWinnerDialog.java:235)
           at com.tomatedigital.lottogram.dialogs.-$$Lambda$ShuffleWinnerDialog$Shuffler$2$vCYJiRVhO65xXIsicqZHHpw_34A.run(-.java:4)
           at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162)
           at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636)
           at java.lang.Thread.run(Thread.java:764)

这并不总是会发生,有时会在生产中(在许多不同的android设备上)发生。但是为什么?

我什至在使用新线程删除侦听器...

我测试过,甚至删除新线程也不能解决问题:仅在某些情况下,不会100%发生此错误。

解释是什么?如何解决?

android android-view android-drawable
1个回答
1
投票

“无法从此方法中添加或删除OnDrawListener侦听器。这是在documentation中,根据您的经验,原因可能是某种race condition,但我不知道详细信息。

我发现以下解决方法是:创建一个GlobalLayoutListener,然后在其中删除onDrawListener。请注意,因为在onDraw之前和之后都会多次调用GlobalLayoutListner。这是我的代码(这并不完美,因为由于线程不同,在将isDescriptionListenerAdded设置为false后,将多次调用GlobalLayoutListener,但这并不重要。请随时进行改进。)

    private var isDescriptionListenerAdded = false

fun setText(title: String, description: String, note: String) {
    titleText.text = title
    descriptionText.text = description

    var descriptionDrawListener = ViewTreeObserver.OnDrawListener {
        val maxLines = descriptionText.height / descriptionText.lineHeight
        descriptionText.maxLines = maxLines
        isDescriptionListenerAdded = true
    }

    descriptionText.viewTreeObserver.addOnDrawListener(descriptionDrawListener)
    descriptionText.viewTreeObserver.addOnGlobalLayoutListener {
        if (isDescriptionListenerAdded) {
            isDescriptionListenerAdded = false
            descriptionText.viewTreeObserver.removeOnDrawListener(descriptionDrawListener)
        }
    }
}

如您所见,设置文本后,它将计算可以完全显示多少行,并将maxLines设置为该值。完成后,isDescriptionListenerAdded设置为true,因此在GlobalLayoutListener中将其删除,并将其设置为false,因此它将不再运行。

© www.soinside.com 2019 - 2024. All rights reserved.