我正在编写代码以在特定时刻从应用程序的屏幕保存位图。
我正在通过侦听某些组件的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%发生此错误。
解释是什么?如何解决?
“无法从此方法中添加或删除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,因此它将不再运行。