ANR in SurfaceView on specific devices only -- The only fix is a short sleep time ANR in SurfaceView on specific devices only -- The only fix is a short sleep time android android

ANR in SurfaceView on specific devices only -- The only fix is a short sleep time


What is currently working for me, although not really fixing the cause of the problem but fighting the symptoms superficially:

1. Removing Canvas operations

My render thread calls the custom method doDraw(Canvas canvas) on the SurfaceView subclass.

In that method, if I remove all calls to Canvas.drawBitmap(...), Canvas.drawRect(...) and other operations on the Canvas, the app does not freeze anymore.

A single call to Canvas.drawColor(int color) may be left in the method. And even costly operations like BitmapFactory.decodeResource(Resources res, int id, Options opts) and reading/writing to my internal Bitmap cache is fine. No freezes.

Obviously, without any drawing, the SurfaceView is not really helpful.

2. Sleeping 10ms in the render thread's run loop

The method that my render thread executes:

@Overridepublic void run() {    Canvas c;    while (mRunning) {        c = null;        try {            c = mSurfaceHolder.lockCanvas();            if (c != null) {                mSurface.doDraw(c);            }        }        finally {            if (c != null) {                try {                    mSurfaceHolder.unlockCanvasAndPost(c);                }                catch (Exception e) { }            }        }    }}

Simply adding a short sleep time within the loop (e.g. at the end) fixes all freezing on the LG G4:

while (mRunning) {    ...    try { Thread.sleep(10); } catch (Exception e) { }}

But who knows why this works and if this really fixes the problem (on all devices).

3. Printing something to System.out

The same thing that worked with Thread.sleep(...) above does also work with System.out.println("123"), strangely.

4. Delaying the start of the render thread by 10ms

This is how I start my render thread from within the SurfaceView:

@Overridepublic void surfaceCreated(SurfaceHolder surfaceHolder) {    mRenderThread = new MyThread(getHolder(), this);    mRenderThread.setRunning(true);    mRenderThread.start();}

When wrapping these three lines inside the following delayed execution, the app does not freeze anymore:

new Handler().postDelayed(new Runnable() {    @Override    public void run() {        ...    }}, 10);

This seems to be because there is only a presumable deadlock right in the beginning. If this is cleared (with the delayed execution), there is no other deadlock. The app runs just fine after that.

But when leaving the Activity, the app freezes again.

5. Just use a different device

Apart from the LG G4, Sony Xperia Z4, Huawei Ascend Mate 7, HTC M9 (and probably a few other devices), the app is working fine on thousands of devices.

Could this be a device-specific glitch? One would surely have heard about this ...


All these "solutions" are hacky. I wish there was a better solution -- and I bet there is!


Look at the ANR trace. Where does it appear to be stuck? ANRs mean the main UI thread is failing to respond, so what you're doing on the renderer thread is irrelevant unless the two are fighting over a lock.

The symptoms you're reporting sound like a race. If your main UI thread is stuck on, say, mRunningLock, it's conceivable that your renderer thread is only leaving it unlocked for a very short window. Adding the log message or sleep call gives the main thread an opportunity to wake up and do work before the renderer thread grabs it again.

(This doesn't actually make sense to me -- your code looks like it should be stalled waiting for lockCanvas() while awaiting the display refresh -- so you need to look at the thread trace in the ANR.)

FWIW, you don't need to synchronize on mSurfaceHolder. An early example did that, and every example since then has cloned it.

Once you get this sorted out, you may want to read about game loops.


Faced the same problem on xiaomi mi 5, android 6. Activity with canvas freezed on start and some time after exit from this activity.Solved this problem using lockHardwareCanvas() instead of lockCanvas(). This method not available in android 6 directly, so I called sHolder.getSurface().lockHardwareCanvas(); and sHolder.getSurface().unlockCanvasAndPost(canvas);Now no delays needed, works normal