问题
I have an app that uses a ViewPager and Fragments to create tabs.
Within my app, I have a chat function. Whenever a chat is received or sent, it is stored in a table of the database. The received chats are coming in on a different thread, and the user's chats are being entered into an EditText window in the Chat fragmenet.
I have a class called "LogChat.java" that saves the chats to the database.
I have a ListView backed by a SimpleCursorAdapter that is displaying the chats. This ListView is in the Chat Fragment of my application.
Everything is working perfectly, except the ListView is not automatically refreshing to show the latest chats. In the Chat fragment, I have this method to display the chats:
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();
}
And I have this to read the chat from the input, and save it to the database:
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();
});
}
In the listener thread, I pass in a reference to the Main Activity, and use that to send the chat to LogChat.java for storage within the database:
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);
}
}
Like I said, this all works, except for refreshing the ListView to show the new received chats. I am successfully storing all chats (the user's and all received chats), and they will correctly display in my ListView if I am tricky with the way I do it (i.e., enter a local chat).
Right now, in order to see the received chats, I have to enter a chat locally, which calls the displayChats() method, which updates the ListView, which shows my entered chat and all other recently received chats in the ListView.
I know that I am supposed to use notifyDataSetChanged()
, but I cannot, for the life of me, figure out how to use it. I have been trying to wrap my head around it for a while now, but I just cannot "get it".
I know I am supposed to call notifyDataSetChanged()
on the simpleCursorAdapter variable like this:
simpleCursorAdapter.notifyDataSetChanged();
But I am not sure how to access that from my LogChats class or my listener thread. Or, for that matter, from the getView()
method of the same class the SimpleCursorAdapter is being used in. I thought it would be a good idea to do it from the LogChats class so there is a central point for logging the chats in the database and refreshing the view all in one place.
I know that notifyDataSetChanged()
is used all the time, so I figure I am just blocked on being able to figure out how to properly use it, but I am blocked nonetheless.
回答1:
It looks like the main issue here is getting the data added event down to the Fragment where the adapter lives.
You can just call a public method in MainActivity from your listener, that uses a reference to the Fragment to call a public method that will call notifyDataSetChanged()
on the adapter.
First, use an instantiateItem()
override in your FragmentPagerAdapter to get a valid reference to your 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;
}
}
Then, define the method in MainActivity that will relay the data changed event:
public void dataChanged() {
//only update if the user is currently on the ChatFragment
if (mViewPager.getCurrentItem() == 0 && mPagerAdapter.chatFragment != null) {
mPagerAdapter.chatFragment.listViewDataChanged();
}
}
Then define the listViewDataChanged()
method in your ChatFragment, and make sure that the adapter is a member variable of the Fragment class:
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();
}
And to link it all together, call dataChanged()
from the Listener when the data changes. Note that if this Runnable is running on it's own Thread, you will need to use 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();
}
});
}
}
来源:https://stackoverflow.com/questions/36919239/i-cannot-figure-out-how-to-correctly-use-notifydatasetchanged-within-my-app