【问题标题】:Cannot call removeOnDrawListener inside of onDraw无法在 onDraw 内调用 removeOnDrawListener
【发布时间】:2019-10-28 13:49:01
【问题描述】:

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

我通过监听某些组件的 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】:

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

    我找到的解决方法如下:创建一个 GlobalLayoutListener,然后删除那里的 onDrawListener。小心,因为 GlobalLayoutListner 会在 onDraw 之前和之后被调用很多次。这是我的代码(不完美,因为线程不同,在 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,就不会再运行了。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-10-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多