2012-10-06 15 views
5

He creado mi primer fondo de pantalla de implementación en vivo en un hilo separado. Así que ahora tengo un WallpaperService y mi WallpaperPainter que hace el trabajo. El problema es que obtengo un IllegalArgumentException en el método unlockCanvasAndPost en algunos dispositivos (Samsung Note es el indicado). He leído todas las recomendaciones que pude encontrar pero no pude solucionar ese error. Parece que se llama al unlockCanvasAndPost cuando se destruye la superficie, por lo que el lienzo no es válido. Aquí está lo esencial de código:IllegalArgumentException en unlockCanvasAndPost (android live wallpaper)

En el servicio de fondo de pantalla:

@Override 
    public void onSurfaceChanged(SurfaceHolder holder, int format, int width, 
      int height) { 
     super.onSurfaceChanged(holder, format, width, height); 
     painting.setSurfaceSize(width, height); 
    } 

    @Override 
    public void onSurfaceCreated(SurfaceHolder holder) { 
     super.onSurfaceCreated(holder); 
     painting.start(); 
    } 

    @Override 
    public void onSurfaceDestroyed(SurfaceHolder holder) { 
     boolean retry = true; 
     painting.stopPainting(); 
     while (retry) { 
      try { 
       painting.join(); 
       retry = false; 
      } catch (InterruptedException e) { } 
     } 
     super.onSurfaceDestroyed(holder); 
    } 

En el hilo de pintura:

public void stopPainting() { 
    this.run = false; 
    synchronized(this) { 
     this.notify(); 
    } 
} 

public void run() { 
    this.run = true; 
    Canvas c = null; 
    while (run) { 
     try { 
      synchronized (this) { 
       Thread.sleep(50); 
       c = this.surfaceHolder.lockCanvas(); 
       doDraw(c); 
      } 
     } catch (InterruptedException e) { 
      e.printStackTrace(); 
     } finally { 
      if (c != null) { 
       this.surfaceHolder.unlockCanvasAndPost(c); // << -- HERE IS THE PROBLEM 
      } 
     } 
     // if pause... 
     synchronized (this) { 
      if (wait) { 
       try { 
        wait(); 
       } catch (Exception e) { } 
      } 
     } 
    } 
} 

¿alguien puede darme alguna idea de lo que estoy haciendo mal? Soy nuevo para Java y Android.

Respuesta

1

No veo un problema definitivo, pero he aquí algunas ideas.

  • Existe la posibilidad de que desbloquee un lienzo que no se haya bloqueado. Establecería c = null; en la parte superior de su circuito while; de lo contrario, el valor anterior de c se desbloqueará la próxima vez a través del ciclo.

    while (run) { 
        Canvas c = null; 
        ... 
    
  • Su campo run debe marcarse como volatile, ya que se accede por varios subprocesos.

  • Nunca llame al Thread.sleep(...) dentro de un bloque synchronized. Esa es una práctica muy mala, ya que bloquea otros hilos innecesariamente.

  • Asegúrese de que al menos registra sus excepciones. Tenga mucho cuidado con catch (Exception e) {}. Todo lo que hace es enmascarar tus problemas.

  • No tiene mucho sentido hacer join() dentro de un lazo while. Si su hilo se interrumpe, debe interrumpir el hilo de la pintura y salir.

  • Dado que los dos están durmiendo y de espera, que tendría más sentido para quitar el sueño y hacer algo como:

    try { 
        synchronized (this) { 
         if (wait) { 
          wait(); 
         else { 
          wait(50); 
         } 
        } 
    } catch (Exception e) { 
        e.printStackTrace(); 
    } 
    
2

Si el error es: UnlockAndPost Falló, significa no desbloqueó ningún buffer. Después this.surfaceHolder.unlockCanvasAndPost(c);
puede anexar
this.surfaceHolder.lockCanvas();
(lo siento por mi pobre dominio del Inglés)

2

Al abrir la vista previa de la imagen de fondo, crea el objeto WallpaperService y, además, crea una instancia del motor. Luego, la secuencia comienza a dibujar el fondo de pantalla.

Luego, cuando hace clic en "Establecer fondo de pantalla", no se crea una nueva instancia de WallpaperService. Pero llama al método onCreateEngine(), que devuelve otra (segunda) instancia de Engine.Que también ejecuta su propio hilo.

¡Ahora tiene dos hilos que compiten! Entonces conducen a una excepción lanzada.

Todo lo que necesita hacer para solucionar el error es escribir un método correcto en CrearEngine().

sustituir este:

@Override 
public Engine onCreateEngine() { 
    return new SampleEngine(); 
} 

a esto:

private SampleEngine engine; 

@Override 
public Engine onCreateEngine() { 

    if (engine!=null) { 
     engine.painting.stopPainting(); 
     engine = null; 
    } 
    engine = new SampleEngine(); 
    return engine; 
} 
1

tuve el mismo problema con mi fondo de pantalla en vivo. En un emulador de Nexus 5 funciona bien, pero cuando lo ejecuto en un emulador Nexus 10 se bloquea en el momento en que se carga la aplicación.

Descubrí que el problema era porque el skin predeterminado para el emulador tiene la resolución incorrecta. Después de que cambié la máscara a "Sin máscara", ya no sufro la colisión.

Para obtener más información sobre cómo solucionar la piel con la resolución incorrecto, por favor ver: Android Studio - Tablet emulator not showing correct resolution

Cuestiones relacionadas