ANR in SurfaceView method “onTouchEvent(…)” on Android

核能气质少年 提交于 2019-12-05 22:09:53

The ANR is happening because your onTouchEvent() method is synchronizing on a lock held by tid=18, an unnamed thread known only as Thread-14297.

Many people follow a pattern where, at the point they lock the SurfaceView canvas, they also lock the SurfaceHolder object. It's a bad idea to synchronize on objects with public visibility, and an even worse idea to synchronize on objects shared with the GUI framework, so it's sad that this pattern persists. (But I digress.)

You're drawing in an overridden onDraw() method, which doesn't make sense if you're drawing from a renderer thread -- the onDraw() method is used by the View hierarchy and would be called from the UI thread, but here it's clearly being called from elsewhere. You should call it something else, maybe just myDraw(). (But I digress.)

Thread-14297 is in the "suspended" state, which means it was executing but stopped when the stack trace was captured. Since the topmost frame is a native method -- which don't get suspended by the VM -- it was probably entering or exiting the frame. The system and user time for the thread, shown in ticks as "utm=" and "stm=" values, are fairly low, suggesting that it's not doing excessive CPU work. Unless, of course, your render thread is a one-shot, in which case it was fairly busy (and may not be done yet).

The good news is that you don't appear to be deadlocked. The render thread is just running slowly. Or, perhaps, you have a loop that is failing to exit (though none is apparent from the posted code). On a slow device, with lots of other activity on the system, and a big mCards list, it could get starved for CPU and fail to respond quickly. Assuming you're following the common pattern and locking the SurfaceHolder when you grab the Canvas, your onTouchEvent() is going to lock up the UI thread for the full duration of the draw. The ANR summary in logcat usually lists recent thread activity levels; if you have access to that, the information could tell you how busy the render thread has been.

Not all ANRs are fatal. If the app becomes permanently unresponsive, that's very different from a temporary ANR that clears up when the user hits "wait". Do you know which kind this is?

You need to:

  1. Re-evaluate your data synchronization. Use shorter windows and maybe a read-write lock to pass data around. Poke around in java.util.concurrent. Stalling the UI thread for an extended period is bad.
  2. Determine why your rendering seems to be taking a long time, and whether it's just running slowly or spinning forever.
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!