Я пытался сделать так, чтобы WordSearch можно было восстановить, когда я вернусь к активности и фрагментирую после того, как я нажму кнопку «Домой» (В режиме - Не сохранять действия),
Нажмите кнопку домой: должен вызвать onSaveInstance.
Нажмите приложение еще раз: должно вернуться в приложение и восстановить его состояние раньше.
Но я почему-то не смог вернуть поле String [] [] this.characterGrid.
Кто-нибудь знает почему?
import android.os.Parcel;
import android.os.Parcelable;
import android.util.Log;
import com.google.gson.annotations.SerializedName;
import java.util.Arrays;
import java.util.List;
public class WordSearch implements Parcelable {
public static final Parcelable.Creator<WordSearch> CREATOR =
new Parcelable.Creator<WordSearch>() {
public WordSearch createFromParcel(Parcel source) {
return new WordSearch(source);
}
public WordSearch[] newArray(int size) {
return new WordSearch[size];
}
};
public final String word;
public final @SerializedName("character_grid") String[][] characterGrid;
public final @SerializedName("word_locations") List<String> translations;
public final @SerializedName("source_language") String sourceLanguage;
public final @SerializedName("target_language") String targetLanguage;
WordSearch(String sourceLanguage, String targetLanguage, String word,
String[][] characterGrid, List<String> translations) {
this.sourceLanguage = sourceLanguage;
this.targetLanguage = targetLanguage;
this.word = word;
this.characterGrid = characterGrid;
this.translations = translations;
}
private WordSearch(Parcel in) {
this.sourceLanguage = in.readString();
this.targetLanguage = in.readString();
this.word = in.readString();
int size = in.readInt();
Log.d("gzl", "WordSearch characterGrid size = " + size);
this.characterGrid = new String[size][];
Log.d("gzl", "WordSearch characterGrid size = " + size);
for (int i = 0; i < size; i++) {
Log.d("gzl", "WordSearch " + Arrays.toString(this.characterGrid[i]));
in.readStringArray(this.characterGrid[i]);
// if (this.characterGrid[i] != null) {
// in.readStringArray(this.characterGrid[i]);
// }
Log.d("gzl", "WordSearch characterGrid position " + i + " "
+ Arrays.toString(this.characterGrid[i]));
}
this.translations = in.createStringArrayList();
}
@Override public int describeContents() {
return 0;
}
@Override public void writeToParcel(Parcel dest, int flags) {
dest.writeString(this.sourceLanguage);
dest.writeString(this.targetLanguage);
dest.writeString(this.word);
dest.writeInt(this.characterGrid.length);
Log.d("gzl", "writeToParcel " + this.characterGrid.length + "");
for (String[] array : this.characterGrid) {
Log.d("gzl", "writeToParcel " + Arrays.toString(array));
dest.writeStringArray(array);
}
dest.writeStringList(this.translations);
Log.d("gzl", "writeToParcel\n");
RuntimeException re = new RuntimeException();
re.fillInStackTrace();
Log.e("gzl", "writeToParcel stackTrace", re);
}
}
Фрагмент:
@Override
public void onResume() {
super.onResume();
if (wordSearches != null) {
// Log.d("gzl", wordSearches.get(position).toString());
Log.d("gzl", "onResume position = " + position);
Log.d("gzl", "onResume wordSearches = " + wordSearches);
setupWordSearch(wordSearches.get(position), boardView, sourceWord);
}
}
@Override
public void onSaveInstanceState(@NonNull Bundle outState) {
if (wordSearches != null) {
outState.putParcelableArrayList(WORD_SEARCHES, wordSearches);
outState.putInt(CURRENT_POSITION, position);
Log.d("gzl", "onSaveInstanceState");
Log.d("gzl", wordSearches.toString());
}
super.onSaveInstanceState(outState);
}
Как восстановить данные:
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (savedInstanceState != null) {
position = savedInstanceState.getInt(CURRENT_POSITION);
// wordSearches = savedInstanceState.getParcelableArrayList(WORD_SEARCHES);
wordSearches = savedInstanceState.<WordSearch>getParcelableArrayList(WORD_SEARCHES);
if (wordSearches != null) {
Log.d("gzl", "onCreate " + wordSearches.toString());
} else {
Log.d("gzl", "onCreate " + "wordSearches = null");
}
Log.d("gzl", "onCreate savedInstanceState " + savedInstanceState.toString());
} else {
getWordSearches();
}
}
Я получил следующий logcat:
2019-03-04 23:42:13.317 25699-25699/com.gongzelong.duolingowordsearch D/gzl: WordSearch characterGrid size = 8
2019-03-04 23:42:16.830 25699-25713/com.gongzelong.duolingowordsearch W/zygote64: Clearing bad or obsolete profile data from file /data/misc/profiles/cur/0/com.gongzelong.duolingowordsearch/primary.prof: Profile EOF reached prematurely for ReadProfileHeader
2019-03-04 23:42:21.947 25699-25699/com.gongzelong.duolingowordsearch D/gzl: WordSearch characterGrid size = 8
2019-03-04 23:42:25.529 25699-25699/com.gongzelong.duolingowordsearch D/gzl: WordSearch null
2019-03-04 23:46:52.471 25699-25699/com.gongzelong.duolingowordsearch D/AndroidRuntime: Shutting down VM
2019-03-04 23:46:52.508 25699-25699/com.gongzelong.duolingowordsearch E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.gongzelong.duolingowordsearch, PID: 25699
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.gongzelong.duolingowordsearch/com.gongzelong.duolingowordsearch.MainActivity}: java.lang.NullPointerException: Attempt to get length of null array
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2778)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2856)
at android.app.ActivityThread.-wrap11(Unknown Source:0)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1589)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6494)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)
Caused by: java.lang.NullPointerException: Attempt to get length of null array
at android.os.Parcel.readStringArray(Parcel.java:1261)
at com.gongzelong.duolingowordsearch.model.WordSearch.<init>(WordSearch.java:48)
at com.gongzelong.duolingowordsearch.model.WordSearch.<init>(WordSearch.java:12)
at com.gongzelong.duolingowordsearch.model.WordSearch$1.createFromParcel(WordSearch.java:16)
at com.gongzelong.duolingowordsearch.model.WordSearch$1.createFromParcel(WordSearch.java:14)
at android.os.Parcel.readParcelable(Parcel.java:2860)
at android.os.Parcel.readValue(Parcel.java:2754)
at android.os.Parcel.readListInternal(Parcel.java:3184)
at android.os.Parcel.readArrayList(Parcel.java:2384)
at android.os.Parcel.readValue(Parcel.java:2775)
at android.os.Parcel.readArrayMapInternal(Parcel.java:3123)
at android.os.BaseBundle.initializeFromParcelLocked(BaseBundle.java:273)
at android.os.BaseBundle.unparcel(BaseBundle.java:226)
at android.os.Bundle.getSparseParcelableArray(Bundle.java:1009)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1361)
at android.support.v4.app.FragmentManagerImpl.moveFragmentToExpectedState(FragmentManager.java:1784)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1852)
at android.support.v4.app.FragmentManagerImpl.dispatchStateChange(FragmentManager.java:3269)
at android.support.v4.app.FragmentManagerImpl.dispatchCreate(FragmentManager.java:3223)
at android.support.v4.app.FragmentController.dispatchCreate(FragmentController.java:190)
at android.support.v4.app.FragmentActivity.onCreate(FragmentActivity.java:369)
at android.support.v7.app.AppCompatActivity.onCreate(AppCompatActivity.java:85)
at com.gongzelong.duolingowordsearch.MainActivity.onCreate(MainActivity.java:14)
Но я могу правильно написать ToParcel:
2019-03-04 23:41:43.149 25699-25699/com.gongzelong.duolingowordsearch D/gzl: writeToParcel [ü, á, p, a, n]
2019-03-04 23:41:43.150 25699-25699/com.gongzelong.duolingowordsearch D/gzl: writeToParcel [k, a, k, m, l]
2019-03-04 23:41:43.150 25699-25699/com.gongzelong.duolingowordsearch D/gzl: writeToParcel [a, x, q, e, h]
2019-03-04 23:41:43.150 25699-25699/com.gongzelong.duolingowordsearch D/gzl: writeToParcel [p, s, a, j, í]
2019-03-04 23:41:43.150 25699-25699/com.gongzelong.duolingowordsearch D/gzl: writeToParcel [á, q, l, j, l]
Обновление:
Я пытался добавить разрешение (чтение и запись), как это в MainActivity # onCreate, но это не такисправить ошибку.
if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)!= PackageManager.PERMISSION_GRANTED) {
//android 6.0 之后需要在activity中动态获取权限
if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) {
//申请WRITE_EXTERNAL_STORAGE权限
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},
1);
}
if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) {
//申请WRITE_EXTERNAL_STORAGE权限
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
1);
}
}