2010-04-08 10 views
19

मैं एक बंडल ऑब्जेक्ट को क्रमबद्ध करना चाहता हूं, लेकिन ऐसा करने का एक आसान तरीका प्रतीत नहीं होता है। पार्सल का उपयोग करना एक विकल्प की तरह प्रतीत नहीं होता है, क्योंकि मैं धारावाहिक डेटा को फ़ाइल में संग्रहीत करना चाहता हूं।बंडल को क्रमबद्ध करने के लिए कैसे?

ऐसा करने के तरीकों पर कोई विचार?

कारण मैं चाहता हूं कि यह मेरी गतिविधि की स्थिति को सहेजना और पुनर्स्थापित करना है, जब उपयोगकर्ता द्वारा इसे मार दिया जाता है। मैं पहले से ही उस राज्य के साथ एक बंडल बना रहा हूं जिसे मैं सहेजना चाहता हूं। लेकिन सिस्टम द्वारा गतिविधि को मारने पर एंड्रॉइड केवल इस बंडल को रखता है। जब उपयोगकर्ता गतिविधि को मारता है, तो मुझे इसे स्वयं स्टोर करना होगा। इसलिए मैं इसे फ़ाइल में क्रमबद्ध और स्टोर करना चाहता हूं। बेशक, यदि आपके पास एक ही चीज़ को पूरा करने का कोई अन्य तरीका है, तो मैं इसके लिए भी आभारी रहूंगा।

संपादित करें: मैंने अपने राज्य को बंडल के बजाय JSONObject के रूप में एन्कोड करने का निर्णय लिया। JSON ऑब्जेक्ट को एक बंडल में एक Serializable के रूप में रखा जा सकता है, या फ़ाइल में संग्रहीत किया जा सकता है। शायद सबसे कुशल तरीका नहीं है, लेकिन यह आसान है, और ऐसा लगता है कि यह ठीक काम करता है।

उत्तर

6

मैं उस सीमा के चारों ओर जाने के लिए SharedPreferences का उपयोग करता हूं, यह बंडल क्लास के रूप में डेटा को संग्रहीत करने और पुनर्प्राप्त करने के लिए एक ही putXXX() और getXXX() शैली का उपयोग करता है और यदि आपने पहले बंडल का उपयोग किया है तो इसे लागू करने के लिए अपेक्षाकृत सरल है।

तो onCreate में मैं onRestoreInstanceState()

और

में एक बंडल से इस

if(savedInstanceState != null) 
{ 
    loadGameDataFromSavedInstanceState(savedInstanceState); 
} 
else 
{ 
    loadGameDataFromSharedPreferences(getPreferences(MODE_PRIVATE)); 
} 

मैं onSaveInstanceState में एक बंडल() करने के लिए अपने खेल डेटा को बचाने की तरह एक चेक, और लोड डेटा है

मैं भी खेल डेटा onPause() में SharedPreferences, और लोड के आंकड़ों के SharedPreferences से onResume में (बचाने के लिए)

onPause() 
{ 
    // get a SharedPreferences editor for storing game data to 
    SharedPreferences.Editor mySharedPreferences = getPreferences(MODE_PRIVATE).edit(); 

    // call a function to actually store the game data 
    saveGameDataToSharedPreferences(mySharedPreferences); 

    // make sure you call mySharedPreferences.commit() at the end of your function 
} 

onResume() 
{ 
    loadGameDataFromSharedPreferences(getPreferences(MODE_PRIVATE)); 
} 

मुझे आश्चर्य नहीं होगा अगर कुछ लोगों को लगता है कि यह साझा संदर्भों का गलत उपयोग है, लेकिन यह काम पूरा हो जाता है। मैं एक साल से अधिक के लिए अपने सभी खेलों (लगभग 2 मिलियन डाउनलोड) में इस विधि का उपयोग कर रहा हूं और यह काम करता है।

+2

यकीन है कि काम करता है, मैं बस राज्य को बंडल करने के 2 तरीके से बचने की उम्मीद कर रहा था, भले ही वे बहुत समान हों। – hermo

+0

यह वही है जो मुझे लगातार स्थिति बचाने के लिए दिमाग में था। – Awemo

7

एक फाइल करने के लिए किसी भी Parcelable भंडारण बहुत आसान है:

FileOutputStream fos = context.openFileOutput(localFilename, Context.MODE_PRIVATE); 
Parcel p = Parcel.obtain(); // i make an empty one here, but you can use yours 
fos.write(p.marshall()); 
fos.flush(); 
fos.close(); 

का आनंद लें!

+9

हां, मुझे वह भी मिला। समस्या यह है कि इस बात की कोई गारंटी नहीं है कि आप इसे फिर से उतार सकते हैं, कहें कि ओएस अपडेट किया गया है और पार्सल बदल गया है। लेकिन अगर आप इसके साथ रह सकते हैं तो यह ठीक है। – hermo

+12

विधि मैशल() से पुनर्प्राप्त डेटा को किसी भी प्रकार के लगातार भंडारण (स्थानीय डिस्क पर, नेटवर्क पर, आदि) में नहीं रखा जाना चाहिए। इसके लिए, आपको मानक क्रमबद्धरण या किसी अन्य प्रकार की सामान्य धारावाहिक तंत्र का उपयोग करना चाहिए। पार्सल मार्शल का प्रतिनिधित्व स्थानीय आईपीसी के लिए अत्यधिक अनुकूलित है, और इस तरह प्लेटफ़ॉर्म के विभिन्न संस्करणों में बनाए गए डेटा के साथ संगतता बनाए रखने का प्रयास नहीं करता है। (http://developer.android.com/reference/android/os/Parcel.html#marshall()) – Oneiros

+0

मुझे लगता है कि आपको सहेजी गई फ़ाइल को अन्य देवताओं में स्थानांतरित नहीं करना चाहिए, लेकिन शायद यह ठीक है अगर आप इसका उपयोग कर रहे हैं यह एकल डिवाइस पर (उदाहरण के लिए अस्थायी डेटा सहेजने के लिए)। –

4

SharedPreferences करने के लिए इसे कन्वर्ट:

private void saveToPreferences(Bundle in) { 
    Parcel parcel = Parcel.obtain(); 
    String serialized = null; 
    try { 
     in.writeToParcel(parcel, 0); 

     ByteArrayOutputStream bos = new ByteArrayOutputStream(); 
     IOUtils.write(parcel.marshall(), bos); 

     serialized = Base64.encodeToString(bos.toByteArray(), 0); 
    } catch (IOException e) { 
     Log.e(getClass().getSimpleName(), e.toString(), e); 
    } finally { 
     parcel.recycle(); 
    } 
    if (serialized != null) { 
     SharedPreferences settings = getSharedPreferences(PREFS, 0); 
     Editor editor = settings.edit(); 
     editor.putString("parcel", serialized); 
     editor.commit(); 
    } 
} 

private Bundle restoreFromPreferences() { 
    Bundle bundle = null; 
    SharedPreferences settings = getSharedPreferences(PREFS, 0); 
    String serialized = settings.getString("parcel", null); 

    if (serialized != null) { 
     Parcel parcel = Parcel.obtain(); 
     try { 
      byte[] data = Base64.decode(serialized, 0); 
      parcel.unmarshall(data, 0, data.length); 
      parcel.setDataPosition(0); 
      bundle = parcel.readBundle(); 
     } finally { 
      parcel.recycle(); 
     } 
    } 
    return bundle; 
} 
+4

यह फिर से एक पार्सल की सामग्री को लगातार स्मृति के किसी भी रूप में संग्रहीत करने की सिफारिश के खिलाफ जा रहा है (जिसे जावाडॉक्स ने चेतावनी दी है)। मान लें कि आप किसी कारण से अपने ओएस को अपडेट और अपडेट करते हैं, तो उपर्युक्त कोड आपके ऐप को 'restoreFromPreferences() "विधि में क्रैश करेगा या बंडल में कुछ अज्ञात मान वापस करेगा। – Yinzara

0

मामले में आप लगातार भंडारण आप parcelable है और न ही serializable तंत्र पर भरोसा नहीं कर सकते में संग्रहीत करना चाहते हैं। आप खुद यह करना है और नीचे तरीका है कि कैसे मैं आम तौर पर यह कार्य करें:

private static final Gson sGson = new GsonBuilder().create(); 
private static final String CHARSET = "UTF-8"; 
// taken from http://www.javacamp.org/javaI/primitiveTypes.html 
private static final int BOOLEAN_LEN = 1; 
private static final int INTEGER_LEN = 4; 
private static final int DOUBLE_LEN = 8; 

public static byte[] serializeBundle(Bundle bundle) { 
    try { 
     List<SerializedItem> list = new ArrayList<>(); 
     if (bundle != null) { 
      Set<String> keys = bundle.keySet(); 
      for (String key : keys) { 
       Object value = bundle.get(key); 
       if (value == null) continue; 
       SerializedItem bis = new SerializedItem(); 
       bis.setClassName(value.getClass().getCanonicalName()); 
       bis.setKey(key); 
       if (value instanceof String) 
        bis.setValue(((String) value).getBytes(CHARSET)); 
       else if (value instanceof SpannableString) { 
        String str = Html.toHtml((Spanned) value); 
        bis.setValue(str.getBytes(CHARSET)); 
       } else if (value.getClass().isAssignableFrom(Integer.class)) { 
        ByteBuffer b = ByteBuffer.allocate(INTEGER_LEN); 
        b.putInt((Integer) value); 
        bis.setValue(b.array()); 
       } else if (value.getClass().isAssignableFrom(Double.class)) { 
        ByteBuffer b = ByteBuffer.allocate(DOUBLE_LEN); 
        b.putDouble((Double) value); 
        bis.setValue(b.array()); 
       } else if (value.getClass().isAssignableFrom(Boolean.class)) { 
        ByteBuffer b = ByteBuffer.allocate(INTEGER_LEN); 
        boolean v = (boolean) value; 
        b.putInt(v ? 1 : 0); 
        bis.setValue(b.array()); 
       } else 
        continue; // we do nothing in this case since there is amazing amount of stuff you can put into bundle but if you want something specific you can still add it 
//      throw new IllegalStateException("Unable to serialize class + " + value.getClass().getCanonicalName()); 

       list.add(bis); 
      } 
      return sGson.toJson(list).getBytes(CHARSET); 
     } 
    } catch (Exception e) { 
     e.printStackTrace(); 
    } 
    throw new IllegalStateException("Unable to serialize " + bundle); 
} 

public static Bundle deserializeBundle(byte[] toDeserialize) { 
    try { 
     Bundle bundle = new Bundle(); 
     if (toDeserialize != null) { 
      SerializedItem[] bundleItems = new Gson().fromJson(new String(toDeserialize, CHARSET), SerializedItem[].class); 
      for (SerializedItem bis : bundleItems) { 
       if (String.class.getCanonicalName().equals(bis.getClassName())) 
        bundle.putString(bis.getKey(), new String(bis.getValue())); 
       else if (Integer.class.getCanonicalName().equals(bis.getClassName())) 
        bundle.putInt(bis.getKey(), ByteBuffer.wrap(bis.getValue()).getInt()); 
       else if (Double.class.getCanonicalName().equals(bis.getClassName())) 
        bundle.putDouble(bis.getKey(), ByteBuffer.wrap(bis.getValue()).getDouble()); 
       else if (Boolean.class.getCanonicalName().equals(bis.getClassName())) { 
        int v = ByteBuffer.wrap(bis.getValue()).getInt(); 
        bundle.putBoolean(bis.getKey(), v == 1); 
       } else 
        throw new IllegalStateException("Unable to deserialize class " + bis.getClassName()); 
      } 
     } 
     return bundle; 
    } catch (Exception e) { 
     e.printStackTrace(); 
    } 
    throw new IllegalStateException("Unable to deserialize " + Arrays.toString(toDeserialize)); 
} 

आप जिसे आप आसानी से, फ़ाइल नेटवर्क के माध्यम से भेज सकते हैं या ormLite के रूप में प्रयोग एसक्यूएल डेटाबेस के लिए स्टोर करने के लिए स्टोर कर सकते हैं बाइट सरणी के रूप में डेटा का प्रतिनिधित्व इस प्रकार है:

@DatabaseField(dataType = DataType.BYTE_ARRAY) 
    private byte[] mRawBundle; 

और SerializedItem:

public class SerializedItem { 


private String mClassName; 
private String mKey; 
private byte[] mValue; 

// + getters and setters 
} 

पुनश्च: उपरोक्त कोड Gson पुस्तकालय पर निर्भर है (जो बहुत आम है, बस आपको यह बताने के लिए)।

संबंधित मुद्दे

 संबंधित मुद्दे