2010-08-23 27 views
14

Estoy tratando de extender HashMap como Parcelable y obtuve la sintaxis para compilar, sin embargo, en el tiempo de ejecución arroja una excepción y devuelve un puntero nulo intentando desarticular los datos.¿Es posible crear un HashMap que sea Parcelable en Android?

El remitente tiene que convertir a (Parcelable) para resolver la ambigüedad, sin embargo, el receptor se queja de que se espera Parcelable pero encontró HashMap.

¿Alguien ha tenido éxito con esto? ¿Está mal mi sintaxis? ¿Existe una solución mejor?

A continuación se presenta el código:

  • HomeActivity.java - el remitente
  • ContentViewActivity.java - el receptor
  • ContentItemSimple.java - como su nombre implica (envuelve una cadena y entero)
  • ContentItemCollection.java - esta es la HashMap

HomeActivity.java

package com.mobibob.android.studyparceable; 

import java.util.HashMap; 

import android.app.Activity; 
import android.content.Intent; 
import android.os.Bundle; 
import android.os.Parcel; 
import android.os.Parcelable; 
import android.text.format.Time; 
import android.util.Log; 
import android.view.View; 
import android.view.View.OnClickListener; 
import android.widget.Button; 

public class HomeActivity extends Activity implements OnClickListener { 
    private static final String TAG = "HomeActivity"; 
    private ContentItemSimple mContentItemSimple = null; 
    private ContentItemContainer mContentItemContainer = null; 

    /** Called when the activity is first created. */ 
    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.home); 

     Button click = (Button) findViewById(R.id.button_clickit); 
     click.setOnClickListener(this); 

     mContentItemSimple = new ContentItemSimple(); 
     mContentItemSimple.name = "mobibob"; 
     mContentItemSimple.year = 2010; 

     String value = "value"; 
     Time nowTime = new Time(); 
     nowTime.setToNow(); 
     mContentItemContainer = new ContentItemContainer(); 
     mContentItemContainer.put("string", new String("baseball is great!")); 
     mContentItemContainer.put("integer", new Integer(1234)); 
//  mContentItemContainer.put("boolean", new Boolean(true)); 
//  mContentItemContainer.put("date", nowTime); 
//  mContentItemContainer.put("parcel", new Bundle()); 
     Log.d(TAG, "..... " + mContentItemContainer.toString()); 
    } 

    @Override 
    public void onClick(View v) { 

     Intent i = new Intent(getBaseContext(), ContentViewActivity.class); 
     i.putExtra(ContentItemSimple.EXTRA_CONTENT_DETAIL, mContentItemSimple); 
     i.putExtra(ContentItemContainer.EXTRA_CONTENT_CONTAINER, (Parcelable) mContentItemContainer); 
     startActivityForResult(i, 0); 

    } 
} 

ContentViewActivity

package com.mobibob.android.studyparceable; 

import android.app.Activity; 
import android.os.Bundle; 
import android.util.Log; 
import android.view.View; 
import android.view.View.OnClickListener; 
import android.widget.Button; 
import android.widget.TextView; 

import com.mobibob.android.studyparceable.ContentItemSimple; 

public class ContentViewActivity extends Activity implements OnClickListener { 

    private static final String TAG = "ContentViewActivity"; 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 

     setContentView(R.layout.content_view); 

     Button gohome = (Button) findViewById(R.id.button_gohome); 

     gohome.setOnClickListener(this); 

     ContentItemSimple ci = null; 
     ContentItemContainer cx = null; 

     try { 
      ci = getIntent().getParcelableExtra(ContentItemSimple.EXTRA_CONTENT_DETAIL); 
      Log.i(TAG, "ci = " + ci.toString()); 

      cx = getIntent().getParcelableExtra(ContentItemContainer.EXTRA_CONTENT_CONTAINER); 
      Log.i(TAG, "cx = " + cx.toString()); 

      TextView tvName = (TextView) findViewById(R.id.ci_name); 
      tvName.setText(ci.name); 
      TextView tvYear = (TextView) findViewById(R.id.ci_year); 
      tvYear.setText(String.format("%d", ci.year)); 

     } catch (Exception e) { 
      Log.e(TAG, e.toString()); 
      e.printStackTrace(); 
     } 
    } 

    @Override 
    public void onClick(View v) { 
     finish(); 
    } 

} 

ContentItemSimple.java

package com.mobibob.android.studyparceable; 

import android.os.Parcel; 
import android.os.Parcelable; 
import android.util.Log; 

public class ContentItemSimple implements Parcelable { 
     public static final String TAG = "ContentItem"; 
    public static final String EXTRA_CONTENT_DETAIL = "contentDetail"; 
    public String name = "name"; 
    public Integer year = Integer.MIN_VALUE; 

    ContentItemSimple() { 
     name = new String(""); 
     year = new Integer(Integer.MIN_VALUE); 
    } 

    ContentItemSimple(Parcel in) { 
      try { 
       name = in.readString(); 
       year = in.readInt(); 
      } catch (Exception e) { 
       Log.e(TAG, e.toString()); 
       e.printStackTrace(); 
     } 
    } 

    @Override 
    public String toString() { 
     return String.format("name=%s age=%d", name, year); 
    } 

    @Override 
    public int describeContents() { 
     return 0; 
    } 

    @Override 
    public void writeToParcel(Parcel dest, int flags) { 
     dest.writeString(name); 
     dest.writeInt(year); 
    } 

    public static final Parcelable.Creator<ContentItemSimple> CREATOR = new Parcelable.Creator<ContentItemSimple>() { 
     public ContentItemSimple createFromParcel(Parcel in) { 
     return new ContentItemSimple(in); 
     } 

     public ContentItemSimple[] newArray(int size) { 
     return new ContentItemSimple[size]; 
     } 
    }; 

} 

ContentItemContainer.java

package com.mobibob.android.studyparceable; 

import java.util.HashMap; 
import java.util.Iterator; 

import android.os.Parcel; 
import android.os.Parcelable; 

public class ContentItemContainer extends HashMap<String, Object> implements Parcelable { 
    /** 
    * Container for wddx 'struct' elements. 
    */ 
    private static final long serialVersionUID = 1L; 
    // public String name = "?"; 
    // public String value = "?"; 
    public static final String EXTRA_CONTENT_DETAIL = "contentDetail"; 
    public static final String EXTRA_CONTENT_CONTAINER = "contentContainer"; 
    public static final String EXTRA_CONTENTDETAIL_NAME = "name"; 
    public static final String EXTRA_CONTENTDETAIL_VALUE = "value"; 

// private static HashMap<String, Object> map = new HashMap<String, Object>(); 

    ContentItemContainer() { 
     super(); 
    } 

    ContentItemContainer(Parcel in) { 
     in.readMap(this, ContentItemContainer.class.getClassLoader()); 
    } 

    @Override 
    public String toString() { 
     StringBuilder sb = new StringBuilder(""); 
     Integer x = 0; 
     Iterator<HashMap.Entry<String, Object>> it = this.entrySet().iterator(); 
     while (it.hasNext()) { 
      HashMap.Entry<String, Object> pairs = (HashMap.Entry<String, Object>) it.next(); 
      x++; 
      sb.append("\n"+x.toString()+": ").append("name=").append(pairs.getKey()).append(" value=").append(pairs.getValue().toString()); 
     } 
     return sb.toString(); 
    } 

    @Override 
    public int describeContents() { 
     return 0; 
    } 

    @Override 
    public void writeToParcel(Parcel dest, int flags) { 
     dest.writeMap(this); 
    } 

    public static final Parcelable.Creator<ContentItemContainer> CREATOR = new Parcelable.Creator<ContentItemContainer>() { 
     public ContentItemContainer createFromParcel(Parcel in) { 
      return new ContentItemContainer(in); 
     } 

     public ContentItemContainer[] newArray(int size) { 
      return new ContentItemContainer[size]; 
     } 
    }; 

} 
+2

¿Por qué no utilizar un 'Bundle' en lugar de un' HashMap'? – CommonsWare

+0

Pensé en eso, así que déjame cambiar y ver si consigo lo que necesito. Mientras tanto, ¿puede esto funcionar? Sé que la documentación indica que Parcelable no tiene la intención de ser un serializador de "propósito general", pero pensé que esto todavía estaba dentro de un uso razonable. – mobibob

+1

Al cambiar a Bundle parece que va a funcionar para mi proyecto. Mientras tanto, me gustaría saber la respuesta a esta pregunta en su forma actual. (Creo que la respuesta será esclarecedora con respecto al SO Android y su SDK.) – mobibob

Respuesta

22

La manera en que su clase es ContentItemContainer implementado: al extender HashMap, nunca se invocará su writeToParcel y Parcelable.Creator.

La razón es que Map es un tipo de datos válido para poner en una Parcela, de modo que la clase se aplana usando la lógica de la clase HashMap, y no la suya. Esto se debe a la forma en que se implementa Parcel; comprueba si los valores proporcionados son descendientes de ciertas clases en un orden específico.

Al desasociar los extras, se creará un HashMap a partir de los datos de su objeto en consecuencia.

Para solucionar esto, podría ocultar HashMap dentro de su clase y exponer getters/putters para HashMap. Esta es exactamente la misma forma en que se implementa ContentValues, y parcelling/unparcelling funciona sin problemas.

+0

Entonces, ayúdenme a entender su respuesta, ¿está diciendo que mi HashMap está escribiendo como Mapa, y luego tratando de volver a leer como HashMap, pero los datos están determinados a ser un Mapa, por lo tanto, la excepción?¿No debería la excepción ser una 'excepción de lanzamiento' no la 'excepción de puntero nulo'? – mobibob

+1

Casi. Bundle intenta volver a leer como Parcelable, pero encuentra un HashMap. Entonces, una clase CastException se produce internamente en Bundle(), pero se detecta y, posteriormente, Bundle devuelve null en la llamada getParcelable() (Intent.getParcelableExtra es un atajo para llamar a Intent.getExtras y luego a Bundle.getParcelable). – Thorstenvv

+0

Eso tiene sentido, pero no tengo tiempo para verificarlo hoy. Supongo que está mirando la fuente de Android para responder a mi pregunta y no se puede 'depurar' como una caja negra e implementar como se podría esperar que la extensión y la interfaz impliquen. Voy a aceptar tu respuesta porque el tiempo se está acabando con la recompensa y estoy seguro de que funcionará como lo estás explicando. – mobibob

Cuestiones relacionadas