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:
- Acceso a la interfaz de usuario de JavaScript en Android
- Android: la mejor práctica para realizar operaciones asíncronas en getView ()
- La actividad ha filtrado la ventana com.android.internal.policy.impl.PhoneWindow$DecorView@46368a28 que fue agregada originalmente aquí
- Cómo sincronizar correctamente el código RenderScript de Android en Nvidia Shield
- Android SDK AsyncTask doInBackground no está en ejecución (subclase)
@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.
- SYSTEM_UI_FLAG_LOW_PROFILE no se puede resolver o no es un campo para google threadsample
- Diseño de motor de juego para Android: ¿cómo sincronizar el bucle de juego y el hilo de actualización de la galería?
- Nexus 5 va a modo de espera hace ciclo de vida de actividad buggy
- Caso de interés en multithreading con int volátil
- RxJava - subir archivos secuencialmente - emitir el siguiente elemento, cuando onNext llamado
- ¿Cómo configurar el nombre del hilo?
- Android: onCreate () se llama varias veces (y no por mí)
- Programación de procesos 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 dec
sería desbloqueado la próxima vez a través del bucle.while (run) { Canvas c = null; ...
-
Su campo de
run
debe estar marcado comovolatile
porque se accede por múltiples subprocesos. -
Nunca llame a
Thread.sleep(...)
dentro de un bloquesynchronized
. 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
- Recoger el sensor android durante un período específico y calcular el promedio
- Activación de KioskMode en Android 4.4.2 con Root