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.

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?

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 se detiene un hilo sin un método stop ()?
  • Ejecutar tareas en backgound en NativeScript
  • Manera alternativa de subprocesos bajo Android
  • Android Runtime Logcat solo obtiene la instancia actual
  • Handlers vs llamadas asincrónicas en Android
  • Android finaliza el subproceso en el servicio y la actualización de la interfaz de usuario
  • Cómo llamar a las actividades de un hilo no actividad?
  • OnPostExecute () de AsyncTask nunca se llama en AndroidTestCase
  • Android 4.0 asynctask al mismo tiempo no es posible
  • ¿Cómo saber cuándo mi actividad está completamente creada?
  • La inicialización de Android TextToSpeech bloquea / congela el subproceso de UI
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.