notifyDataSetChanged after configuration change

给你一囗甜甜゛ 提交于 2020-01-22 15:56:29

问题


I'm doing some test after change device configuration (change language, orientation, etc), and i notice that after this, the method "notifyDataSetChanged()" is not working.

The action example:

I'm calling updateList() everytime i do an action like delete, save, etc. The user click a delete button, a DialogFragment is shown, "Are you sure you want to delete?", when i change the orientation, or the language, or any configuration of the device and then click "yes" on the Dialog, the data is removed, but the list doesn't update. I need to quit the activity, then go back to see the alteration.

BookAdapter:

public void updateList(ArrayList<Book> books) {
     bookList = books;
     notifyDataSetChanged();
}

What can i do to make it works after the configuration change?

Edit:

BookAdapter Constructor:

public BookAdapter(Context c, ArrayList<Book> books) {
    context = c;
    bookList = books
    bookDAO = BookDAO.getInstance(context);
}

BookFragment:

public class BookFragment extends Fragment {

    private BookDAO bookDAO;

    private BookAdapter bookAdapter;

    private ListView listBook;

    private View view;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

        bookDAO = bookDAO.getInstance(getActivity());

        view = inflater.inflate(R.layout.book_tab, container, false);

        ArrayList<Book> listBook = null;

        try {
            llistBook = bookDAO.getAll();
        } catch (Exception e) {
            Toast.makeText(getActivity(), e.getMessage(), Toast.LENGTH_LONG).show();
            return view;
        }

        bookAdapter = new BookAdapter(getActivity(), listBook);
        listBook = (ListView)view.findViewById(R.id.listBook);
        listBook.setAdapter(bookAdapter);

        return view;

    }

}

回答1:


The problem occurs because every time your rotate, change language, etc... the activity is recreated and your fragments are also recreated (new instance), so the notififyDataSetChanged is actually notifying the old instances of your fragments. A solution for that would be. Make your fragments static. Then you create some refresh method for your fragments, and called it when you press yes for your dialog.

In your activity you should have something like this.

private static BookFragment  bookFragment;
...
@Override
protected void onCreate(Bundle savedInstanceState) {
    ...
    if (fragment1 == null) {
        bookFragment = new BookFragment();
    }

    ...
}

Create some interface like:

public interface Refreshable {
    public void refresh();
}

Then implement this interface all your fragments. In the method that is called when the dialog is answered positively you should call

...
fragment.refresh();
...

Inside the refresh method of you fragment you can call its adapter method updateList(...)

Might not be the prettier solution, but it works....

Why this happen... Google's Android Dev Team might know.




回答2:


You can try implementing BookAdapter as a Singleton to confirm that you are not calling updateList(..) from a stale reference.

Changes that you will need to make:

// I am assuming that you are using a BaseAdapter because
// BookAdapter's constructor that you provided in the code above
// does not contain a call to super(....)
public class BookAdapter extends BaseAdapter {

    private static BookAdapter mAdapter;
    private Context context;
    private static ArrayList<Book> bookList;
    private BookDAO bookDAO;

    // To keep at most one instance of BookAdapter
    public static BookAdapter getInstance(Context con, ArrayList<Book> books) {

        // If an instance exists, return it
        if (mAdapter != null) {
            bookList = books;
            return mAdapter;
        }

        // Else, craete a new instance
        mAdapter =  new MyAdapter(con, books);
        return mAdapter;
    }

    // BookAdapter's only constructor is declared as private to restrict access
    private BookAdapter(Context con, ArrayList<Book> books) {
        context = con;
        bookList = books;
        bookDAO = BookDAO.getInstance(context);
    }

    public void updateList(ArrayList<Book> books) {
        bookList = books;
        notifyDataSetChanged();
    }

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

        // Retrieve object
        Book bookItem = bookList.get(position);

        ....
        ....

}

}

This is how the Fragment's onCreateView will change:

bookAdapter = BookAdapter.getInstance(getActivity(), listBook);

Code that will be executed when the user presses yes to Are you sure you want to delete?:

// Remove entry from bookDAO
// Remove entry from listBook
// OR update listBook:
try {
    listBook = bookDAO.getAll();
} catch (Exception e) {
    Toast.makeText(getActivity(), e.getMessage(), Toast.LENGTH_LONG).show();
}

// Assertion: "listBook" does not contain the 
// item that was just deleted from "bookDAO"

// Update ListView's contents
bookAdapter.updateList(listBook);



回答3:


I am using an ArrayList of Strings in my GridViewAdapter which extends BaseAdapter.

so in case i changed the data concerning the List, i cann notifyDataSetChanged() on the Adapter. I dont really see the point why you cant call it?

So what i would do is ovverride this method, and just call notifyDataSetChanged()

@Override
public void onConfigurationChanged(Configuration newConfig) {
   super.onConfigurationChanged(newConfig);
   adapter.notifyDataSetChanged();
}

Besides that, does your Book data chnage based on your configuration/orientation?




回答4:


Try using the same list for the whole adapter lifecycle, and change only its content:

public class BookAdapter extends ArrayAdapter<Book> {

    private final booklist;
    // ..

    public BookAdapter(Context c, ArrayList<Book> books) {
        super(c, R.layout.yourlayout, books);
        context = c;
        bookList = books
        bookDAO = BookDAO.getInstance(context);
    }

    public void updateList(ArrayList<Book> books) {
        bookList.clear();
        boolList.addAll(books);
        notifyDataSetChanged();
    }

    // ..
}



回答5:


Why are you keeping your View as a data member?

When keeping a view across configuration changes, you hold a reference to the previous instance, before the configuration change was happening. Since it's the view holding your list - it may miss data updates.

Try to remove this field, and the use of it, and see if the list now updates.




回答6:


I think the problem comes from the fact that any configuration change such as the orientation will restart your current Activity.

Because of this, I guess some parts of your code are still referencing the previous activity that does not exist anymore and the notifyDataSetChanged is not working anymore.

There are 2 things you can quickly try:

  1. Add this line in the manifest file for your activity: android:configChanges="orientation|locale". This change means to the system that you will handle yourself the changes to do during orientation or language changes. Therefore, the app will not recreate the activity by itself anymore (so the activity should work the same).

  2. The other trick can be to add this line at the beginning of the function onCreateView: setRetainInstance(true);. This line will retain the fragment state during configuration changes as the documentation explains:

Control whether a fragment instance is retained across Activity re-creation (such as from a configuration change). This can only be used with fragments not in the back stack. If set, the fragment lifecycle will be slightly different when an activity is recreated:

  • onDestroy() will not be called (but onDetach() still will be, because the fragment is being detached from its current activity).
  • onCreate(Bundle) will not be called since the fragment is not being re-created.
  • onAttach(Activity) and onActivityCreated(Bundle) will still be called.

Just be informed that as explained the Fragment lifecycle will change a little.

3) Last option could be to retain the activity state using onSaveInstanceState and onRestoreInstanceState as explained in details in this answer: https://stackoverflow.com/a/151940/2206688



来源:https://stackoverflow.com/questions/18773251/notifydatasetchanged-after-configuration-change

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!