2010-12-02 14 views
9

Estoy intentando utilizar una clase AsyncTask-extended para manejar la conexión a una URL, analizar JSON, mostrar un ProgressDialog indeterminado durante el análisis y devolver los resultados como valor-clave se empareja en un HashMap con la actividad principal. Los resultados de HashMap serán leídos por la Actividad principal y puestos en campos de formulario. Sin embargo, aunque estoy llenando el HashMap en mi AsyncTask (evidenciado por println declaraciones), llamando a un método en la Actividad principal que devuelve el HashMap produce un resultado vacío. No puedo entender si esto es algo que estoy haciendo mal, o si estoy malinterpretando las capacidades de AsyncTask.Android: resultado de que AsyncTask no se devuelve a la actividad principal

Estoy debatiendo la conversión de mi clase que extiende AsyncTask a una actividad. Básicamente, el usuario no debería poder hacer nada más durante esta búsqueda/análisis de datos y debería esperar hasta que el archivo de diálogo de progreso desaparezca antes de que pueda volver a interactuar con la aplicación (o presionando el botón Atrás). Además, mi aplicación debe ser capaz de manejar ciertos casos en mi AsyncTask donde se detectan excepciones (no se puede conectar a URL, JSON incorrecto, ID de producto para buscar no se puede encontrar) y los diálogos de error personalizados están diseñados para esas excepciones. Podría hacer esto fácilmente si esta clase fuera una Actividad, ya que podría enviar diferentes códigos de resultado al llamar a finish(), dependiendo de si se captura una excepción.

Una vez más, no estoy seguro de si AsyncTask es la mejor solución aquí, ya que el usuario no hará nada más mientras se recopila y analiza la información. Por favor, avísenme si una nueva actividad tendría sentido o si solo estoy destruyendo mi implementación de un hilo de fondo.

MainActivity.java

mInitiateProductLookupButton.setOnClickListener(new View.OnClickListener() { 
      public void onClick(View v) { 
       ProductLookup pl = new ProductLookup(id, MainActivity.this); 
       pl.execute(); 

       // The below variable is always empty! 
       HashMap<String, String> productInfo = pl.getProductInfo(); 
       applyProductInfoToFormFields(productInfo); 
      } 
     }); 

ProductLookup.java

public class ProductLookup extends AsyncTask<Object, Void, HashMap<String, String>> { 
    private String mProductID; 
    private Context mContext; 
    HashMap<String, String> mProductInfo; 
    ProgressDialog mDialog; 

    public ProductLookup(String id, Context applicationContext) { 
     mProductID = id; 
     mContext = applicationContext; 
     mProductInfo = new HashMap<String, String>(); 
    } 

    @Override 
    protected void onPreExecute() { 
     mDialog = new ProgressDialog(mContext); 
     mDialog.setMessage("Loading product info. Please wait..."); 
     mDialog.setIndeterminate(true); 
     mDialog.setCancelable(false); 
     mDialog.show(); 
    } 

    @Override 
    protected void onPostExecute(HashMap<String, String> result){ 
     super.onPostExecute(result); 
     mDialog.dismiss(); 
     mProductInfo = result; 
    } 


    @Override 
    protected HashMap<String, String> doInBackground(Object... params) { 
     try { 
      // Connect to URL, parse JSON, and add key-value pairs to mProductInfo... 

     } catch (MalformedURLException e) { 
      e.printStackTrace(); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } catch (JSONException e) { 
      e.printStackTrace(); 
     } 
     finally { 
      try { 
       // Close input/output reader variables 
      } catch (IOException e) { 
       e.printStackTrace(); 
      } 
     } 
     return mProductInfo; 

    } 

    public HashMap<String, String> getProductInfo(){ 
     return this.mProductInfo; 
    } 

} 

Respuesta

5

Cuando se emite .execute() que se ejecuta como roscado y no espera el resultado.

Así que como sea que llame después de esto, está vacío ya que los datos no se han cargado todavía.

Es necesario configurar el PostExecuted el resultado directamente a su actividad a través de un regulador de MainActivity.this.setProductInfo(result)

+1

Cuando trato de hacer eso, me sale un error que no me deja de compilación: "Ningún caso encerrando del MainActivity tipo es accesible en su alcance" – Keeb13r

+2

Crear el AsyncTask interior de su MainActivity como clase privada niño . – Pentium10

+0

¿Cómo creas exactamente una clase privada para niños? – Keeb13r

3

Hay algún concepto fallida de usted. La instrucción después de AsyncTask.execute() se ejecutará justo después de la llamada. Mientras tu doInBackground funciona en otro hilo. Aquí, cuando está utilizando el mapa de información del producto, doInBackground no se completó, por lo que el resultado no se rellena allí

La solución más fácil para usted es utilizar el resultado en el método onPostExecute.

protected void onPostExecute(HashMap<String, String> result){ 
     mDialog.dismiss(); 
     mProductInfo = result; 
applyProductInfoToFormFields(productInfo); 

    } 
+0

El método applyProductInfoToFormFields() está en MainActivity, y establece los miembros de datos de esa clase (que representan los campos de formulario) para tener nuevos valores (por ejemplo, los valores analizados desde mi JSON) . No pensé que podría hacer una llamada a ese método desde ProductLookup. Además, pensé que si iba a modificar/interactuar con mi GUI, debería continuar haciéndolo desde mi MainActivity. ¿Cómo sabría ProductInfo cuáles son los datos de los miembros de mis campos sin guardar nuevas instancias de ellos? – Keeb13r

+0

No te entiendo correctamente. Creo que necesitas acceder a tu formulario de control GUI applyProductInfoToFormFields(). Si lo mejor para usted es declarar su componente de GUI globalmente para que pueda acceder a él desde cualquier lugar. –

+0

¿Y cómo me referiría a los miembros de datos de MainActivity de ProductLookup? ¿Qué tendría que cambiar sobre ellos para que sean globales? – Keeb13r

Cuestiones relacionadas