【问题标题】:I cannot figure out how to correctly use notifyDataSetChanged within my app我无法弄清楚如何在我的应用程序中正确使用 notifyDataSetChanged
【发布时间】:2016-04-28 15:32:34
【问题描述】:

我有一个使用 ViewPager 和 Fragments 来创建标签的应用程序。

在我的应用程序中,我有一个聊天功能。每当接收或发送聊天时,它都会存储在数据库的表中。接收到的聊天来自不同的线程,并且用户的聊天被输入到聊天片段中的 EditText 窗口中。

我有一个名为“LogChat.java”的类,可以将聊天记录保存到数据库中。

我有一个由 SimpleCursorAdapter 支持的 ListView,它显示聊天。此 ListView 在我的应用程序的聊天片段中。

一切正常,除了 ListView 不会自动刷新以显示最新聊天。在聊天片段中,我有这个方法来显示聊天:

displayChats()

public void displayChats(){
    DatabaseHelper databaseHelper = new DatabaseHelper(getActivity());
    Cursor chatsCursor = databaseHelper.getChatsCursor();
    String[] fromColumns = {chatInfo, chatContent};
    int[] toViews = {R.id.chat_info, R.id.chat_content};
    SimpleCursorAdapter simpleCursorAdapter = new SimpleCursorAdapter(getContext(), R.layout.line_of_chat, chatsCursor, fromColumns, toViews, 0);
    ListView listView = (ListView) rootView.findViewById(R.id.chat_text_display);

    listView.setAdapter(simpleCursorAdapter);
    databaseHelper.close();
}

我有这个从输入中读取聊天,并将其保存到数据库中:

getView()

@Override
public View getView(){
    Button sendChatButton = (Button) rootView.findViewById(R.id.send_chat_button);
    EditText chatEntryWindow = (EditText) rootView.findViewById(R.id.chat_entry_window);

    sendChatButton.setOnClickListener(new View.OnClickListener(){
        String message = chatEntryWindow.getText().toString();

        LogChat logChat = new LogChat();
        logChat.addMessage(message);

        displayChats();
    });
}

在侦听器线程中,我传入对 Main Activity 的引用,并使用它将聊天发送到 LogChat.java 以存储在数据库中:

Listener.java

public class Listener implements Runnable(){
    private MainActivity mainActivity;

    public Listener(MainActivity mainActivity){
        this.mainActivity = mainActivity;
    }

    @Override
    public void run(){
        LogChat logChat = new LogChat();
        logChat.addMessage(message);
    }
}

就像我说的,这一切都有效,除了刷新 ListView 以显示新收到的聊天记录。我成功地存储了所有聊天(用户和所有收到的聊天),如果我的操作方式很棘手(即输入本地聊天),它们将正确显示在我的 ListView 中。

现在,为了查看收到的聊天,我必须在本地输入一个聊天,它调用 displayChats() 方法,该方法会更新 ListView,它会在 ListView 中显示我输入的聊天和所有其他最近收到的聊天。

我知道我应该使用notifyDataSetChanged(),但我终其一生都无法弄清楚如何使用它。一段时间以来,我一直在努力思考它,但我就是无法“明白”。

我知道我应该像这样在 simpleCursorAdapter 变量上调用 notifyDataSetChanged()

simpleCursorAdapter.notifyDataSetChanged();

但我不确定如何从我的 LogChats 类或我的侦听器线程中访问它。或者,就此而言,来自使用 SimpleCursorAdapter 的同一类的 getView() 方法。我认为从 LogChats 类中执行此操作是一个好主意,因此有一个中心点可以将聊天记录在数据库并在一处刷新视图。

我知道notifyDataSetChanged() 一直在使用,所以我想我只是无法弄清楚如何正确使用它,但我仍然被阻止了。

【问题讨论】:

    标签: android listview android-fragments simplecursoradapter


    【解决方案1】:

    看起来这里的主要问题是将数据添加事件向下传递到适配器所在的片段。

    您可以从侦听器调用 MainActivity 中的公共方法,该方法使用对 Fragment 的引用来调用将在适配器上调用 notifyDataSetChanged() 的公共方法。

    首先,在 FragmentPagerAdapter 中使用 instantiateItem() 覆盖以获得对 ChatFragment 的有效引用:

    public class ViewPagerAdapter extends FragmentPagerAdapter {
        public ChatFragment chatFragment;
    
        //...
    
        @Override
        public Fragment getItem(int position) {
            switch (position) {
                case 0:
                    return new ChatFragment();
                case 1:
                    ...
                default:
                    return null;
            }
        }
    
        @Override
        public Object instantiateItem(ViewGroup container, int position) {
          Fragment createdFragment = (Fragment) super.instantiateItem(container, position);
          if (position == 0) {
            chatFragment = (ChatFragment) createdFragment;
          }
          return createdFragment;
        }
    }
    

    然后,在 MainActivity 中定义将中继数据更改事件的方法:

    public void dataChanged() {
        //only update if the user is currently on the ChatFragment
        if (mViewPager.getCurrentItem() == 0 && mPagerAdapter.chatFragment != null) {
            mPagerAdapter.chatFragment.listViewDataChanged();
        }
    }
    

    然后在你的ChatFragment中定义listViewDataChanged()方法,并确保适配器是Fragment类的成员变量:

    public void listViewDataChanged() {
        simpleCursorAdapter.notifyDataSetChanged();
    }
    
    //Class member variable:    
    SimpleCursorAdapter simpleCursorAdapter;
    
    public void displayChats(){
        DatabaseHelper databaseHelper = new DatabaseHelper(getActivity());
        Cursor chatsCursor = databaseHelper.getChatsCursor();
        String[] fromColumns = {chatInfo, chatContent};
        int[] toViews = {R.id.chat_info, R.id.chat_content};
        //modified:
        simpleCursorAdapter = new SimpleCursorAdapter(getContext(), R.layout.line_of_chat, chatsCursor, fromColumns, toViews, 0);
        ListView listView = (ListView) rootView.findViewById(R.id.chat_text_display);
    
        listView.setAdapter(simpleCursorAdapter);
        databaseHelper.close();
    }
    

    要将它们链接在一起,请在数据更改时从侦听器中调用dataChanged()。请注意,如果此 Runnable 在它自己的线程上运行,则需要使用 runOnUiThread()

    public class Listener implements Runnable(){
        private MainActivity mainActivity;
    
        public Listener(MainActivity mainActivity){
            this.mainActivity = mainActivity;
        }
    
        @Override
        public void run(){
            LogChat logChat = new LogChat();
            logChat.addMessage(message);
            //added:
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                     mainActivity.dataChanged();
                }
            });
    
        }
    }
    

    【讨论】:

    • 我尝试了您在此处提供的内容,但每当我的侦听线程接收到聊天时,我都会收到错误 CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views并且我在聊天视图/选项卡上。当我在任何其他视图/选项卡上时,它不会引发此错误。
    • @P.Alston 看看我刚刚做的更新,用runOnUiThread()调用mainActivity.dataChanged()
    • runOnUiThread 在我的侦听器线程中不可用,因此我将其添加到 Main Activity 中的 dataChanged() 方法中。该应用程序不再崩溃,但列表仍然没有刷新。它表现出与以前相同的行为。
    • 我想通了。我没有调用listViewDataChanged(),而是调用了我原来的displayChats() 方法,现在一切正常。我还没有完全理解整个过程,但它现在可以工作了。执行这个简单的功能应该不难。有时 Android 的方法非常令人沮丧。
    猜你喜欢
    • 2019-10-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多