Creación de vistas dentro de un hilo de trabajo
Tengo un requisito para generar un mapa de bits de un EditText y luego realizar algunas manipulaciones en él. Mi principal preocupación es no llamar al método View.buildDrawingCache()
en el subproceso de UI y posiblemente bloquearlo, especialmente cuando se habla de pantallas grandes (es decir, Nexus 10) ya que el EditText
ocupará alrededor del 80% del tamaño de pantalla disponible.
Runnable
s dentro de un ThreadPoolExecutor
, éstos inflarán vistas dummy en un hilo de trabajo y establecerán todos los atributos requeridos para ellos, entonces simplemente llame a buildDrawingCache()
& getDrawingCache()
para generar un mapa de bits.
- Nexus 5 va a modo de espera hace ciclo de vida de actividad buggy
- Realizar cambios en la interfaz de usuario de la actividad principal desde el subproceso en Service
- End SurfaceView y GameThread al salir de la aplicación
- Asynctask vs hilo en android
- La aplicación se bloquea y muestra un error en el hilo (señal fatal)
Esto funciona perfectamente en algunos dispositivos, pero recientemente he encontrado algunos dispositivos que se bloquean con el siguiente mensaje:
java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
Entiendo por qué esto sucede, ya que algunos teléfonos deben haber modificado la implementación de EditText
que crea un Handler
y, por lo tanto, requiere que Looper.prepare()
sea llamado primero.
De lo que he leído en línea no hay ningún problema con llamar Looper.prepare () dentro de un hilo de trabajo, aunque algunos han dicho que es muy poco recomendable, pero no pude encontrar una razón para eso.
Aparte de eso, la mayoría de los mensajes relacionados con este problema indican que no se supone que inflar vistas dentro de un hilo de fondo, probablemente debido a lo siguiente de la documentación oficial de Android (Procesos e hilos) :
"Do not access the Android UI toolkit from outside the UI thread"
-
¿Cuál es el enfoque recomendado para lidiar con este problema?
-
¿Hay algún daño en llamar build / get drawingcache del hilo principal? (En cuanto al rendimiento)
-
¿Llamar a Looper.prepare () dentro de mi hilo de trabajo solucionará este problema?
EDITAR
Sólo para elaborar mi requisito específico, tengo una interfaz de usuario que consta de un ImageView y un EditarTexto personalizado encima de él, el EditText puede cambiar su fuente y color de acuerdo a la selección del usuario, puede ser ampliado / Pinch to zoom "y también se puede arrastrar para permitir al usuario volver a colocarlo en la parte superior de la imagen.
Eventualmente lo que hago es crear una vista ficticia dentro de mi hilo de trabajo utilizando exactamente los mismos valores (ancho, altura, posición) que tiene actualmente en la interfaz de usuario y, a continuación, generarlo en la caché de dibujo, el mapa de bits de la imagen original se decodifica de nuevo desde un archivo local.
Una vez que los dos mapas de bits están listos, los fusiono en un único mapa de bits para uso futuro.
Así que para decirlo simple, ¿hay algo malo con la ejecución del siguiente código (desde dentro de un hilo de fondo ):
Llame a Looper.prepare () Cree una vista nueva con el contexto de la aplicación, la measure()
llamada measure()
& layout()
manualmente y luego compile + get drawingcache de ella, es decir:
Looper.prepare(); EditText view = new EditText(appContext); view.setText("some text"); view.setLayoutParams(layoutParams); view.measure( View.MeasureSpec.makeMeasureSpec(targetWidth, View.MeasureSpec.EXACTLY), View.MeasureSpec.makeMeasureSpec(targetHeight, View.MeasureSpec.EXACTLY)); view.layout(0, 0, targetWidth, targetHeight); view.buildDrawingCache(); Bitmap bitmap = view.getDrawingCache();
¿Cómo se aplica esto a la restricción de no acceder al kit de herramientas de la interfaz de usuario de Android desde fuera del hilo de la interfaz de usuario, qué podría ir mal?
- AsyncTask para actualizar widget - cómo acceder a textviews en onPostExecute ()?
- Cámara Android: ¿Hilos? Que debe hacer lo que
- Cordova plugin bloqueo de hilo
- Cómo administrar Loopers y Threads (el hilo no muere más!)
- Iniciar un servicio en un proceso separado android
- Método de servicio de Android llamado en hilo diferente. ¿Sigue funcionando en el hilo principal?
- Uso de OpenGL desde el hilo principal de Android
- Eficacia de la consulta con Parse que utiliza una tienda local en Android
En su caso, puede hacerlo por supuesto, pero tenga cuidado de leer sólo los valores de los datos de la interfaz de usuario, para evitar errores de sincronización.
Además, no deberías recrear el EditText del hilo de fondo, será más eficiente acceder directamente al ya existente:
Looper.prepare(); myEditText.setDrawingCacheEnabled(true); Bitmap bitmap = myEditText.getDrawingCache();
Si su pregunta es: por qué no es recomendada por las directrices de Android, aquí está una buena respuesta a su pregunta.
Llamar a View.buildDrawingCache()
llama a Bitmap.nativeCreate
que puede ser una asignación grande, así que sí, puede ser potencialmente dañina para ejecutarse en el subproceso principal. No veo un problema al llamar a Looper.prepare () en su subproceso de fondo. Sin embargo, no está claro lo que está tratando de lograr y puede haber una mejor solución a su problema.
La razón por la que no se supone que el kit de herramientas de la interfaz de usuario de otros hilos es que no está escrito para ser seguro de hilo se escribe bajo la suposición de que sólo un hilo lo ejecuta. Esto significa que es realmente difícil decir qué puede salir mal, los efectos negativos, si los hay, ocurrirán en su mayoría en una repetición impredecible debido a la sincronización específica de los subprocesos. Su descripción de lo que está tratando de hacer no demasiado claro. En su caso, sólo asignaría un mapa de bits grande, y dibujaría el texto en él. ¿Por qué está utilizando el EditText en primer lugar? Parece una especie de hack, y los hacks tienden a romperse con el tiempo.
¿Por qué View.buildDrawingCache()
? ¿Qué pasa con View.draw (lienzo lienzo) para renderizar manualmente a un Canvas
respaldo de un Bitmap
? El método parece lo suficientemente simple como para no causar problemas en los subprocesos de fondo.
EditText edit = (EditText)findViewById(R.id.edit); edit.buildDrawingCache(); ImageView img = (ImageView)findViewById(R.id.test); img.setImageBitmap(edit.getDrawingCache());
Lalit cuando intenta crear el caché en el método onCreate, el dibujo no ha ocurrido aún así que el drawingCache no debería tener nada. Ponga el método buildDrawingChache en el método onClick. O utilice el siguiente código en onCreate.
ViewTreeObserver vto = editText.getViewTreeObserver(); vto.addOnGlobalLayoutListener(new OnGlobalLayoutListener() { @Override public void onGlobalLayout() { editText.buildDrawingCache(); } });
También he encontrado este error unas cuantas veces:
java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
mi solución:
new Thread(new Runnable(){ @Override public void run(){ //add implementations that DOES NOT AFFECT the UI here new Handler(Looper.getMainLooper()).post(new Runnable() { @Override public void run(){ //manage your edittext and Other UIs here } }); } }).start();
Sólo cree un controlador dentro de su hilo de trabajo para aplicar los cambios de datos a su interfaz de usuario
- Cómo cargar archivos en la unidad de google con mi aplicación de Android
- Caída del evento debido a la ventana sin foco