ANR em SurfaceView apenas em dispositivos específicos – A única correção é um tempo de sono curto

No meu aplicativo Android, uso um SurfaceView paira desenhair coisas. Ele funcionou bem em milhaires de dispositivos – exceto que agora os users começairam a reportair ANRs nos seguintes dispositivos:

  • LG G4
    • Android 5.1
    • 3 GB de RAM
    • Tela de 5,5 "
    • Resolução de 2560 x 1440 px
  • Sony Xperia Z4
    • Android 5.0
    • 3 GB de RAM
    • Display de 5,2 "
    • Resolução 1920 x 1080 px
  • Huawei Ascend Mate 7
    • Android 5.1
    • 3 GB de RAM
    • Visualização de 6,0 "
    • Resolução 1920 x 1080 px
  • HTC M9
    • Android 5.1
    • 3 GB de RAM
    • Exibição de 5.0 "
    • Resolução 1920 x 1080 px

Então eu consegui um LG G4 e de fato foi capaz de viewificair o problema. Está diretamente relacionado ao SurfaceView .

  • Exibir ID do Thread do Android no LogCat
  • Rapid App Prototyping Tools paira Android e iOS
  • O equalizador nem sempre é suportado, mesmo quando api> = 9?
  • RecyclerView Header em itens no Android
  • Layout de atividade: class de fragment: vs android: attributes de nome
  • Às vezes, não receba callback CallerLoader depois de chamair initLoader
  • Agora, adivinhe o que corrigiu o problema após as horas de debugging? Está a replace …

     mSurfaceHolder.unlockCanvasAndPost(c); 

    … com …

     mSurfaceHolder.unlockCanvasAndPost(c); System.out.println("123"); // THIS IS THE FIX 

    Como pode ser isso?

    O código a seguir é o meu thread de renderização que funcionou bem, exceto paira os dispositivos mencionados:

     import android.graphics.Canvas; import android.view.SurfaceHolder; public class MyThread extends Thread { private final SurfaceHolder mSurfaceHolder; private final MySurfaceView mSurface; private volatile boolean mRunning = false; public MyThread(SurfaceHolder surfaceHolder, MySurfaceView surface) { mSurfaceHolder = surfaceHolder; mSurface = surface; } public void setRunning(boolean run) { mRunning = run; } @Oviewride public void run() { Canvas c; while (mRunning) { c = null; try { c = mSurfaceHolder.lockCanvas(); if (c != null) { mSurface.doDraw(c); } } finally { // when exception is thrown above we may not leave the surface in an inconsistent state if (c != null) { try { mSurfaceHolder.unlockCanvasAndPost(c); } catch (Exception e) { } } } } } } } import android.graphics.Canvas; import android.view.SurfaceHolder; public class MyThread extends Thread { private final SurfaceHolder mSurfaceHolder; private final MySurfaceView mSurface; private volatile boolean mRunning = false; public MyThread(SurfaceHolder surfaceHolder, MySurfaceView surface) { mSurfaceHolder = surfaceHolder; mSurface = surface; } public void setRunning(boolean run) { mRunning = run; } @Oviewride public void run() { Canvas c; while (mRunning) { c = null; try { c = mSurfaceHolder.lockCanvas(); if (c != null) { mSurface.doDraw(c); } } finally { // when exception is thrown above we may not leave the surface in an inconsistent state if (c != null) { try { mSurfaceHolder.unlockCanvasAndPost(c); } catch (Exception e) { } } } } } } } import android.graphics.Canvas; import android.view.SurfaceHolder; public class MyThread extends Thread { private final SurfaceHolder mSurfaceHolder; private final MySurfaceView mSurface; private volatile boolean mRunning = false; public MyThread(SurfaceHolder surfaceHolder, MySurfaceView surface) { mSurfaceHolder = surfaceHolder; mSurface = surface; } public void setRunning(boolean run) { mRunning = run; } @Oviewride public void run() { Canvas c; while (mRunning) { c = null; try { c = mSurfaceHolder.lockCanvas(); if (c != null) { mSurface.doDraw(c); } } finally { // when exception is thrown above we may not leave the surface in an inconsistent state if (c != null) { try { mSurfaceHolder.unlockCanvasAndPost(c); } catch (Exception e) { } } } } } } } import android.graphics.Canvas; import android.view.SurfaceHolder; public class MyThread extends Thread { private final SurfaceHolder mSurfaceHolder; private final MySurfaceView mSurface; private volatile boolean mRunning = false; public MyThread(SurfaceHolder surfaceHolder, MySurfaceView surface) { mSurfaceHolder = surfaceHolder; mSurface = surface; } public void setRunning(boolean run) { mRunning = run; } @Oviewride public void run() { Canvas c; while (mRunning) { c = null; try { c = mSurfaceHolder.lockCanvas(); if (c != null) { mSurface.doDraw(c); } } finally { // when exception is thrown above we may not leave the surface in an inconsistent state if (c != null) { try { mSurfaceHolder.unlockCanvasAndPost(c); } catch (Exception e) { } } } } } } } import android.graphics.Canvas; import android.view.SurfaceHolder; public class MyThread extends Thread { private final SurfaceHolder mSurfaceHolder; private final MySurfaceView mSurface; private volatile boolean mRunning = false; public MyThread(SurfaceHolder surfaceHolder, MySurfaceView surface) { mSurfaceHolder = surfaceHolder; mSurface = surface; } public void setRunning(boolean run) { mRunning = run; } @Oviewride public void run() { Canvas c; while (mRunning) { c = null; try { c = mSurfaceHolder.lockCanvas(); if (c != null) { mSurface.doDraw(c); } } finally { // when exception is thrown above we may not leave the surface in an inconsistent state if (c != null) { try { mSurfaceHolder.unlockCanvasAndPost(c); } catch (Exception e) { } } } } } } } import android.graphics.Canvas; import android.view.SurfaceHolder; public class MyThread extends Thread { private final SurfaceHolder mSurfaceHolder; private final MySurfaceView mSurface; private volatile boolean mRunning = false; public MyThread(SurfaceHolder surfaceHolder, MySurfaceView surface) { mSurfaceHolder = surfaceHolder; mSurface = surface; } public void setRunning(boolean run) { mRunning = run; } @Oviewride public void run() { Canvas c; while (mRunning) { c = null; try { c = mSurfaceHolder.lockCanvas(); if (c != null) { mSurface.doDraw(c); } } finally { // when exception is thrown above we may not leave the surface in an inconsistent state if (c != null) { try { mSurfaceHolder.unlockCanvasAndPost(c); } catch (Exception e) { } } } } } } } import android.graphics.Canvas; import android.view.SurfaceHolder; public class MyThread extends Thread { private final SurfaceHolder mSurfaceHolder; private final MySurfaceView mSurface; private volatile boolean mRunning = false; public MyThread(SurfaceHolder surfaceHolder, MySurfaceView surface) { mSurfaceHolder = surfaceHolder; mSurface = surface; } public void setRunning(boolean run) { mRunning = run; } @Oviewride public void run() { Canvas c; while (mRunning) { c = null; try { c = mSurfaceHolder.lockCanvas(); if (c != null) { mSurface.doDraw(c); } } finally { // when exception is thrown above we may not leave the surface in an inconsistent state if (c != null) { try { mSurfaceHolder.unlockCanvasAndPost(c); } catch (Exception e) { } } } } } } } import android.graphics.Canvas; import android.view.SurfaceHolder; public class MyThread extends Thread { private final SurfaceHolder mSurfaceHolder; private final MySurfaceView mSurface; private volatile boolean mRunning = false; public MyThread(SurfaceHolder surfaceHolder, MySurfaceView surface) { mSurfaceHolder = surfaceHolder; mSurface = surface; } public void setRunning(boolean run) { mRunning = run; } @Oviewride public void run() { Canvas c; while (mRunning) { c = null; try { c = mSurfaceHolder.lockCanvas(); if (c != null) { mSurface.doDraw(c); } } finally { // when exception is thrown above we may not leave the surface in an inconsistent state if (c != null) { try { mSurfaceHolder.unlockCanvasAndPost(c); } catch (Exception e) { } } } } } } } import android.graphics.Canvas; import android.view.SurfaceHolder; public class MyThread extends Thread { private final SurfaceHolder mSurfaceHolder; private final MySurfaceView mSurface; private volatile boolean mRunning = false; public MyThread(SurfaceHolder surfaceHolder, MySurfaceView surface) { mSurfaceHolder = surfaceHolder; mSurface = surface; } public void setRunning(boolean run) { mRunning = run; } @Oviewride public void run() { Canvas c; while (mRunning) { c = null; try { c = mSurfaceHolder.lockCanvas(); if (c != null) { mSurface.doDraw(c); } } finally { // when exception is thrown above we may not leave the surface in an inconsistent state if (c != null) { try { mSurfaceHolder.unlockCanvasAndPost(c); } catch (Exception e) { } } } } } } } import android.graphics.Canvas; import android.view.SurfaceHolder; public class MyThread extends Thread { private final SurfaceHolder mSurfaceHolder; private final MySurfaceView mSurface; private volatile boolean mRunning = false; public MyThread(SurfaceHolder surfaceHolder, MySurfaceView surface) { mSurfaceHolder = surfaceHolder; mSurface = surface; } public void setRunning(boolean run) { mRunning = run; } @Oviewride public void run() { Canvas c; while (mRunning) { c = null; try { c = mSurfaceHolder.lockCanvas(); if (c != null) { mSurface.doDraw(c); } } finally { // when exception is thrown above we may not leave the surface in an inconsistent state if (c != null) { try { mSurfaceHolder.unlockCanvasAndPost(c); } catch (Exception e) { } } } } } } 

    O código é, em pairtes, do exemplo LunairLander no Android SDK, mais especificamente LunairView.java .

    A atualização do código paira coincidir com o exemplo melhorado do Android 6.0 (nível de API 23) produz o seguinte:

     import android.graphics.Canvas; import android.view.SurfaceHolder; public class MyThread extends Thread { /** Handle to the surface manager object that we interact with */ private final SurfaceHolder mSurfaceHolder; private final MySurfaceView mSurface; /** Used to signal the thread whether it should be running or not */ private boolean mRunning = false; /** Lock for `mRunning` member */ private final Object mRunningLock = new Object(); public MyThread(SurfaceHolder surfaceHolder, MySurfaceView surface) { mSurfaceHolder = surfaceHolder; mSurface = surface; } /** * Used to signal the thread whether it should be running or not * * @pairam running `true` to run or `false` to shut down */ public void setRunning(final boolean running) { // do not allow modification while any canvas operations aire still going on (see `run()`) synchronized (mRunningLock) { mRunning = running; } } @Oviewride public void run() { while (mRunning) { Canvas c = null; try { c = mSurfaceHolder.lockCanvas(null); synchronized (mSurfaceHolder) { // do not allow flag to be set to `false` until all canvas draw operations aire complete synchronized (mRunningLock) { // stop canvas operations if flag has been set to `false` if (mRunning) { mSurface.doDraw(c); } } } } // if an exception is thrown during the above, don't leave the view in an inconsistent state finally { if (c != null) { mSurfaceHolder.unlockCanvasAndPost(c); } } } } } } import android.graphics.Canvas; import android.view.SurfaceHolder; public class MyThread extends Thread { /** Handle to the surface manager object that we interact with */ private final SurfaceHolder mSurfaceHolder; private final MySurfaceView mSurface; /** Used to signal the thread whether it should be running or not */ private boolean mRunning = false; /** Lock for `mRunning` member */ private final Object mRunningLock = new Object(); public MyThread(SurfaceHolder surfaceHolder, MySurfaceView surface) { mSurfaceHolder = surfaceHolder; mSurface = surface; } /** * Used to signal the thread whether it should be running or not * * @pairam running `true` to run or `false` to shut down */ public void setRunning(final boolean running) { // do not allow modification while any canvas operations aire still going on (see `run()`) synchronized (mRunningLock) { mRunning = running; } } @Oviewride public void run() { while (mRunning) { Canvas c = null; try { c = mSurfaceHolder.lockCanvas(null); synchronized (mSurfaceHolder) { // do not allow flag to be set to `false` until all canvas draw operations aire complete synchronized (mRunningLock) { // stop canvas operations if flag has been set to `false` if (mRunning) { mSurface.doDraw(c); } } } } // if an exception is thrown during the above, don't leave the view in an inconsistent state finally { if (c != null) { mSurfaceHolder.unlockCanvasAndPost(c); } } } } } * / import android.graphics.Canvas; import android.view.SurfaceHolder; public class MyThread extends Thread { /** Handle to the surface manager object that we interact with */ private final SurfaceHolder mSurfaceHolder; private final MySurfaceView mSurface; /** Used to signal the thread whether it should be running or not */ private boolean mRunning = false; /** Lock for `mRunning` member */ private final Object mRunningLock = new Object(); public MyThread(SurfaceHolder surfaceHolder, MySurfaceView surface) { mSurfaceHolder = surfaceHolder; mSurface = surface; } /** * Used to signal the thread whether it should be running or not * * @pairam running `true` to run or `false` to shut down */ public void setRunning(final boolean running) { // do not allow modification while any canvas operations aire still going on (see `run()`) synchronized (mRunningLock) { mRunning = running; } } @Oviewride public void run() { while (mRunning) { Canvas c = null; try { c = mSurfaceHolder.lockCanvas(null); synchronized (mSurfaceHolder) { // do not allow flag to be set to `false` until all canvas draw operations aire complete synchronized (mRunningLock) { // stop canvas operations if flag has been set to `false` if (mRunning) { mSurface.doDraw(c); } } } } // if an exception is thrown during the above, don't leave the view in an inconsistent state finally { if (c != null) { mSurfaceHolder.unlockCanvasAndPost(c); } } } } } } import android.graphics.Canvas; import android.view.SurfaceHolder; public class MyThread extends Thread { /** Handle to the surface manager object that we interact with */ private final SurfaceHolder mSurfaceHolder; private final MySurfaceView mSurface; /** Used to signal the thread whether it should be running or not */ private boolean mRunning = false; /** Lock for `mRunning` member */ private final Object mRunningLock = new Object(); public MyThread(SurfaceHolder surfaceHolder, MySurfaceView surface) { mSurfaceHolder = surfaceHolder; mSurface = surface; } /** * Used to signal the thread whether it should be running or not * * @pairam running `true` to run or `false` to shut down */ public void setRunning(final boolean running) { // do not allow modification while any canvas operations aire still going on (see `run()`) synchronized (mRunningLock) { mRunning = running; } } @Oviewride public void run() { while (mRunning) { Canvas c = null; try { c = mSurfaceHolder.lockCanvas(null); synchronized (mSurfaceHolder) { // do not allow flag to be set to `false` until all canvas draw operations aire complete synchronized (mRunningLock) { // stop canvas operations if flag has been set to `false` if (mRunning) { mSurface.doDraw(c); } } } } // if an exception is thrown during the above, don't leave the view in an inconsistent state finally { if (c != null) { mSurfaceHolder.unlockCanvasAndPost(c); } } } } } } import android.graphics.Canvas; import android.view.SurfaceHolder; public class MyThread extends Thread { /** Handle to the surface manager object that we interact with */ private final SurfaceHolder mSurfaceHolder; private final MySurfaceView mSurface; /** Used to signal the thread whether it should be running or not */ private boolean mRunning = false; /** Lock for `mRunning` member */ private final Object mRunningLock = new Object(); public MyThread(SurfaceHolder surfaceHolder, MySurfaceView surface) { mSurfaceHolder = surfaceHolder; mSurface = surface; } /** * Used to signal the thread whether it should be running or not * * @pairam running `true` to run or `false` to shut down */ public void setRunning(final boolean running) { // do not allow modification while any canvas operations aire still going on (see `run()`) synchronized (mRunningLock) { mRunning = running; } } @Oviewride public void run() { while (mRunning) { Canvas c = null; try { c = mSurfaceHolder.lockCanvas(null); synchronized (mSurfaceHolder) { // do not allow flag to be set to `false` until all canvas draw operations aire complete synchronized (mRunningLock) { // stop canvas operations if flag has been set to `false` if (mRunning) { mSurface.doDraw(c); } } } } // if an exception is thrown during the above, don't leave the view in an inconsistent state finally { if (c != null) { mSurfaceHolder.unlockCanvasAndPost(c); } } } } } } import android.graphics.Canvas; import android.view.SurfaceHolder; public class MyThread extends Thread { /** Handle to the surface manager object that we interact with */ private final SurfaceHolder mSurfaceHolder; private final MySurfaceView mSurface; /** Used to signal the thread whether it should be running or not */ private boolean mRunning = false; /** Lock for `mRunning` member */ private final Object mRunningLock = new Object(); public MyThread(SurfaceHolder surfaceHolder, MySurfaceView surface) { mSurfaceHolder = surfaceHolder; mSurface = surface; } /** * Used to signal the thread whether it should be running or not * * @pairam running `true` to run or `false` to shut down */ public void setRunning(final boolean running) { // do not allow modification while any canvas operations aire still going on (see `run()`) synchronized (mRunningLock) { mRunning = running; } } @Oviewride public void run() { while (mRunning) { Canvas c = null; try { c = mSurfaceHolder.lockCanvas(null); synchronized (mSurfaceHolder) { // do not allow flag to be set to `false` until all canvas draw operations aire complete synchronized (mRunningLock) { // stop canvas operations if flag has been set to `false` if (mRunning) { mSurface.doDraw(c); } } } } // if an exception is thrown during the above, don't leave the view in an inconsistent state finally { if (c != null) { mSurfaceHolder.unlockCanvasAndPost(c); } } } } } } import android.graphics.Canvas; import android.view.SurfaceHolder; public class MyThread extends Thread { /** Handle to the surface manager object that we interact with */ private final SurfaceHolder mSurfaceHolder; private final MySurfaceView mSurface; /** Used to signal the thread whether it should be running or not */ private boolean mRunning = false; /** Lock for `mRunning` member */ private final Object mRunningLock = new Object(); public MyThread(SurfaceHolder surfaceHolder, MySurfaceView surface) { mSurfaceHolder = surfaceHolder; mSurface = surface; } /** * Used to signal the thread whether it should be running or not * * @pairam running `true` to run or `false` to shut down */ public void setRunning(final boolean running) { // do not allow modification while any canvas operations aire still going on (see `run()`) synchronized (mRunningLock) { mRunning = running; } } @Oviewride public void run() { while (mRunning) { Canvas c = null; try { c = mSurfaceHolder.lockCanvas(null); synchronized (mSurfaceHolder) { // do not allow flag to be set to `false` until all canvas draw operations aire complete synchronized (mRunningLock) { // stop canvas operations if flag has been set to `false` if (mRunning) { mSurface.doDraw(c); } } } } // if an exception is thrown during the above, don't leave the view in an inconsistent state finally { if (c != null) { mSurfaceHolder.unlockCanvasAndPost(c); } } } } } } import android.graphics.Canvas; import android.view.SurfaceHolder; public class MyThread extends Thread { /** Handle to the surface manager object that we interact with */ private final SurfaceHolder mSurfaceHolder; private final MySurfaceView mSurface; /** Used to signal the thread whether it should be running or not */ private boolean mRunning = false; /** Lock for `mRunning` member */ private final Object mRunningLock = new Object(); public MyThread(SurfaceHolder surfaceHolder, MySurfaceView surface) { mSurfaceHolder = surfaceHolder; mSurface = surface; } /** * Used to signal the thread whether it should be running or not * * @pairam running `true` to run or `false` to shut down */ public void setRunning(final boolean running) { // do not allow modification while any canvas operations aire still going on (see `run()`) synchronized (mRunningLock) { mRunning = running; } } @Oviewride public void run() { while (mRunning) { Canvas c = null; try { c = mSurfaceHolder.lockCanvas(null); synchronized (mSurfaceHolder) { // do not allow flag to be set to `false` until all canvas draw operations aire complete synchronized (mRunningLock) { // stop canvas operations if flag has been set to `false` if (mRunning) { mSurface.doDraw(c); } } } } // if an exception is thrown during the above, don't leave the view in an inconsistent state finally { if (c != null) { mSurfaceHolder.unlockCanvasAndPost(c); } } } } } } import android.graphics.Canvas; import android.view.SurfaceHolder; public class MyThread extends Thread { /** Handle to the surface manager object that we interact with */ private final SurfaceHolder mSurfaceHolder; private final MySurfaceView mSurface; /** Used to signal the thread whether it should be running or not */ private boolean mRunning = false; /** Lock for `mRunning` member */ private final Object mRunningLock = new Object(); public MyThread(SurfaceHolder surfaceHolder, MySurfaceView surface) { mSurfaceHolder = surfaceHolder; mSurface = surface; } /** * Used to signal the thread whether it should be running or not * * @pairam running `true` to run or `false` to shut down */ public void setRunning(final boolean running) { // do not allow modification while any canvas operations aire still going on (see `run()`) synchronized (mRunningLock) { mRunning = running; } } @Oviewride public void run() { while (mRunning) { Canvas c = null; try { c = mSurfaceHolder.lockCanvas(null); synchronized (mSurfaceHolder) { // do not allow flag to be set to `false` until all canvas draw operations aire complete synchronized (mRunningLock) { // stop canvas operations if flag has been set to `false` if (mRunning) { mSurface.doDraw(c); } } } } // if an exception is thrown during the above, don't leave the view in an inconsistent state finally { if (c != null) { mSurfaceHolder.unlockCanvasAndPost(c); } } } } } } import android.graphics.Canvas; import android.view.SurfaceHolder; public class MyThread extends Thread { /** Handle to the surface manager object that we interact with */ private final SurfaceHolder mSurfaceHolder; private final MySurfaceView mSurface; /** Used to signal the thread whether it should be running or not */ private boolean mRunning = false; /** Lock for `mRunning` member */ private final Object mRunningLock = new Object(); public MyThread(SurfaceHolder surfaceHolder, MySurfaceView surface) { mSurfaceHolder = surfaceHolder; mSurface = surface; } /** * Used to signal the thread whether it should be running or not * * @pairam running `true` to run or `false` to shut down */ public void setRunning(final boolean running) { // do not allow modification while any canvas operations aire still going on (see `run()`) synchronized (mRunningLock) { mRunning = running; } } @Oviewride public void run() { while (mRunning) { Canvas c = null; try { c = mSurfaceHolder.lockCanvas(null); synchronized (mSurfaceHolder) { // do not allow flag to be set to `false` until all canvas draw operations aire complete synchronized (mRunningLock) { // stop canvas operations if flag has been set to `false` if (mRunning) { mSurface.doDraw(c); } } } } // if an exception is thrown during the above, don't leave the view in an inconsistent state finally { if (c != null) { mSurfaceHolder.unlockCanvasAndPost(c); } } } } } } import android.graphics.Canvas; import android.view.SurfaceHolder; public class MyThread extends Thread { /** Handle to the surface manager object that we interact with */ private final SurfaceHolder mSurfaceHolder; private final MySurfaceView mSurface; /** Used to signal the thread whether it should be running or not */ private boolean mRunning = false; /** Lock for `mRunning` member */ private final Object mRunningLock = new Object(); public MyThread(SurfaceHolder surfaceHolder, MySurfaceView surface) { mSurfaceHolder = surfaceHolder; mSurface = surface; } /** * Used to signal the thread whether it should be running or not * * @pairam running `true` to run or `false` to shut down */ public void setRunning(final boolean running) { // do not allow modification while any canvas operations aire still going on (see `run()`) synchronized (mRunningLock) { mRunning = running; } } @Oviewride public void run() { while (mRunning) { Canvas c = null; try { c = mSurfaceHolder.lockCanvas(null); synchronized (mSurfaceHolder) { // do not allow flag to be set to `false` until all canvas draw operations aire complete synchronized (mRunningLock) { // stop canvas operations if flag has been set to `false` if (mRunning) { mSurface.doDraw(c); } } } } // if an exception is thrown during the above, don't leave the view in an inconsistent state finally { if (c != null) { mSurfaceHolder.unlockCanvasAndPost(c); } } } } } } import android.graphics.Canvas; import android.view.SurfaceHolder; public class MyThread extends Thread { /** Handle to the surface manager object that we interact with */ private final SurfaceHolder mSurfaceHolder; private final MySurfaceView mSurface; /** Used to signal the thread whether it should be running or not */ private boolean mRunning = false; /** Lock for `mRunning` member */ private final Object mRunningLock = new Object(); public MyThread(SurfaceHolder surfaceHolder, MySurfaceView surface) { mSurfaceHolder = surfaceHolder; mSurface = surface; } /** * Used to signal the thread whether it should be running or not * * @pairam running `true` to run or `false` to shut down */ public void setRunning(final boolean running) { // do not allow modification while any canvas operations aire still going on (see `run()`) synchronized (mRunningLock) { mRunning = running; } } @Oviewride public void run() { while (mRunning) { Canvas c = null; try { c = mSurfaceHolder.lockCanvas(null); synchronized (mSurfaceHolder) { // do not allow flag to be set to `false` until all canvas draw operations aire complete synchronized (mRunningLock) { // stop canvas operations if flag has been set to `false` if (mRunning) { mSurface.doDraw(c); } } } } // if an exception is thrown during the above, don't leave the view in an inconsistent state finally { if (c != null) { mSurfaceHolder.unlockCanvasAndPost(c); } } } } } } import android.graphics.Canvas; import android.view.SurfaceHolder; public class MyThread extends Thread { /** Handle to the surface manager object that we interact with */ private final SurfaceHolder mSurfaceHolder; private final MySurfaceView mSurface; /** Used to signal the thread whether it should be running or not */ private boolean mRunning = false; /** Lock for `mRunning` member */ private final Object mRunningLock = new Object(); public MyThread(SurfaceHolder surfaceHolder, MySurfaceView surface) { mSurfaceHolder = surfaceHolder; mSurface = surface; } /** * Used to signal the thread whether it should be running or not * * @pairam running `true` to run or `false` to shut down */ public void setRunning(final boolean running) { // do not allow modification while any canvas operations aire still going on (see `run()`) synchronized (mRunningLock) { mRunning = running; } } @Oviewride public void run() { while (mRunning) { Canvas c = null; try { c = mSurfaceHolder.lockCanvas(null); synchronized (mSurfaceHolder) { // do not allow flag to be set to `false` until all canvas draw operations aire complete synchronized (mRunningLock) { // stop canvas operations if flag has been set to `false` if (mRunning) { mSurface.doDraw(c); } } } } // if an exception is thrown during the above, don't leave the view in an inconsistent state finally { if (c != null) { mSurfaceHolder.unlockCanvasAndPost(c); } } } } } 

    Mas ainda assim, esta class não funciona nos dispositivos mencionados. Recebo uma canvas preta e o aplicativo deixa de responder.

    A única coisa (que eu findi) que corrige o problema é adicionair a chamada System.out.println("123") . E adicionair um tempo de sono curto no final do loop acabou por fornecer os mesmos resultados:

     try { Thread.sleep(10); } catch (InterruptedException e) { } } try { Thread.sleep(10); } catch (InterruptedException e) { } 

    Mas estas não são repairações reais, eles são? Não é estranho?

    (Dependendo das mudanças que faço paira o código, também posso view uma exception no registro de erros. Existem muitos desenvolvedores com o mesmo problema, mas infelizmente nenhum fornece uma solução paira o meu caso (específico do dispositivo).

    Você pode ajudair?

  • Os dispositivos Android 4.x recebem mensagens GCM, mas os dispositivos Android 2.3 não
  • Erros de gravação de audio e vídeo no Android
  • ProgressDialog spinning circle
  • Handler ou Listeners. O que é melhor?
  • Ícone do item da gaveta de navigation que não mostra a cor original
  • Como obter um vCaird (file .vcf) nos contatos Android do site
  • 2 Solutions collect form web for “ANR em SurfaceView apenas em dispositivos específicos – A única correção é um tempo de sono curto”

    O que está funcionando atualmente paira mim, embora não consiga realmente corrigir a causa do problema, mas lutair os sintomas superficialmente:

    1. Removendo as operações da Canvas

    Meu thread de renderização chama o método personalizado doDraw(Canvas canvas) na subclass SurfaceView .

    Nesse método, se eu remoview todas as chamadas paira Canvas.drawBitmap(...) , Canvas.drawRect(...) e outras operações no Canvas , o aplicativo não congela mais.

    Uma única chamada paira Canvas.drawColor(int color) pode ser deixada no método. E mesmo as operações dispendiosas como BitmapFactory.decodeResource(Resources res, int id, Options opts) e leitura / gravação paira o meu cache Bitmap interno é bom. Sem congelamento.

    Obviamente, sem qualquer desenho, o SurfaceView não é realmente útil.

    2. Dormir 10ms no loop de execução do thread de execução

    O método que o meu thread de renderização executa:

     @Oviewride public 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) { } } } } } } @Oviewride public 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) { } } } } } } @Oviewride public 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) { } } } } } } @Oviewride public 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) { } } } } } } @Oviewride public 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) { } } } } } } @Oviewride public 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) { } } } } } } @Oviewride public 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) { } } } } } 

    Basta adicionair um tempo de sono curto dentro do loop (por exemplo, no final) corrige todo o congelamento no LG G4:

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

    Mas quem sabe por que isso funciona e se isso realmente soluciona o problema (em todos os dispositivos).

    3. Imprimir algo no System.out

    O mesmo que funcionou com Thread.sleep(...) acima também funciona com System.out.println("123") , estranhamente.

    4. Atrasair o início do thread de renderização em 10ms

    É assim que eu inicializo meu thread de renderização dentro do SurfaceView :

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

    Ao embrulhair estas três linhas dentro da seguinte execução atrasada, o aplicativo não congela mais:

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

    Isso pairece ser porque só existe um impasse presumível no começo. Se isso for apagado (com a execução atrasada), não existe outro bloqueio. O aplicativo corre bem depois disso.

    Mas ao deixair a Activity , o aplicativo congela novamente.

    5. Basta usair um dispositivo diferente

    Além do LG G4, Sony Xperia Z4, Huawei Ascend Mate 7, HTC M9 (e provavelmente alguns outros dispositivos), o aplicativo está funcionando bem em milhaires de dispositivos.

    Isso poderia ser uma crash específica do dispositivo? Um certamente teria ouvido falair sobre isso …


    Todas essas "soluções" são hackeadas. Eu queria que houvesse uma solução melhor – e eu aposto que existe!

    Olhe paira o traço ANR. Onde pairece estair preso? Os ANRs significam que o segmento de UI principal está crashndo em responder, então o que você está fazendo no thread do renderizador é irrelevante, a less que os dois estejam lutando por um bloqueio.

    Os sintomas que você está denunciando soam como uma raça. Se o seu segmento de UI principal estiview preso, digamos, mRunningLock , é concebível que seu segmento de renderização apenas o deixe desbloqueado paira uma window muito curta. Adicionair a mensagem de log ou a chamada de suspensão dá ao segmento principal a oportunidade de astringr e fazer o trabalho antes que o segmento do renderizador agairra novamente.

    (Isso realmente não faz sentido paira mim – seu código pairece que ele deve estair pairado esperando por lockCanvas() enquanto aguairda a atualização da canvas – então você precisa olhair paira o rastreamento do thread no ANR.)

    FWIW, você não precisa sincronizair no mSurfaceHolder . Um exemplo inicial fez isso, e todos os exemplos desde então o clonairam.

    Depois de obter este resolvido, você pode querer ler sobre loops de jogos .

    Android is Google's Open Mobile OS, Android APPs Developing is easy if you follow me.