I have a list that can be updated by the user, but notifyDataSetChanged() is not working on the adapter associated with the listView. I am using it in a fragment. Datbase gets updated, however the adpater doesn't. Following is my implementation:
My Main Fargment:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
myArrayList = new ArrayList<myList>();
myArrayList = Database.getSharedObject(getActivity()).getMyList();
if (myArrayList != null && myArrayList.size() > 0) {
adapter = new myListAdapter(getActivity(), 0, myArrayList);
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.mainfragment, container, false);
myListView = (ListView) v.findViewById(R.id.my_list_view);
myListView.setOnItemClickListener(this);
if (adapter != null) {
myListView.setAdapter(adapter);
}
return v;
}
After some navigations process List gets updated and in my onResume() method I get the updated List from database and call notifyDatasetChanged() method that does not update my view, however corresponding array from DB is updated one.
#Override
public void onResume() {
super.onResume();
myArrayList = Database.getSharedObject(getActivity()).getMyList();
adapter.setItems (myArrayList);
adapter.notifyDataSetChanged();
}
MyListAdapter
public class MyListAdapter extends ArrayAdapter<Message> {
private ArrayList<Message> myList;
/* Context */
private Context context;
public void setItems (ArrayList<Message> myList) {
this.myList = myList;
}
public MyListAdapter (Context context, int textViewResourceId, ArrayList<Message> myList) {
super(context, textViewResourceId, myList);
this.context = context;
this.myList = myList;
}
#Override
public View getView (int position, View v, ViewGroup parent) {
// Keeps reference to avoid future findViewById()
MyViewHolder viewHolder;
if (v == null) {
LayoutInflater li = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = li.inflate(R.layout.list_row, parent, false);
viewHolder = new MyViewHolder();
viewHolder.txtImage = (ImageView) v.findViewById(R.id.message_icon);
viewHolder.txtMessage = (TextView) v.findViewById(R.id.message);
viewHolder.txtDate = (TextView) v.findViewById(R.id.date);
v.setTag(viewHolder);
} else {
viewHolder = (MyViewHolder) v.getTag();
}
Message myMessage = new Message();
myMessage = myList.get(position);
if (myMessage != null) {
viewHolder.txtMessage.setText(myMessage.getText());
viewHolder.txtDate.setText(myMessage.getDate());
}
return v;
}
static class MyViewHolder {
ImageView txtImage;
TextView txtMessage;
TextView txtDate;
}
}
Any thought on what is going wrong? Why is not listview getting updated? Any helps is appreciated.
notifyDataSetChanged() won't work for you. Reasons why
Your adapter loses reference to your list.
Always creating and adding a new list to the Adapter. Do like this:
initialize the ArrayList while declaring globally.
ArrayList<MyItemType> myArrayList=new ArrayList<>(); // as a global variable
Add List to the adapter directly without checking null and empty condition. Set the adapter to the list directly(don't check for any condition)
myListView.setAdapter(adapter);
Add data to the myArrayList Every time(if your data is completely new, then you can call adapter.clear() and myArrayList.clear() before actually adding data to the list) but don't set the adapter
i.e If the new data is populated in the myArrayList, then just adapter.notifyDataSetChanged()
adapter = new myListAdapter(getActivity(), 0, myArrayList);
Remove this line
adapter.setItems (myArrayList);
Just overrige getCount method
#Override
public int getCount() {
return myArrayList.count();
}
In your setItems method try to clear the old ArrayList.
instead of this:
public void setItems(ArrayList<Message> myList) {
this.myList = myList;
}
Try this:
public void setItems(ArrayList<Message> myList) {
this.myList.clear();
this.myList.addAll(myList);
notifyDataSetChanged();
}
The problem is in the constructor of MyListAdapter
Instead of
public MyListAdapter(Context context, int textViewResourceId, ArrayList<Message> myList) {
super(context, textViewResourceId, scheduledMessageList);
this.context = context;
this.myList = myList;
}
try
public MyListAdapter(Context context, int textViewResourceId, ArrayList<Message> myList) {
super(context, textViewResourceId, myList);
this.context = context;
this.myList = myList;
}
also instead of you own Method setItems you should call adapter.clear(); followed by adapter.addAll(myArrayList);
If you can use notifyDataSetChanged() but in Adapter !
create a little method inside
Related
How can I update my listView adapter properly when I add a new file? The listView is feed by a an array. I have read a lot and tried several things but nothing works outs. Am I missing something? notifyDataSetChanged is not working for some reason.
activity.java
on create:
ListView list2;
CustomList listAdapter;
String[] ficheros;
final File carpeta = new File("/storage/emulated/0/Android/data/cc.openframeworks.androidMultiOFActivitiesExample/files/xml");
list2=(ListView)findViewById(R.id.listview);
list2.setVisibility(GONE);
list2.setCacheColorHint(Color.TRANSPARENT);
ficheros = list.toArray(new String[list.size()]);
List<String> list = new ArrayList<String>();
listAdapter = new CustomList(OFActivityA.this, ficheros,fecha);
list2.setAdapter(listAdapter);
listarFicherosPorCarpeta(carpeta);
#Override
protected void onResume() {
super.onResume();
public void listarFicherosPorCarpeta(final File carpeta) {
for (final File ficheroEntrada: carpeta.listFiles()) {
if (ficheroEntrada.isDirectory()) {
listarFicherosPorCarpeta(ficheroEntrada);
} else {
System.out.println(ficheroEntrada.getName());
list.add(ficheroEntrada.getName());
}
}
listAdapter.notifyDataSetChanged();
}
CustomList.java
public class CustomList extends ArrayAdapter<String>{
private final Activity context;
private final String[] ficheros;
private final String[] fecha;
public CustomList(Activity context, String[] ficheros, String[] fecha) {
super(context, R.layout.rowlayout, ficheros);
this.context = context;
this.ficheros = ficheros;
this.fecha = fecha;
}
#Override
public View getView(int position, View view, ViewGroup parent) {
LayoutInflater inflater = context.getLayoutInflater();
View rowView= inflater.inflate(R.layout.rowlayout, null, true);
TextView txtTitle = (TextView) rowView.findViewById(R.id.listtext);
TextView txtFecha = (TextView) rowView.findViewById(R.id.fechatxt);
txtTitle.setTextColor(Color.parseColor("#015D99"));
txtTitle.setHeight(123);
txtFecha.setText(fecha[position]);
txtTitle.setText(ficheros[position]);
return rowView;
}
notifyDataSetChanged() will work if the content in dataset has changed. You are calling it in onResume() which might get called before your loop in function has finished. Try changing your function call and add notifyDataSetChanged() once your for loop completes.
public void listarFicherosPorCarpeta(final File carpeta) {
for (final File ficheroEntrada: carpeta.listFiles()) {
if (ficheroEntrada.isDirectory()) {
listarFicherosPorCarpeta(ficheroEntrada);
} else {
System.out.println(ficheroEntrada.getName());
list.add(ficheroEntrada.getName());
}
}
listAdapter.notifyDataSetChanged(); //call it here after you have updated your data.
}
i have created a custom array adapter for my list view but for some reason the data is not getting displayed in listview item. even the log cat doesnt show anything when i put log statement in getView method of the custom adapter which extends ArrayAdapter.
This is the activity that holds listview
public class booktable extends AppCompatActivity {
ListView mylv;
int[] array = new int[5];
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_booktable);
mylv = findViewById(R.id.mylv);
array = new int[]{1, 0, 0, 0, 1};
ListAdapter la = new customadapter(getApplicationContext(),R.layout.activity_booktable,array);
mylv.setAdapter(la);
}
}
this is my custom adapter
public class customadapter extends ArrayAdapter {
LayoutInflater li;
int[] table = new int[5];
public customadapter(#NonNull Context context,int resource, int [] array) {
super(context,resource);
li = LayoutInflater.from(context);
table = array;
}
#NonNull
#Override
public View getView(int position, #Nullable View convertView, #NonNull ViewGroup parent) {
View v = li.inflate(R.layout.custom_row,parent);
ImageView img = v.findViewById(R.id.img);
TextView tv = v.findViewById(R.id.tv);
if(table[position]==0)
{
tv.setText("FULL");
tv.setTextColor(Color.RED);
}
if(table[position]==1)
{
tv.setText("AVAILABLE");
tv.setTextColor(Color.GREEN);
}
return v;
}
}
try to pass the parameter array or collection to ArrayAdapter constructor, Looks like this:
public customadapter(#NonNull Context context,int resource, int [] array) {
super(context, resource, array);
li = LayoutInflater.from(context);
table = array;
}
I have an array named societies:
List<Society> societies = new ArrayList<>();
That holds the following data:
[{"society_id":1,"name":"TestName1","email":"Test#email1","description":"TestDes1"},
{"society_id":2,"name":"TestName2","email":"Test#email2","description":"TestDes2"},
{"society_id":3,"name":"TestName3","email":"Test#email3","description":"TestDes3"}}
I will be using this to populate a ListView but am having trouble writing the loop that will assign each array of values to its spot in the ListView.
I would like to find a way of pulling the values from the Array and assigning them to each list item by using a loop, can anybody help me with this?
My code (should be sufficient but if you need to see more please ask):
public class SocietySearch extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_society_search);
List<Society> societies = new ArrayList<>();
ServerRequests serverRequest1 = new ServerRequests(SocietySearch.this);
serverRequest1.GetSocietyDataAsyncTask(societies, new GetSocietyCallback() {
#Override
public void done(List<Society> societies) {
ListView lv = (ListView) findViewById(R.id.ListView);
List<ListViewItem> items = new ArrayList<>();
items.add(new ListViewItem() {{
ThumbnailResource = R.drawable.test;
Title = societies.socName;
Subtitle = societies.socDes;
}});
CustomListViewAdapter adapter = new CustomListViewAdapter(SocietySearch.this, items);
lv.setAdapter(adapter);
}
});
}
class ListViewItem {
public int ThumbnailResource;
public String Title;
public String Subtitle;
}
Adapter Class:
public class CustomListViewAdapter extends ArrayAdapter {
LayoutInflater inflater;
List<SocietySearch.ListViewItem> items;
public CustomListViewAdapter(Activity context, List<SocietySearch.ListViewItem> items) {
super(context, R.layout.item_row);
this.items = items;
this.inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
//Auto-generated method stub
ListViewItem item = items.get(position);
View vi = convertView;
if (convertView == null)
vi = inflater.inflate(R.layout.item_row, null);
ImageView test = (ImageView) vi.findViewById(R.id.imgThumbnail);
TextView txtTitle = (TextView) vi.findViewById(R.id.txtTitle);
TextView txtSubTitle = (TextView) vi.findViewById(R.id.txtSubTitle);
test.setImageResource(item.ThumbnailResource);
txtTitle.setText(item.Title);
txtSubTitle.setText(item.Subtitle);
return vi;
}
}
So we came to the conclusion, that we need to have the for loop to iterate through all the Society classes in the SocietySearch class:
#Override
public void done(List<Society> societies) {
ListView lv = (ListView) findViewById(R.id.ListView);
List<ListViewItem> items = new ArrayList<>();
for(Society s : societies) {
items.add(new ListViewItem() {{
ThumbnailResource = R.drawable.test;
Title = s.socName;
Subtitle = s.socDes;
}});
}
CustomListViewAdapter adapter = new CustomListViewAdapter(
SocietySearch.this, items);
lv.setAdapter(adapter);
}`
And we also had to fix the ArrayAdapter implementation:
public class CustomListViewAdapter extends ArrayAdapter {
LayoutInflater inflater;
List<SocietySearch.ListViewItem> items;
public CustomListViewAdapter(Activity context, List<SocietySearch.ListViewItem> items) {
super(context, R.layout.item_row, **items**); // the constructor
//needs the reference of the list, even though we use our variable to
//populate the rows. I guess it has to know how many elements it contains to
//iterate then through getView method, which is called for each row
this.items = items;
this.inflater = (LayoutInflater) context.getSystemService(
Context.LAYOUT_INFLATER_SERVICE);
}
Are you looking for a custom solution? So that you would bind each ListViewItem state to the corresponding column, then you have to create the custom solution like it is here. You would need to have a custom layout for each line and extend the ArrayAdapter where you bind each column for a line.
Is this what you want to know? If not, can you be more specific please.
You are creating an anonymous class and trying to assign values in it's object initializer. Object initializer doesn't have a reference to societies, that's why you are getting the compilation error. Try this instead:
class ListViewItem {
private final int ThumbnailResource;
private final String Title;
private final String Subtitle;
public ListViewItem(int thumbnail, String title, String subtitle) {
ThumbnailResource = thumbnail;
Title = title;
Subtitle = subtitle;
}
}
When adding list items:
items.add(new ListViewItem(R.drawable.test, societies.socName, societies.socDes);
I want a user to input data through an editable text and I want to receive that data through a custom made listview, for that I am trying to use a custom adapter to add a textfield into my listview, through the tostring() method I have converted the data from the editable textview to a string and I am adding that string within my custom adapter to an Arraylist variable values and I’m trying to display that data through get(0) but either the Arraylist is not populating correctly or the data is not displaying properly because whenever I type something within my editable text and press the add button nothing happens, before this I added the string to an Array Adapter and the listview was populating normally, what am I doing wrong?
public class todoFragment extends ListFragment {
private EditText mToDoField;
private Button mAdd;
UsersAdapter mAdapter;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getActivity().setTitle(R.string.todo_title);
}
public class UsersAdapter extends ArrayAdapter<String> {
public Context context;
public ArrayList<String> values;
public UsersAdapter(Context context, ArrayList<String> values) {
super(context, 0, values);
this.context = context;
this.values = values;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = LayoutInflater.from(getContext()).inflate(R.layout.todo_list, parent, false);
TextView todoTextView = (TextView) convertView.findViewById(R.id.todo_TextView);
todoTextView.setText(values.get(0));
return convertView;
}
}
#TargetApi(9) // remember this for isEmpty()
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_todo, container, false);
ArrayList<String> todoList = new ArrayList<String>();
mAdapter = new UsersAdapter(getActivity(), todoList);
ListView listViewToDo = (ListView) v.findViewById (android.R.id.list);
listViewToDo.setAdapter(mAdapter);
mToDoField = (EditText) v.findViewById(R.id.todo_editText);
mAdd = (Button)v.findViewById(R.id.add_button);
mAdd.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
String toDo = mToDoField.getText().toString().trim();
if (toDo.isEmpty()){
return;
}
mAdapter.values.add(toDo);
mToDoField.setText("");
}
});
return v;
}
}
Firstly, you should not be doing
todoTextView.setText(values.get(0));
Because this will always return the first element of the values list. You should do
todoTextView.setText(values.get(position));
Secondly,
mAdapter.values.add(toDo);
is not really right. It will work, but its not the best practise. Try using something like
mAdapter.add(toDo);
or
values.add(toDo);
Now once you've added the data to the list, you need to notify the adapter that the data set has been changed. This is done by
mAdapter.notifyDataSetChanged();
When you manually update the data don't forget to call:
mAdapter.notifyDataSetChanged();
Instead of mAdapter.values.add(toDo); UsemAdapter.add(toDo);
Look at the Add Method Of ArrayAdpter Class, it Itself use notifyDataSetChanged() so need to write any extra line of code:
public void add(T object) {
synchronized (mLock) {
if (mOriginalValues != null) {
mOriginalValues.add(object);
} else {
mObjects.add(object);
}
}
if (mNotifyOnChange) notifyDataSetChanged();
}
I'm trying to inflate a list using baseadapter within an activity. The list just doesn't inflate. From the logs implemented within the class, the getView() function doesn't even execute. Here's the code. -
public class CallLog extends Activity {
ListView logList;
List mList;
Context mCtx;
ArrayList<String> logName;
ArrayList<String> logNumber;
ArrayList<String> logTime;
#Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.reject_call_log);
mCtx = getApplicationContext();
ListView logList = (ListView) findViewById(R.id.log_list);
mList = new List(mCtx, R.layout.log_row);
logList.setAdapter(mList);
SharedPreferences savedLogName = PreferenceManager.getDefaultSharedPreferences(mCtx);
SharedPreferences savedLogNumber = PreferenceManager.getDefaultSharedPreferences(mCtx);
SharedPreferences savedLogTime = PreferenceManager.getDefaultSharedPreferences(mCtx);
try{
logName = new ArrayList(Arrays.asList(TextUtils.split(savedLogName.getString("logName", null), ",")));
logNumber = new ArrayList(Arrays.asList(TextUtils.split(savedLogNumber.getString("logNumber", null), ",")));
logTime = new ArrayList(Arrays.asList(TextUtils.split(savedLogTime.getString("logTime", null), ",")));
Collections.reverse(logName);
Collections.reverse(logNumber);
Collections.reverse(logTime);
}catch(NullPointerException e){
e.printStackTrace();
//TextView noLog = (TextView)findViewById(R.id.no_log);
}
}
public class List extends BaseAdapter {
LayoutInflater mInflater;
TextView nameText;
TextView numberText;
TextView timeText;
int timePos = 1;
public List(Context context, int resource) {
}
#Override
public int getCount() {
return 0;
}
#Override
public Object getItem(int i) {
return null;
}
#Override
public long getItemId(int i) {
return 0;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View v = convertView;
if (convertView == null) {
v = mInflater.inflate(R.layout.row, null);
}
nameText = (TextView) v.findViewById(R.id.log_name);
numberText = (TextView) v.findViewById(R.id.log_number);
timeText = (TextView) v.findViewById(R.id.log_time);
nameText.setText(logName.get(position));
numberText.setText(logNumber.get(position));
timeText.setText(logTime.get(timePos) + logTime.get(timePos+1));
Log.d("RejectCall", "ListView");
timePos+=2;
return v;
}
}
}
Where is it all going wrong? Also, is there a better way to do what I'm trying to do?
Please replace the following code :
#Override
public int getCount() {
return 0;
}
with
#Override
public int getCount() {
return logName.size();
}
As list view only show the numbers of rows that is returned by this method and right now you are returning 0;
And after fetching the data in arraylist please use adapter.notifyDataSetChanged() to notify the list view.
You have to call notifyDataSetChanged() as you are filling data in array list after setting the adapter. so to notify the list view that data has been changed you have to call notify method(as above)
Your getItem() and getCount() haven't been implemented. If you want any kind of adapter to work for the list, these need to be implemented. Your list is also not holding any actual data, so getItem() has nothing to set.
Don't forget to call notifiyDataSetChanged() in your adapter after you set appropriate implementations for the above two functions.