android


Why Is My Custom Android ArrayAdapter Not Refreshing Its ListView When New Data Is Added To The Array?


As part of my Android app, I am integrating a very simple custom group chat feature; this is just a proof-of-concept feature. I am aware of the fact that this is transient, and that my chats disappear whenever I restart my app. My app uses Fragments and a ViewPager to create tabs within my app.
What I have backing this feature is a LinkedList which holds Message objects (send time, sender name, message). Whenever a chat is sent or received, it is added to the LinkedList. At the start of my MainActivity.java, I declare the list
public static LinkedList<Message> chatList;
In the onCreate method, I initialize the list
chatList = new LinkedList<Message>();
I have a listener thread that runs in the background that listens for incoming messages. I passed the chatList into this thread in its constructor
MyListener myListener = new MyListener(MainActivity.this, chatList);
Thread listenerThread = new Thread(myListener);
listenerThread.start();
Whenever the listener thread receives a message, it sticks it into the LinkedList
chatList.add(new_message_object);
To display the chats, I use a ListView that is backed by a custom ArrayAdapter, in which I have overridden the getView() method. The ArrayAdapter gets the array from the toArray() method of my LinkedList and displays the chats on the screen.
This process almost works. Whenever chats are received, the LinkedList is successfully populated. The problem is getting the ListView to immediately update and display the chats. If I switch to a new fragment/tab within my app, then switch back to my chat tab, then the list is populated; but, I have to do this whenever I want to see any new chats.
This is also true for any chats I enter locally (i.e., within my chat feature). It is still added to the LinkedList, but the ListView does not refresh.
I don't want to use a SwipeRefreshLayout, I would rather the list update itself. I created a method within the custom ArrayAdapter
public void refreshList(){
this.notifyDataSetChanged();
}
I call this whenever a new message object is added to the LinkedList, but it is not refreshing the list.
So, what am I doing incorrectly? Like I said, I would prefer the ListView update itself like a proper chat program does.
Thanks
EDIT:
As requested, here is my custom ArrayAdapter
public class CustomArrayAdapter extends ArrayAdapter {
Context context;
int resource;
Object[] objects;
public CustomArrayAdapter(Context context, int resource, Object[] objects) {
super(context, resource, objects);
this.context = context;
this.resource = resource;
this.objects = objects;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View row = convertView;
MessageHolder messageHolder = null;
if(row == null){
LayoutInflater inflater = ((Activity)context).getLayoutInflater();
row = inflater.inflate(resource, parent, false);
messageHolder = new MessageHolder();
messageHolder.chat_information = (TextView) row.findViewById(R.id.chat_information);
messageHolder.chat_message = (TextView) row.findViewById(R.id.chat_message);
row.setTag(messageHolder);
} else {
messageHolder = (MessageHolder) row.getTag();
}
Message item = (Message) objects[position];
messageHolder.chat_information.setText(item.getSenderName() + Constants.NEWLINE + item.getSendTime());
messageHolder.chat_message.setText(item.getMessageText());
return row;
}
public void refreshList(){
this.notifyDataSetChanged();
}
private class MessageHolder {
TextView chat_information;
TextView chat_message;
}
}
EDIT 2:
I am adding my Chat.java fragment.
public class Chat extends Fragment {
private View rootView;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
rootView = inflater.inflate(R.layout.chat, container, false);
return rootView;
}
#Override
public void onViewCreated(View rootView, Bundle savedInstanceState) {
super.onViewCreated(rootView, savedInstanceState);
displayChats();
}
#Override
public View getView() {
Button sendChatButton = (Button) rootView.findViewById(R.id.text_send);
sendChatButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Date rightNow = new Date();
SimpleDateFormat timeSDF = new SimpleDateFormat(Constants.SIMPLE_TIME);
SimpleDateFormat dateSDF = new SimpleDateFormat(Constants.SIMPLE_DATE);
SharedPreferences myAppPreferences = getContext().getSharedPreferences(Constants.PREFS_NAME, getContext().MODE_PRIVATE);
EditText chatEntryWindow = (EditText)rootView.findViewById(R.id.chat_text_compose);
String message = chatEntryWindow.getText().toString();
String username = myAppPreferences.getString("username", Constants.TABLET_ID);
Message myMessage = new Message(username, message, 0, dateSDF.format(rightNow), timeSDF.format(rightNow));
CustomArrayAdapter caa = new CustomArrayAdapter(getActivity(), R.layout.outgoing_line_of_chat, MainActivity.chatList);
caa.add(myMessage);
caa.notifyDataSetChanged();
new SendChat(getActivity(), message, username).execute();
}
});
return super.getView();
}
public void displayChats(){
ListView list = (ListView) rootView.findViewById(R.id.chat_text_display);
ArrayAdapter adapter = new CustomArrayAdapter(getActivity(), R.layout.outgoing_line_of_chat, MainActivity.chatList);
list.setAdapter(adapter);
}
}
use the following after inserting new data in array adapter:
yourAdapterName.notifyDataSetChanged();
Your CustomArrayAdapter does not use your LinkedList. It uses an Object[]. I assume, from your question and comments, that when you create your CustomArrayAdapter, at that point, you call toArray() on the LinkedList to get your Object[].
At this point, though, the Object[] is completely decoupled from the LinkedList. Suppose, at the outset, the LinkedList has 5 Message objects. You call toArray(), and you get an Object[5] containing those 5 Message objects. You later call add() on the LinkedList, to add a 6th Message. The Object[5] is still an Object[5] and knows nothing about that 6th Message. The only way the AdapterView will update is if you replace the CustomArrayAdapter entirely.
So, get rid of the Object[]. ArrayAdapter takes a List in half of its constructors. So, replace:
public class CustomArrayAdapter extends ArrayAdapter {
Context context;
int resource;
Object[] objects;
public CustomArrayAdapter(Context context, int resource, Object[] objects) {
super(context, resource, objects);
this.context = context;
this.resource = resource;
this.objects = objects;
}
with:
public class CustomArrayAdapter extends ArrayAdapter<Message> {
Context context;
int resource;
public CustomArrayAdapter(Context context, int resource, List<Message> messages) {
super(context, resource, messages);
this.context = context;
this.resource = resource;
}
Then, in getView(), replace Message item = (Message) objects[position]; with Message item=getItem(position);.
Finally, when a new Message arrives, call add() on the CustomArrayAdapter, which will both update your List<Message> and update the attached AdapterView.
Change the code like this . This will not make too many changes ,
public class CustomArrayAdapter extends ArrayAdapter {
Context context;
int resource;
List objects ;
Activity activity ;
public CustomArrayAdapter(Context context, int resource, List objects) {
super(context, resource, objects);
this.context = context;
this.resource = resource;
//clone the arraylist.
this.objects = new ArrayList(objects);
activity = (Activity) context;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View row = convertView;
MessageHolder messageHolder = null;
if (row == null) {
LayoutInflater inflater = LayoutInflater.from(context);
row = inflater.inflate(resource, parent, false);
messageHolder = new MessageHolder();
messageHolder.chat_information = (TextView) row.findViewById(R.id.chat_information);
messageHolder.chat_message = (TextView) row.findViewById(R.id.chat_message);
row.setTag(messageHolder);
} else {
messageHolder = (MessageHolder) row.getTag();
}
Message item = (Message) objects.get(position);
messageHolder.chat_information.setText(item.getSenderName() + Constants.NEWLINE + item.getSendTime());
messageHolder.chat_message.setText(item.getMessageText());
return row;
}
public void setObjects(List newObjects)
{
if (objects != null)
{
objects.clear();
objects.addAll(newObjects);
}
}
public void refreshList() {
activity.runOnUiThread(new Runnable() {
#Override
public void run() {
notifyDataSetChanged();
}
});
}
private class MessageHolder {
TextView chat_information;
TextView chat_message;
}
}
And also one each chat message call setObjects() method with the linked list and call refreshList() method

Related Links

How to make TextView the same size regardless of the texts inside
Service, Observer, and Loopers
KeyEvent.KEYCODE_MEDIA_NEXT not received unless audio is playing
Achartengine legend location
Android ListView shows only last item
Random resize problems Android tablets
About UTF-8(Uyghur) language support on Android 3.2 OS
Android and muting music when i want to play a custom voice message
Android two sliding drawer in a single view
Add Another Layout to display in OnActivityResult()
How to set custom list view item's height…?
Android Web Request Title grab
Why not working the google map api with the different key in android?
Google Reader-esque optimizing of WebViews on Android
android: SQLite query with between condition problem
How to set typeface for application name

Categories

HOME
kentico
fftw
grafana
xbee
permissions
ado.net
fosrestbundle
32bit-64bit
mel
opengl-es-3.0
filechannel
zerobrane
enterprise-architect
scrolltop
capistrano3
esoteric-languages
guzzle
href
string-concatenation
expressionengine3
rselenium
contacts
hibernate-search
sharding
modalviewcontroller
sql-delete
wurfl
ideascript
filesystemwatcher
knime
berkeley-db-je
httrack
openal
facebook-pixel
vugen
identification
posixct
aquamacs
appdomain
yii2-user
edit
d3-force-directed
baidu
branch-prediction
reachability
cassia
project-organization
ikiwiki
fuzzywuzzy
false-sharing
toast
oracle-spatial
forwarding
doctype
amiga
dronekit-android
branch-and-bound
sql-server-data-tools
nutiteq
dot.js
code-documentation
wxformbuilder
decoupling
unit-of-work
kogrid
observium
swfobject
saleslogix
wcf-configuration
correlated-subquery
appjs
httponly
window-decoration
kqueue
jquery-address
relative
instantiationexception
updatesourcetrigger
folding
scrollbars
escrow
netbeans6.1
idatareader

Resources

Encrypt Message