3

我在更改设备配置(更改语言、方向等)后进行了一些测试,我注意到在此之后,方法“notifyDataSetChanged()”不起作用。

动作示例:

每次我执行删除、保存等操作时,我都会调用 updateList()。当我更改方向或语言或设备的任何配置,然后单击对话框上的“是”,数据被删除,但列表不会更新。我需要退出活动,然后回去查看更改。

图书适配器:

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

配置更改后我该怎么做才能使其正常工作?

编辑:

BookAdapter 构造函数:

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

书段:

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;

    }

}
4

6 回答 6

6

您可以尝试实现BookAdapter为 Singleton 以确认您不是updateList(..)从过时的引用中调用。

您需要进行的更改:

// 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);

        ....
        ....

}

}

这就是 Fragment 的 onCreateView 将如何改变:

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

当用户按下是时将执行的代码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);
于 2013-09-18T09:39:02.493 回答
2

出现问题的原因是每次您的旋转、更改语言等......活动都会重新创建并且您的片段也会重新创建(新实例),因此 notififyDataSetChanged 实际上是在通知片段的旧实例。一个解决方案是。使您的片段静态。然后为您的片段创建一些刷新方法,并在您为对话框按“是”时调用它。

在你的活动中,你应该有这样的东西。

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

    ...
}

创建一些界面,例如:

public interface Refreshable {
    public void refresh();
}

然后实现这个接口你所有的片段。在对话得到肯定回答时调用的方法中,您应该调用

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

在片段的刷新方法中,您可以调用其适配器方法 updateList(...)

可能不是更漂亮的解决方案,但它有效....

为什么会这样……谷歌的 Android 开发团队可能知道。

于 2013-09-23T14:46:52.927 回答
0

我在扩展 BaseAdapter 的 GridViewAdapter 中使用字符串的 ArrayList。

因此,如果我更改了有关列表的数据,我无法在适配器上 notifyDataSetChanged()。我真的不明白为什么你不能打电话?

所以我要做的是覆盖这个方法,然后调用 notifyDataSetChanged()

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

除此之外,您的 Book 数据是否会根据您的配置/方向而变化?

于 2013-09-16T19:46:09.117 回答
0

尝试在整个适配器生命周期中使用相同的列表,并仅更改其内容:

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();
    }

    // ..
}
于 2013-09-17T03:18:24.743 回答
0

您为什么将您的视图保留为数据成员?

在查看配置更改时,您在配置更改发生之前持有对前一个实例的引用。由于它是保存您列表的视图 - 它可能会错过数据更新。

尝试删除此字段,并使用它,并查看列表现在是否更新。

于 2013-09-20T11:30:37.527 回答
-1

我认为问题在于任何配置更改(例如方向)都会重新启动当前的Activity.

因此,我猜您的代码的某些部分仍在引用以前不再存在且notifyDataSetChanged不再工作的活动。

您可以快速尝试两件事:

  1. 在清单文件中为您的活动添加此行:android:configChanges="orientation|locale". 此更改对系统意味着您将自己处理在方向或语言更改期间要做的更改。因此,应用程序将不再自行重新创建活动(因此活动应该以相同的方式工作)。

  2. 另一个技巧是在函数的开头添加这一行onCreateViewsetRetainInstance(true);。如文档所述,此行将在配置更改期间保留片段状态:

控制是否在 Activity 重新创建期间(例如从配置更改)保留片段实例。这只能与不在后台堆栈中的片段一起使用。如果设置,片段生命周期将在重新创建活动时略有不同:

  • onDestroy() 将不会被调用(但 onDetach() 仍然会被调用,因为片段正在与其当前活动分离)。
  • onCreate(Bundle) 不会被调用,因为片段没有被重新创建。
  • onAttach(Activity) 和 onActivityCreated(Bundle) 仍将被调用。

请注意,正如所解释的,Fragment生命周期会发生一些变化。

3)最后一个选项可能是使用onSaveInstanceStateonRestoreInstanceState在此答案中详细说明:https ://stackoverflow.com/a/151940/2206688

于 2013-09-17T13:41:37.757 回答