无法在listview上恢复状态

时间:2016-02-09 17:14:06

标签: android listview android-adapter

我有一个应用程序,允许用户选择一个选项,并在列表视图中显示某个列表。我遇到了保存和恢复状态的问题。我有一个list_mode,它取决于用户选择的选项。到目前为止,我已经保存了适配器的状态但是恢复它导致了一个问题(我知道它正在保存,因为当我在onCreate中检查customAdapter.onRestoreInstanceState(savedInstanceState)时它会显示正确的项目选择,但我很难将其恢复到列表视图。它将在恢复时崩溃。它在getAllItems.clear和.addAll上崩溃。我甚至将其硬编码到其中一个列表但它没有&#当我评论那条线路时,它会在主要活动中崩溃。当我谈到Java和Android时,我仍然在学习。我不知道我离我有多近或有多远任何人都可以提供有关我做错事以及如何使其发挥作用的见解吗?谢谢

列表适配器:

public class ListAdapter extends BaseAdapter {
private static final String KEY_ADAPTER_STATE = "ListAdapter.KEY_ADAPTER_STATE";
public enum ListMode {
    IMAGES_AND_TEXT,
    IMAGES_ONLY,
    TEXT_ONLY
}

private ListMode mListMode = ListMode.IMAGES_AND_TEXT;

private ArrayList<Item> mItems;

private ArrayList<Item> mImages;

private ArrayList<Item> mTexts;

@Override
public int getCount() {
    switch (mListMode) {
        case IMAGES_AND_TEXT:
            return mItems == null ? 0 : mItems.size();
        case IMAGES_ONLY:
            return mImages == null ? 0 : mImages.size();
        case TEXT_ONLY:
            return mTexts == null ? 0 : mTexts.size();
    }
    return 0;
}

@Override
public Item getItem(int position) {
    switch (mListMode) {
        case IMAGES_AND_TEXT:
            return mItems == null ? null : mItems.get(position);
        case IMAGES_ONLY:
            return mImages == null ? null : mImages.get(position);
        case TEXT_ONLY:
            return mTexts == null ? null : mTexts.get(position);

    }
    return null;
}
public ArrayList getAllItems() {
    switch (mListMode) {
        case IMAGES_AND_TEXT:
            return mItems;
        case IMAGES_ONLY:
            return mImages;
        case TEXT_ONLY:
            return  mTexts;

    }
    return null;
}

@Override
public long getItemId(int position) {
    return position;    // not really used
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {

    View v = null;
    TextView tn = null;
    ImageView img = null;

    if (convertView == null) {
        LayoutInflater vi;
        vi = LayoutInflater.from(parent.getContext());
        v = vi.inflate(R.layout.list, null);
    } else {
        v=convertView;
    }

    Item p = getItem(position);
    tn = (TextView) v.findViewById(R.id.tvText);
    img = (ImageView) v.findViewById(R.id.thumbnail);
    if (p.getmType().equals("image")) {
        img.setVisibility(View.VISIBLE);
        Picasso.with(parent.getContext()).load(p.getmData()).error((R.drawable.placeholder_error)).placeholder(R.drawable.placeholder).resize(90,0).into(img);
        tn.setText("ID: " + p.getmID()+"\nTYPE: " + p.getmType() +"\nDate: " + p.getmDate()+ "\nImage URL: " +  p.getmData());
    } else {
        img.setVisibility(View.GONE);
        tn.setText("ID: " + p.getmID()+"\nTYPE: " + p.getmType() +"\nDate: " + p.getmDate()+ "\nText Data: " +  p.getmData());
    }
    return v;
}


public void setListMode(ListMode listMode) {
    mListMode = listMode;
    notifyDataSetChanged();
}

public void setItems(JSONArray jsonArray) throws JSONException {

    mItems = new ArrayList<>();
    mImages = new ArrayList<>();
    mTexts = new ArrayList<>();
    for (int i = 0; i < jsonArray.length(); i++) {
        Item item = new Item((JSONObject) jsonArray.get(i));
        mItems.add(item);
        if (item.getmType().equals("image")) {
            mImages.add(item);
        }
        if (item.getmType().equals("text")) {
            mTexts.add(item);
        }
    }

    notifyDataSetChanged();
}
public void onSaveInstanceState(Bundle savedInstanceState) {
    savedInstanceState.putParcelableArrayList("list_items", getAllItems());
}

public void onRestoreInstanceState(Bundle savedInstanceState) {
    if (savedInstanceState.containsKey("list_items")) {
        //ArrayList<Item> objects = savedInstanceState.getParcelableArrayList(KEY_ADAPTER_STATE);
        //getAllItems().clear();
        //getAllItems().addAll(objects);
        //mImages.clear();
        //mImages.addAll(objects);
    }
}

}

主要活动:

myListView = (ListView) findViewById(R.id.listViewID);
    customAdapter = new ListAdapter();
    if(savedInstanceState!=null) {
        //When I put a breakpoint here I see it's getting the correct list
        customAdapter.onRestoreInstanceState(savedInstanceState);
    }

    if (savedInstanceState != null && savedInstanceState.containsKey("list_items")) {
        //When I remove the .clear and .addAll it then crashes on this line
        myListView.onRestoreInstanceState(savedInstanceState.getParcelable("list_items"));
        myListView.setAdapter(customAdapter);
    }
    else{
        if (isNetworkAvailable()) {
            getData theJsonData = new getData();
            theJsonData.execute();
        }
        else{
            Toast.makeText(getApplicationContext(), "No internet connection", Toast.LENGTH_SHORT).show();
            tvNoInet.setVisibility(View.VISIBLE);
        }
    }
@Override
public void onSaveInstanceState(Bundle savedInstanceState) {
    super.onSaveInstanceState(savedInstanceState);
    //Not sure what I should put here or if what I have is right
   customAdapter.onSaveInstanceState(savedInstanceState);

}
//This is the code that sets the list_mode when the user selects an option
if (id == R.id.all) {
        item.setChecked(true);
        customAdapter.setListMode(ListAdapter.ListMode.IMAGES_AND_TEXT);
        myListView.setSelectionAfterHeaderView();
        return true;

    }
    if (id == R.id.images) {
        item.setChecked(true);
        customAdapter.setListMode(ListAdapter.ListMode.IMAGES_ONLY);
        myListView.setSelectionAfterHeaderView();
        return true;

    }
    if (id == R.id.text) {
        item.setChecked(true);
        customAdapter.setListMode(ListAdapter.ListMode.TEXT_ONLY);
        myListView.setSelectionAfterHeaderView();
        return true;
    }

我的Item类:

public class Item implements Parcelable{
private String mID;
private String mType;
private String mDate;
private String mData;

public Item(String mID,String mType, String mDate, String mData)  {
    this.mType = mType;
    this.mID = mID;
    this.mDate = mDate;
    this.mData = mData;
}
public Item(JSONObject jsonItem) throws JSONException {
    String itemID=null;
    String itemType=null;
    String itemDate=null;
    String itemData=null;

    if (jsonItem.has("id")) {
        itemID=jsonItem.getString("id");
    }
    if (jsonItem.has("type")) {
        itemType=jsonItem.getString("type");
    }
    if (jsonItem.has("date")){
        itemDate=jsonItem.getString("date");
    }
    if (jsonItem.has("data")){
        itemData=jsonItem.getString("data");
    }
    this.mID=itemID;
    this.mType=itemType;
    this.mDate=itemDate;
    this.mData=itemData;
}


protected Item(Parcel in) {
    String[] data = new String[4];
    in.readStringArray(data);
    this.mID = data[0];
    this.mType = data[1];
    this.mDate = data[2];
    this.mData = data[3];

}

public static final Creator<Item> CREATOR = new Creator<Item>() {
    @Override
    public Item createFromParcel(Parcel in) {
        return new Item(in);
    }

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

public String getmID() {
    return mID;
}

public String getmType() {
    return mType;
}

public String getmDate() {
    return mDate;
}

public String getmData() {
    return mData;
}

@Override
public String toString() {
    return "{" +
            "ID='" + mID + '\'' +
            ", Type='" + mType + '\'' +
            ", Date='" + mDate + '\'' +
            ", Data='" + mData + '\'' +
            '}';
}

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

@Override
public void writeToParcel(Parcel dest, int flags) {

    String[] data = new String[4];
    data[0] = mID;
    data[1] = mType;
    data[2] = mDate;
    data[3] = mData;
    dest.writeStringArray(data);
}
}

更新:这就是代码现在的样子。当我选择某个列表,然后旋转屏幕时,它正在工作。它停留在当前选定的列表中。现在的问题是,在设备旋转后选择新列表时,列表视图完全空白

if(savedInstanceState!=null) {
        customAdapter.onRestoreInstanceState(savedInstanceState);

        if (savedInstanceState.containsKey(KEY_LIST_VIEW_STATE)) {
            myListView.onRestoreInstanceState(savedInstanceState.getParcelable(KEY_LIST_VIEW_STATE));
            myListView.setAdapter(customAdapter);
        }

    }

    else{
        if (isNetworkAvailable()) {
            getData theJsonData = new getData();
            theJsonData.execute();
            tvNoInet.setVisibility(View.GONE);
            btnRetry.setVisibility(View.GONE);
        } else {
            Toast.makeText(getApplicationContext(), "No internet connection", Toast.LENGTH_SHORT).show();
            tvNoInet.setVisibility(View.VISIBLE);
            btnRetry.setVisibility(View.VISIBLE);
        }
    }

@Override
public void onSaveInstanceState(Bundle savedInstanceState) {
    super.onSaveInstanceState(savedInstanceState);
    customAdapter.onSaveInstanceState(savedInstanceState);
    savedInstanceState.putParcelable(KEY_LIST_VIEW_STATE, myListView.onSaveInstanceState());


}

和我更新的列表适配器:

 private ListMode mListMode = ListMode.IMAGES_AND_TEXT;

private ArrayList<Item> mItems= new ArrayList<>();

private ArrayList<Item> mImages= new ArrayList<>();

private ArrayList<Item> mTexts= new ArrayList<>();

   public void onSaveInstanceState(Bundle savedInstanceState) {
    //savedInstanceState.putParcelableArrayList("list_items", getAllItems());
    savedInstanceState.putParcelableArrayList(KEY_ADAPTER_STATE, getAllItems());
}

public void onRestoreInstanceState(Bundle savedInstanceState) {
    if (savedInstanceState.containsKey(KEY_ADAPTER_STATE)) {
        ArrayList<Item> objects = savedInstanceState.getParcelableArrayList(KEY_ADAPTER_STATE);
        getAllItems().clear();
        getAllItems().addAll(objects);
        //mImages.clear();
        //mImages.addAll(objects);
    }
}

这是切换列表的选项菜单中的代码。如果我还没有旋转屏幕,那么这是有效的。当我旋转屏幕并选择不同的列表时,列表视图则为空白。如果我选择&#34;全部&#34;如果还原,应该显示所有项目,然后显示我之前选择的任何列表。因此,如果我首先选择了“仅图像”,则旋转屏幕,一切都显示正确,如果我向后旋转屏幕并再次选择“仅文本”或“仅图像”,则列表为空白,如果我选择&#34;全部&#34;然后显示我第一次选择的列表(在这种情况下只显示图像)

if (id == R.id.all) {
        item.setChecked(true);
        customAdapter.setListMode(ListAdapter.ListMode.IMAGES_AND_TEXT);
        myListView.setSelectionAfterHeaderView();
        return true;

    }
    if (id == R.id.images) {
        item.setChecked(true);
        customAdapter.setListMode(ListAdapter.ListMode.IMAGES_ONLY);
        myListView.setSelectionAfterHeaderView();
        return true;

    }
    if (id == R.id.text) {
        item.setChecked(true);
        customAdapter.setListMode(ListAdapter.ListMode.TEXT_ONLY);
        myListView.setSelectionAfterHeaderView();
        return true;
    }

2 个答案:

答案 0 :(得分:0)

如果您在

之前没有致电ListAdapter.getAllItems().clear()而致电ListAdapter.setItems(),您的应用就会崩溃

原因:如果ListAdapter.getAllItems()mItemsmImages未初始化,mTexts可能会返回null。

一种解决方法可能是

public class ListAdapter extends ... {
    ...
    private ArrayList<Item> mItems = new ArrayList<>();
    private ArrayList<Item> mImages = new ArrayList<>();
    private ArrayList<Item> mTexts = new ArrayList<>();
    ...
    }

答案 1 :(得分:0)

好吧,因为我让你陷入了这个烂摊子...... :)。

我在这种情况下做的事情是将保存的实例状态Bundle传递给适配器的构造函数。由于您创建了ItemParcelable,其他一切都应该很简单。

    public ListAdapter(Bundle savedInstanceState) {

        if (savedInstanceState != null) {

            int ordinal = savedInstanceState.getInt("adapter_mode", 0);
            mListMode = ListMode.values()[ordinal];

            ArrayList<Item> items = 
                    savedInstanceState.getParcelableArrayList(KEY_ADAPTER_STATE);
            if (items != null) {
                setItems(items);
            }
        }
    }


    public void onSaveInstanceState(Bundle outState) {
        outState.putInt("adapter_mode", mListMode.ordinal());
        outState.putParcelableArrayList(KEY_ADAPTER_STATE, mItems);
    }

因此,使用构造函数中保存的实例状态,您不需要显式方法来恢复适配器状态。

    public void setItems(JSONArray jsonArray) throws JSONException {

        List<Item> items = new ArrayList<>();
        for (int i = 0; i < jsonArray.length(); i++) {
            items.add(new Item((JSONObject) jsonArray.get(i)));
        }
        setItems(items);
    }

    private void setItems(List<Item> items) {

        for (Item item : items) {
            mItems.add(item);
            if (item.getmType().equals("image")) {
                mImages.add(item);
            }
            if (item.getmType().equals("text")) {
                mTexts.add(item);
            }
        }

        notifyDataSetChanged();
     }