IllegalArgumentException en unlockCanvasAndPost (fondo de pantalla en vivo Android)

He creado mi primer fondo de pantalla en vivo que implementa el dibujo en un hilo separado. Así que ahora tengo un WallpaperService y mi WallpaperPainter que hace el trabajo. El problema es que IllegalArgumentException una IllegalArgumentException en el método unlockCanvasAndPost en algunos de los dispositivos (Samsung Note es el único). He leído todas las recomendaciones que pude encontrar, pero no podía arreglar ese error. Parece que el unlockCanvasAndPost se llama cuando se destruye la superficie, por lo que el lienzo no es válido. Aquí están las partes esenciales del código:

En el servicio de papel tapiz:

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

¿Puede alguien darme alguna pista de lo que estoy haciendo mal? Soy nuevo tanto para Java como para Android.

Si el error es: UnlockAndPost Falló , significa que no ha sido bloqueado. Después this.surfaceHolder.unlockCanvasAndPost(c);
Puedes adjuntar
this.surfaceHolder.lockCanvas();
(Lo siento por mi pobre dominio del inglés)

No veo un problema definitivo, pero aquí hay algunos pensamientos.

  • Existe la posibilidad de desbloquear un lienzo que no ha sido bloqueado. Yo pondría c = null; En la parte superior de su loop while de lo contrario el valor anterior de c sería desbloqueado la próxima vez a través del bucle.

     while (run) { Canvas c = null; ... 
  • Su campo de run debe estar marcado como volatile porque se accede por múltiples subprocesos.

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

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

  • No hay mucho sentido en hacer el join() dentro de un bucle while. Si el hilo se interrumpe debe interrumpir el hilo de la pintura y salir.

  • Ya que ambos están durmiendo y esperando, tendría más sentido eliminar el sueño y hacer algo como:

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

Cuando abre la vista previa del fondo de pantalla, crea el objeto WallpaperService y crea además una instancia de Engine. Entonces el flujo empieza a dibujar fondo de pantalla.

A continuación, al hacer 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 se ejecuta su propio hilo.

Ahora tienes dos hilos competidores !!! Así que llevan a una excepción que se lanza.

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

Reemplace esto:

 @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; } 

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

Descubrí que el problema era porque el skin predeterminado para el emulador tenía la resolución incorrecta. Después de cambiar la piel a "No Skin", entonces no tengo el accidente más.

Para obtener más información sobre cómo solucionar la piel con una resolución incorrecta, consulte: Android Studio – El emulador de Tablet no muestra la resolución correcta

  • Juegos de sincronización de Java: sincronizados && wait && notify
  • Android: RunOnUiThread vs AsyncTask
  • Cómo administrar Loopers y Threads (el hilo no muere más!)
  • Android: Sincronización con el subproceso de procesador de OpenGL
  • Trabajos de fondo de Android para la sincronización con un servicio web
  • Utilizar Otto para actualizar un listadapter de un GcmListenerService
  • ¿Qué pasa con este hilo que se puede ejecutar al final una vez que se ha completado?
  • Despertar un hilo de dormir - interrupción () versus "dividir" el sueño en varios sueños
  • ¿Qué sucede con el subproceso como onDestroy se llama cuando se gira el dispositivo
  • ¿Cómo esperar que todas las tareas en un ThreadPoolExecutor terminen sin apagar el Ejecutor?
  • ¿Los BroadcastReceivers de Android comenzaron en un nuevo hilo?
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.