2012-06-29 13 views
14

Wenn eine Konfigurationsänderung passiert, gehen meine ListView Checkbox-Zustände verloren, was ich verstehe. Ich versucheBeste Möglichkeit, SparseBooleanArray in Bundle zu speichern?

public void onSaveInstanceState(final Bundle outState) 

in einer meiner Fragmente zu implementieren. Also frage ich mich, was ist der einfachste Weg, um meine SparseBooleanArray in der outState zu speichern.

Auch ich bin ein wenig verwirrt, als Listview die Methode hat:

getListView().getCheckedItemPositions(); 

Was für dieses gut ist?

+0

Möglicherweise müssen Sie 'onSaveInstanceState()' überhaupt nicht verwenden. Siehe http://stackoverflow.com/questions/24294919/maintain-item-selection-on-orientation-change – faizal

Antwort

0

Sie könnten entweder ein Serialisierungsschema für diese Datenstruktur erfinden oder zu einem HashSet wechseln und nur die Listenindexpositionen darin speichern, die überprüft werden. Da HashSet serialisierbar ist, können Sie es einfach in den Instanzstatus Bundle einfügen.

0

Ich versuche das Gleiche zu tun. Zunächst wurde ich mit einem HashMap

How to send hashmap value to another activity using an intent

zwischen Aktivitäten passieren, da es die Serializable-Schnittstelle erweitert. Doch nach einigen Recherchen:

SparseBooleanArrays sollen effizienter sein als ein HashMap mit Integers zu Booleans abzubilden.“

Ich kann jedoch keine einfache Möglichkeit finden, diese Datenstruktur zu speichern. Ich habe erwogen, die Werte des SparseBooleanArray zu greifen und es in einem HashMap zu speichern, damit es zwischen Aktivitäten übergeben werden kann. Aber das scheint mehr Komplexität hinzuzufügen.

Leider denke ich, dass ich mit HashMaps zurückkehren werde meine Liste der angekreuzte Kästchen speichern

0

Hier ist meine Lösung. Nur ein einfacher Wrapper, mit dem man eine SparseBooleanArray serialisieren kann.

public class SerializableSparseBooleanArrayContainer implements Serializable { 

    private static final long serialVersionUID = 393662066105575556L; 
    private SparseBooleanArray mSparseArray; 

    public SerializableSparseBooleanArrayContainer(SparseBooleanArray mDataArray) { 
     this.mSparseArray = mDataArray; 
    } 

    public SparseBooleanArray getSparseArray() { 
     return mSparseArray; 
    } 

    public void setSparseArray(SparseBooleanArray sparseArray) { 
     this.mSparseArray = sparseArray; 
    } 

    private void writeObject(java.io.ObjectOutputStream out) throws IOException { 
     out.writeLong(serialVersionUID); 
     int sparseArraySize = mSparseArray.size(); 
     out.write(sparseArraySize); 
     for (int i = 0 ; i < sparseArraySize; i++){ 
      int key = mSparseArray.keyAt(i); 
      out.writeInt(key); 
      boolean value = mSparseArray.get(key); 
      out.writeBoolean(value); 
     } 
    } 

    private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException { 
     long readSerialVersion = in.readLong(); 
     if (readSerialVersion != serialVersionUID) { 
      throw new IOException("serial version mismatch"); 
     } 
     int sparseArraySize = in.read(); 
     mSparseArray = new SparseBooleanArray(sparseArraySize); 
     for (int i = 0 ; i < sparseArraySize; i++) { 
      int key = in.readInt(); 
      boolean value = in.readBoolean(); 
      mSparseArray.put(key, value); 
     } 
    } 

} 

ich dann fügen Sie das Objekt zu einem Bündel etwa so:

@Override 
public void onSaveInstanceState(Bundle outState) { 
    super.onSaveInstanceState(outState); 
    SparseBooleanArray sparseBooleanArray = getSparseBooleanArray(); 
    SerializableSparseBooleanArrayContainer sparseBooleanArraySerializable = new SerializableSparseBooleanArrayContainer(sparseBooleanArray); 
    outState.putSerializable(SOME_BUNDLE_KEY, sparseBooleanArraySerializable); 
} 
4

Ich sehe keine Antworten auf den letzten Teil der Frage:

Auch ich m ein bisschen verwirrt, da ListView die Methode hat:

getListView().getCheckedItemPositions();

Wofür ist das gut?

Angenommen, Sie verwenden Kontrollkästchen in Verbindung mit dem Aktionsmodus, der Aktionsmodus selbst speichert den Status der überprüften Positionen. Im normalen Modus wird durch Drücken und Halten ein Element hervorgehoben, der Aktionsmodus aktiviert und dem Benutzer ermöglicht, andere Elemente anzutippen, um sie ebenfalls zu überprüfen.

Was passiert bei einer Orientierungsänderung? Der Aktionsmodus wird fortgesetzt und die Highlights bleiben erhalten. Ihre Checkboxen sind nicht, aber eindeutig die Daten von dem, was überprüft wird.

Nach einer Orientierungsänderung wird onCreateActionMode() aufgerufen. Bei dieser Methode (aber nicht vorher) gibt getListView().getCheckedItemPositions() die SparseBooleanArray zurück, die Sie wahrscheinlich suchen.

Der nette Teil darüber ist, wenn dies Ihr einziger Anwendungsfall für die SparseBooleanArray ist, müssen Sie nicht einmal sorgen, um es selbst zu speichern. Sie können es von dem System abrufen, das bereits ist, das es über die Orientierungsänderung speichert.

Das ist, was getListView().getCheckedItemPositions() ist gut für.

37

In meinem Fall landete ich es zu tun um rund die SparseBooleanArray eine Parcel Wrapper Umsetzung wie folgt aus:

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

public class SparseBooleanArrayParcelable extends SparseBooleanArray implements Parcelable { 
    public static Parcelable.Creator<SparseBooleanArrayParcelable> CREATOR = new Parcelable.Creator<SparseBooleanArrayParcelable>() { 
    @Override 
    public SparseBooleanArrayParcelable createFromParcel(Parcel source) { 
     SparseBooleanArrayParcelable read = new SparseBooleanArrayParcelable(); 
     int size = source.readInt(); 

     int[] keys = new int[size]; 
     boolean[] values = new boolean[size]; 

     source.readIntArray(keys); 
     source.readBooleanArray(values); 

     for (int i = 0; i < size; i++) { 
     read.put(keys[i], values[i]); 
     } 

     return read; 
    } 

    @Override 
    public SparseBooleanArrayParcelable[] newArray(int size) { 
     return new SparseBooleanArrayParcelable[size]; 
    } 
    }; 

    public SparseBooleanArrayParcelable() { 

    } 

    public SparseBooleanArrayParcelable(SparseBooleanArray sparseBooleanArray) { 
    for (int i = 0; i < sparseBooleanArray.size(); i++) { 
     this.put(sparseBooleanArray.keyAt(i), sparseBooleanArray.valueAt(i)); 
    } 
    } 

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

    @Override 
    public void writeToParcel(Parcel dest, int flags) { 
    int[] keys = new int[size()]; 
    boolean[] values = new boolean[size()]; 

    for (int i = 0; i < size(); i++) { 
     keys[i] = keyAt(i); 
     values[i] = valueAt(i); 
    } 

    dest.writeInt(size()); 
    dest.writeIntArray(keys); 
    dest.writeBooleanArray(values); 
    } 
} 

Auf diese Weise können Sie Ihre SparseBooleanArray speichern und laden, indem Sie gerade tun:

Bundle bundle; //For your activity/fragment state, to include in an intent, ... 
SparseBooleanArray sbarray; //Probably from your listview.getCheckedItemPositions() 

//Write it 
bundle.putParcelable("myBooleanArray", new SparseBooleanArrayParcelable(sbarray)); 

//Read it back 
sbarray = (SparseBooleanArray) bundle.getParcelable("myBooleanArray"); 

Nur meine .02 €

+0

Tolle Lösung. Hat wunderbar funktioniert. Gute Arbeit – Stephen

+0

Sie sollten bundle.getParcelable ("myBooleanArray") an (SparseBooleanArray) beim Lesen aus Bundle werfen. – localhost

+0

Danke für die Bearbeitung @localhost! – opsidao

1

SparseArray Erweitern einer Serializable zu implementieren:

import java.io.IOException; 
import java.io.ObjectInputStream; 
import java.io.ObjectOutputStream; 
import java.io.Serializable; 
import android.util.SparseArray; 



/** 
* @author Asaf Pinhassi www.mobiledev.co.il 
* @param <E> 
* 
*/ 
public class SerializableSparseArray<E> extends SparseArray<E> implements Serializable{ 

    private static final long serialVersionUID = 824056059663678000L; 

    public SerializableSparseArray(int capacity){ 
     super(capacity); 
    } 

    public SerializableSparseArray(){ 
     super(); 
    } 

    /** 
    * This method is private but it is called using reflection by java 
    * serialization mechanism. It overwrites the default object serialization. 
    * 
    * <br/><br/><b>IMPORTANT</b> 
    * The access modifier for this method MUST be set to <b>private</b> otherwise {@link java.io.StreamCorruptedException} 
    * will be thrown. 
    * 
    * @param oos 
    *   the stream the data is stored into 
    * @throws IOException 
    *    an exception that might occur during data storing 
    */ 
    private void writeObject(ObjectOutputStream oos) throws IOException { 
     Object[] data = new Object[size()]; 

     for (int i=data.length-1;i>=0;i--){ 
      Object[] pair = {keyAt(i),valueAt(i)}; 
      data[i] = pair; 
     } 
     oos.writeObject(data); 
    } 

    /** 
    * This method is private but it is called using reflection by java 
    * serialization mechanism. It overwrites the default object serialization. 
    * 
    * <br/><br/><b>IMPORTANT</b> 
    * The access modifier for this method MUST be set to <b>private</b> otherwise {@link java.io.StreamCorruptedException} 
    * will be thrown. 
    * 
    * @param oos 
    *   the stream the data is read from 
    * @throws IOException 
    *    an exception that might occur during data reading 
    * @throws ClassNotFoundException 
    *    this exception will be raised when a class is read that is 
    *    not known to the current ClassLoader 
    */ 
    private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException { 
     Object[] data = (Object[]) ois.readObject(); 
     for (int i=data.length-1;i>=0;i--){ 
      Object[] pair = (Object[]) data[i]; 
      this.append((Integer)pair[0],(E)pair[1]); 
     } 
     return; 
    } 


} 
0

habe ich versucht, die Lösung SerializableSparseArray verlauf SparseArray was es ermöglicht, die Erstellung über Bundle.putSerializable Anruf ein SparseArray in Bündel zu setzen.

Aber ich fand, dass ich das gespeicherte Objekt aus dem Bündel in onRestoreInstanceState nicht erhalten kann. In das Problem eingrabend fand ich, dass savedInstanceState.getSerializable(KEY_TO_STRING_SPARSE_ARRAY) == null.

Dann versuchen savedInstanceState.get(KEY_TO_STRING_SPARSE_ARRAY) zu überprüfen und überraschenderweise eine SparseArray<String> nicht SerializableSparseArray<String>. Schließlich verwende ich savedInstanceState.getSparseParcelableArray(KEY_TO_STRING_SPARSE_ARRAY), um SparseArray zurück von einem Bündel zu erhalten.

Verwenden Sie dann Java Reflection, um eine SparseArray<String> zu speichern, um direkt zu bündeln, ohne mit Serializable oder Schnittstelle zu erweitern. Es ist ein bisschen schmutzig, aber ich denke, Sie können Ihre eigene Dienstprogrammfunktion machen, die die folgende Detailimplementierung versteckt.

try { 
    // FIXME WTF 
    Method m = Bundle.class.getMethod("putSparseParcelableArray", String.class, SparseArray.class); 
    m.invoke(savedInstanceState, KEY_TO_STRING_SPARSE_ARRAY, mSparseStringArray); 
} catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) { 
    Log.e(TAG, "exception", e); 
} 

Ich habe den Code getestet und es funktioniert auf Android 4.4.4. Und ich würde gerne wissen, ob es sicher ist, die Implementierung in anderen SDK-Implementierungen zu verwenden.