android multithreading android-layout android-ui

android - Creando vistas dentro de un hilo de trabajo



multithreading android-layout (6)

¿Por qué View.buildDrawingCache() ? ¿Qué hay de usar View.draw (lienzo de lienzo) para renderizar manualmente a un Canvas respaldado por un Bitmap ? El método parece lo suficientemente simple como para no causar problemas en subprocesos de fondo.

Tengo el requisito de 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 la interfaz de usuario y posiblemente bloquearlo, especialmente cuando se habla de pantallas grandes (es decir, Nexus 10) ya que el EditText ocupará aproximadamente el 80% del tamaño de pantalla disponible.

Runnable s dentro de ThreadPoolExecutor , estos inflarán vistas ficticias en un subproceso de trabajo y les buildDrawingCache() todos los atributos requeridos, luego simplemente llamarán a buildDrawingCache() & getDrawingCache() para generar un mapa de bits.

Esto funciona perfectamente en algunos dispositivos, pero recientemente he encontrado algunos dispositivos que fallan con el siguiente mensaje:

java.lang.RuntimeException: Can''t create handler inside thread that has not called Looper.prepare()

Entiendo por qué sucede esto, ya que algunos teléfonos deben haber modificado la implementación de EditText que crea un Looper.prepare() y, por lo tanto, requiere que se llame primero a Looper.prepare() .

Por lo que he leído en línea, no hay problema con llamar a Looper.prepare () dentro de un hilo de trabajo, aunque algunos declararon que no está recomendado, pero no pude encontrar una razón para ello.

Aparte de eso, la mayoría de las publicaciones relacionadas con este problema indican que no se debe inflar las vistas dentro de un hilo de fondo, probablemente debido a lo siguiente de la documentación oficial de Android (Procesos y subprocesos) :

"Do not access the Android UI toolkit from outside the UI thread"

  • ¿Cuál es el enfoque recomendado para tratar este problema?

  • ¿Hay algún daño al llamar a build / get drawingcache desde el hilo principal? (En cuanto al rendimiento)

  • ¿Resolveré este problema llamando a Looper.prepare () dentro de mi hilo de trabajo?

EDITAR

Solo para desarrollar mi requerimiento específico, tengo una interfaz de usuario que consta de un ImageView y un EditText personalizado, el EditText puede cambiar su fuente y color de acuerdo con la selección del usuario, se puede ampliar / reducir con " el gesto "pellizcar para ampliar" y también se puede arrastrar para que el usuario pueda colocarlo sobre la imagen.

Finalmente, lo que hago es crear una vista ficticia dentro de mi subproceso de trabajo con los mismos valores (ancho, alto, posición) que tiene actualmente en la interfaz de usuario y luego generar su caché de dibujo, el mapa de bits de la imagen original se descodifica nuevamente desde un archivo local.

Una vez que los dos mapas de bits están listos, los fusiono en un solo mapa de bits para su uso futuro.

En pocas palabras, ¿hay algún error con la ejecución del siguiente código (desde dentro de un hilo de fondo ):

Call Looper.prepare () Crea una nueva vista con el contexto de la aplicación, call measure() & layout() manualmente y luego crea + obtiene 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 subproceso de la interfaz de usuario, qué podría salir mal?


En su caso, puede hacerlo, por supuesto, pero tenga cuidado de solo leer los valores de los datos de la interfaz de usuario para evitar errores de sincronización.

Además, no debe volver a crear el EditText desde el 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 está recomendada por las directrices de Android, here hay una buena respuesta para su pregunta?


La razón por la que no se supone que el kit de herramientas de la interfaz de usuario de otros subprocesos es que no está escrito como seguro para subprocesos, se escribe bajo el supuesto de que solo un subproceso lo ejecuta. Esto significa que es realmente difícil saber qué puede salir mal, los efectos negativos, si es que ocurren, sucederán en su mayoría en una repetición debido a la sincronización específica de los subprocesos. Su descripción de lo que está tratando de hacer no es demasiado clara. En su caso, solo asignaría un gran mapa de bits y dibujaría texto en él. ¿Por qué usas EditText en primer lugar? Parece una especie de hack, y los hackers tienden a romperse con el tiempo.


Llamar a View.buildDrawingCache() llama a Bitmap.nativeCreate que puede ser una asignación grande, por lo que sí, puede ser potencialmente dañino para ejecutarse en el subproceso principal. No veo un problema con la llamada a Looper.prepare () en el hilo de fondo. Sin embargo, no está claro lo que está intentando lograr y puede haber una mejor solución para su problema.


También me encontré con este error unas cuantas veces ya:

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();

simplemente cree un controlador dentro de su subproceso de trabajo para aplicar cambios de datos a su interfaz de usuario


EditText edit = (EditText)findViewById(R.id.edit); edit.buildDrawingCache(); ImageView img = (ImageView)findViewById(R.id.test); img.setImageBitmap(edit.getDrawingCache());

Lalit cuando intenta crear la memoria caché en el método onCreate, el dibujo aún no se ha realizado, por lo que la DrawingCache no debería tener nada. Ponga el método buildDrawingChache en el método onClick. O use el siguiente código en onCreate.

ViewTreeObserver vto = editText.getViewTreeObserver(); vto.addOnGlobalLayoutListener(new OnGlobalLayoutListener() { @Override public void onGlobalLayout() { editText.buildDrawingCache(); } });