2012-12-01 3 views
23

내 안드로이드 게임용 데이터를 모두 savedInstanceState 번들에 맞추기 위해 많은 노력을 기울였습니다. 많은 Parcelable 객체를 포함하여 많은 데이터가 있습니다. 이렇게하면 앱이 일시 중지되거나 방향이 바뀌면 Activity가 재생성되어 데이터가 손실되지 않습니다.번들을 SharedPreferences에 저장

그러나 최근에 나는 savedInstanceState 번들이 장기간 저장에 적합하지 않음을 발견했습니다. 그래서 저는 기존의 save 메소드를 장기적인 해결책으로 적용하여 게임 상태를 항상 복원 할 수있는 방법을 찾고 있습니다.

나는이 개 솔루션 지금까지 들어 본 적이 :

1) 방향 변경에 대한 savedInstanceState 번들을 사용하여, 또한 응용 프로그램이 완전히 종료해야하는 경우에 대한 SharedPrefs을 통합합니다.

기본적으로 똑같은 작업을 수행하기 위해 완전히 다른 두 가지 방법을 사용하기 때문에 이것은 비생산적인 것처럼 보입니다. 또한, 내 savedInstanceState 번들은 Parcelable 객체를 사용하기 때문에 각 객체에 SharedPrefs에 기록 할 수있는 또 다른 메소드를 제공해야합니다. 본질적으로 중복되고 관리하기 어려운 코드가 많이 있습니다.

2) savedInstanceState 번들을 직렬화하여 파일에 직접 작성하십시오.

나는이 문제에 대해 공개적으로 답변을하고 있지만 실제로 어떻게해야하는지에 대해서는 알지 못합니다. 그러나 안드로이드에서의 직렬화가 "코믹하게/쓸모 없게 느리다"는 말을 들었을 때 더 나은 해결책이있을 것이라는 희망을 계속 갖고 있습니다.

누군가 내게 해결책을 제공 할 수 있다면 매우 감사 할 것입니다.

+0

직렬화 클래스를 찾기 위해 직렬화하려면 찾기가 매우 어렵지 않습니다. 나는 그것을 사용하는 동안 극심한 지연을 발견하지 못했습니다. – mango

+0

찾을 수있는 유일한 정보는 Serializable을 구현해야한다는 것을 알려주지 만 번들은이 인터페이스를 구현하지 않습니다. – Dan

+0

나는 https://github.com/iamironz/binaryprefs 라이브러리를 권장한다. 구현을 통해 표준 자바와 같은 데이터를 저장할 수있다. 지속 가능한 인터페이스 (jdk의 외부화 가능 인터페이스) –

답변

3

이제이 문제에 대한 내 자신의 해결책을 제시했습니다.이 문제는 번들을 SharedPreferences에 저장하는 반자동 방식입니다. Bundle을 저장하는 것은 단 하나의 메소드 만 필요하지만 데이터를 다시 검색하여 Bundle로 되돌리기 때문에 반자동이라고 할 수 있습니다. 여기

은 번들을 저장하는 코드이다 : 나는 단지 내가 필요로하는 유형에 대한 사례를 작성한

SharedPreferences save = getSharedPreferences(SAVE, MODE_PRIVATE); 
Editor ed = save.edit(); 
saveBundle(ed, "", gameState); 

/** 
* Manually save a Bundle object to SharedPreferences. 
* @param ed 
* @param header 
* @param gameState 
*/ 
private void saveBundle(Editor ed, String header, Bundle gameState) { 
    Set<String> keySet = gameState.keySet(); 
    Iterator<String> it = keySet.iterator(); 

    while (it.hasNext()){ 
     key = it.next(); 
     o = gameState.get(key); 
     if (o == null){ 
      ed.remove(header + key); 
     } else if (o instanceof Integer){ 
      ed.putInt(header + key, (Integer) o); 
     } else if (o instanceof Long){ 
      ed.putLong(header + key, (Long) o); 
     } else if (o instanceof Boolean){ 
      ed.putBoolean(header + key, (Boolean) o); 
     } else if (o instanceof CharSequence){ 
      ed.putString(header + key, ((CharSequence) o).toString()); 
     } else if (o instanceof Bundle){ 
      saveBundle(header + key, ((Bundle) o)); 
     } 
    } 

    ed.commit(); 
} 

주,하지만 당신은 다른 유형을 포함 번들이있는 경우이 쉽게 적응할 수 있어야합니다.

이 메서드는 주어진 번들 안에 저장된 다른 Bundle 개체를 반복적으로 저장합니다. 그러나 Parcelable 오브젝트에서는 작동하지 않으므로 Parcelable 오브젝트를 변경하여 대신 Bundle에 저장되도록해야합니다. 소포와 번들은 꽤 비슷하기 때문에 이것은 그리 어렵지 않았습니다. 나는 번들이 소포보다 약간 느릴 수도 있다고 생각한다.

나는 이전의 모든 Parcelable 개체에 생성자를 작성하여 SharedPreferences에 저장된 데이터에서 다시 묶을 수 있도록했습니다. 필요한 데이터에 맞게 키를 재구성하는 것은 쉽습니다.다음과 같이

Bundle b { 
    KEY_X -> int x; 
    KEY_Y -> Bundle y { 
       KEY_Z -> int z; 
      } 
} 

이가 된 SharedPreferences에 저장됩니다 : 당신은 다음과 같은 데이터 구조를 가지고 말

KEY_X -> x 
KEY_YKEY_Z -> z 

그것은 세계에서 가장 예쁜의 방법은 아닐 수 있지만 작동하고, 그것은 나를 비용 이제는 onSaveInstanceState 메소드와 onPause 메소드가 동일한 기술을 사용하므로 대안보다 코드가 훨씬 적습니다.

+0

어떻게 이런 상황에서 번들을 얻을 수 있습니까? 감사합니다. –

+1

정확히 무엇을 의미하는지 모르겠습니다 ... 번들이 SharedPrefs에 저장되면 다른 번들처럼 검색 할 수 있습니다. – Dan

+0

여기에는 무엇이 핵심이고? 형태 어디에서이 arguements을 패스합니까 – ekjyot

18

재미있는 이번 주, 문제 47 번 Android Weekly이이 라이브러리를 풀어 냈습니다 : android complex preferences.

적합해야합니다.

+0

이것은 유망한 것처럼 보였지만 슬프게도 나는 그것을 작동시킬 수 없다. 아무것도. 나는 빈 것들을 포함하여 다양한 Bundle 객체들과, 그리고 Point와 같은 좀 더 간단한 객체들을 시도했지만 여전히 운이 없다. 저장시 "순환 참조"에 대해 불만을 표시하거나로드 할 때 "키 ___에 저장된 객체가 다른 게임의 인스턴스입니다"라고 불평합니다. 이것은 나를 미치게합니다 ... – Dan

+0

별도의 질문으로 게시 해주십시오. 내 주소에 의견을 추가하면 관심을 가질 수 있습니다. – Snicolas

+1

실제로 GSon을 사용하여 JSon으로 모든 것을 저장하고 있습니다 ... 어쨌든 내 느낌은 데이터가 무언가의 내부 클래스 일 수 있다는 것입니다. 이것은 매우 쉽게주기를 줄 것입니다. POJO는 별도의 수업입니까? – Snicolas

1

Dan의 답변을 Bundles를 자동으로 다시 생성하는 기능으로 확장하여 충돌 가능성이 적어졌습니다.

private static final String SAVED_PREFS_BUNDLE_KEY_SEPARATOR = "§§"; 

/** 
* Save a Bundle object to SharedPreferences. 
* 
* NOTE: The editor must be writable, and this function does not commit. 
* 
* @param editor SharedPreferences Editor 
* @param key SharedPreferences key under which to store the bundle data. Note this key must 
*   not contain '§§' as it's used as a delimiter 
* @param preferences Bundled preferences 
*/ 
public static void savePreferencesBundle(SharedPreferences.Editor editor, String key, Bundle preferences) { 
    Set<String> keySet = preferences.keySet(); 
    Iterator<String> it = keySet.iterator(); 
    String prefKeyPrefix = key + SAVED_PREFS_BUNDLE_KEY_SEPARATOR; 

    while (it.hasNext()){ 
     String bundleKey = it.next(); 
     Object o = preferences.get(bundleKey); 
     if (o == null){ 
      editor.remove(prefKeyPrefix + bundleKey); 
     } else if (o instanceof Integer){ 
      editor.putInt(prefKeyPrefix + bundleKey, (Integer) o); 
     } else if (o instanceof Long){ 
      editor.putLong(prefKeyPrefix + bundleKey, (Long) o); 
     } else if (o instanceof Boolean){ 
      editor.putBoolean(prefKeyPrefix + bundleKey, (Boolean) o); 
     } else if (o instanceof CharSequence){ 
      editor.putString(prefKeyPrefix + bundleKey, ((CharSequence) o).toString()); 
     } else if (o instanceof Bundle){ 
      savePreferencesBundle(editor, prefKeyPrefix + bundleKey, ((Bundle) o)); 
     } 
    } 
} 

/** 
* Load a Bundle object from SharedPreferences. 
* (that was previously stored using savePreferencesBundle()) 
* 
* NOTE: The editor must be writable, and this function does not commit. 
* 
* @param sharedPreferences SharedPreferences 
* @param key SharedPreferences key under which to store the bundle data. Note this key must 
*   not contain '§§' as it's used as a delimiter 
* 
* @return bundle loaded from SharedPreferences 
*/ 
public static Bundle loadPreferencesBundle(SharedPreferences sharedPreferences, String key) { 
    Bundle bundle = new Bundle(); 
    Map<String, ?> all = sharedPreferences.getAll(); 
    Iterator<String> it = all.keySet().iterator(); 
    String prefKeyPrefix = key + SAVED_PREFS_BUNDLE_KEY_SEPARATOR; 
    Set<String> subBundleKeys = new HashSet<String>(); 

    while (it.hasNext()) { 

     String prefKey = it.next(); 

     if (prefKey.startsWith(prefKeyPrefix)) { 
      String bundleKey = StringUtils.removeStart(prefKey, prefKeyPrefix); 

      if (!bundleKey.contains(SAVED_PREFS_BUNDLE_KEY_SEPARATOR)) { 

       Object o = all.get(prefKey); 
       if (o == null) { 
        // Ignore null keys 
       } else if (o instanceof Integer) { 
        bundle.putInt(bundleKey, (Integer) o); 
       } else if (o instanceof Long) { 
        bundle.putLong(bundleKey, (Long) o); 
       } else if (o instanceof Boolean) { 
        bundle.putBoolean(bundleKey, (Boolean) o); 
       } else if (o instanceof CharSequence) { 
        bundle.putString(bundleKey, ((CharSequence) o).toString()); 
       } 
      } 
      else { 
       // Key is for a sub bundle 
       String subBundleKey = StringUtils.substringBefore(bundleKey, SAVED_PREFS_BUNDLE_KEY_SEPARATOR); 
       subBundleKeys.add(subBundleKey); 
      } 
     } 
     else { 
      // Key is not related to this bundle. 
     } 
    } 

    // Recursively process the sub-bundles 
    for (String subBundleKey : subBundleKeys) { 
     Bundle subBundle = loadPreferencesBundle(sharedPreferences, prefKeyPrefix + subBundleKey); 
     bundle.putBundle(subBundleKey, subBundle); 
    } 


    return bundle; 
} 
+0

https://commons.apache.org/proper/commons-lang/javadocs/api-2.6/src-html/org/ apache/commons/lang/StringUtils.html StringUtils 함수가 수행하는 작업을 얻으려면 (안드로이드에는 포함되지 않음) –

관련 문제