尝试使用onSaveInstanceState()恢复String [] []时“java.lang.NullPointerException:尝试获取null数组的长度”

问题描述 投票:0回答:2

当我点击主页按钮(在模式 - 不保持活动)后回到活动和片段时,我试图使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);
  }
}
android nullpointerexception parcel onsaveinstancestate
2个回答
1
投票

一旦你必须读取/写入本机不支持的Parcel,我建议创建一个ParcelableUtils类来帮助组织你的代码。在这种情况下,String[][]本身不受支持,所以我创建了处理它的方法。

public class ParcelableUtils {

    private ParcelableUtils() {
        throw new UnsupportedOperationException("static methods only");
    }

    public static String[][] createStringArrayArray(Parcel in) {
        int size = in.readInt();

        if (size != -1) {
            String[][] arrayArray = new String[size][];

            for (int i = 0; i < size; i++) {
                arrayArray[i] = in.createStringArray();
            }

            return arrayArray;
        } else {
            return null;
        }
    }

    public static void writeStringArrayArray(Parcel dest, String[][] arrayArray) {
        if (arrayArray != null) {
            dest.writeInt(arrayArray.length);

            for (String[] array : arrayArray) {
                dest.writeStringArray(array);
            }
        } else {
            dest.writeInt(-1);
        }
    }
}

总体技术是首先编写数组数组的大小,然后编写每个数组。如果你看一下Parcel.java的来源,这就是writeStringArray()的实现方式。另一方面也是如此:我们读取数组数组的大小,然后直接从Parcel创建每个数组。

有了这个,你在Parcelable上的WordSearch实现变得非常容易处理:

private WordSearch(Parcel in) {
    this.sourceLanguage = in.readString();
    this.targetLanguage = in.readString();
    this.word = in.readString();
    this.characterGrid = ParcelableUtils.createStringArrayArray(in);
    this.translations = in.createStringArrayList();
}

@Override
public void writeToParcel(Parcel dest, int flags) {
    dest.writeString(this.sourceLanguage);
    dest.writeString(this.targetLanguage);
    dest.writeString(this.word);
    ParcelableUtils.writeStringArrayArray(dest, characterGrid);
    dest.writeStringList(this.translations);
}

0
投票

替换以下语句:

in.readStringArray(this.characterGrid[i]);

this.characterGrid[i] = in.createStringArray();
© www.soinside.com 2019 - 2024. All rights reserved.