Android SlideExpandableListView Remove Item - android

I am using the library found at:
https://github.com/tjerkw/Android-SlideExpandableListView
to provide slidedown views on my listitems. The problem I am running into is that each of my list items has a delete button which will remove the item from the underlying adapter. When this happens if the item that was removed was expanded then the item below it will become expanded. After digging through the source for the expandablelistview library I found that the culprit is a BitSet which is being used to keep track of the states of the listviews ( expanded 1, not expanded 0 ). When I remove an item from the list the list of states does not get updated. It needs to shift all values down. The problem is I am not sure how to notify the library that my adapter has had an item removed from it.
My custom list adapter extends array adapter and when I remove an item I call notifyDataSetChanged. Somehow I need to detect that call in the slideExpandablelistview which wraps my adapter so that I can update the BitSet. IF anyone has worked with this library before or care to take a look I would love some help.
I create the expanandablelistview by doing
myAdapter= new SlideExpandableListAdapter(new CustomAdapter(getActivity(), new ArrayList<CustomObject>()), R.id.contact_row, R.id.expandable);
Thanks,
Nathan

"When this happens if the item that was removed was expanded then the item below it will become expanded."
After deleting the item from your ArrayList and then doing adapter.notifyDataSetChanged(), you can do something like:
((ActionSlideExpandableListView) list).collapse();
Here is a full example that I made by modifying the author's sample that comes with the library:
package com.tjerkw.slideexpandable.sample;
import java.util.ArrayList;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.TextView;
import android.widget.Toast;
import com.tjerkw.slideexpandable.library.ActionSlideExpandableListView;
public class ExampleActivity extends Activity
{
PersonDB db;
ArrayList<String> people;
ArrayAdapter<String> adapter;
#Override
public void onCreate(Bundle savedData)
{
super.onCreate(savedData);
this.setContentView(R.layout.single_expandable_list);
final ActionSlideExpandableListView list = (ActionSlideExpandableListView) this.findViewById(R.id.list);
db = PersonDB.getInstance();
people = db.getPeople();
adapter = new PersonArrayAdapter(people);
list.setAdapter(adapter);
// listen for events in the two buttons for every list item.
// the 'position' var will tell which list item is clicked
list.setItemActionListener(new ActionSlideExpandableListView.OnActionClickListener() {
#Override
public void onClick(View listView, View buttonview, int position)
{
switch (buttonview.getId())
{
case R.id.buttonA:
people.remove(position);
((ArrayAdapter<String>) adapter).notifyDataSetChanged();
((ActionSlideExpandableListView) list).collapse();
break;
case R.id.buttonB:
Toast.makeText(ExampleActivity.this, "You pressed buttonB", Toast.LENGTH_SHORT).show();
}
}
// note that we also add 1 or more ids to the setItemActionListener
// this is needed in order for the listview to discover the buttons
}, R.id.buttonA, R.id.buttonB);
}
private class PersonArrayAdapter extends ArrayAdapter<String>
{
public PersonArrayAdapter(ArrayList<String> people)
{
super(ExampleActivity.this, R.layout.expandable_list_item, people);
}
#Override
public View getView(int position, View convertView, ViewGroup parent)
{
// if we weren't given a view, inflate one
if (convertView == null)
{
convertView = getLayoutInflater().inflate(R.layout.expandable_list_item, null);
}
TextView textView = (TextView) convertView.findViewById(R.id.text);
textView.setText(people.get(position));
return convertView;
}
#Override
public int getCount()
{
return people.size();
}
}
}
Here is the dummy database class:
package com.tjerkw.slideexpandable.sample;
import java.util.ArrayList;
public class PersonDB
{
private static PersonDB db = null;
private ArrayList<String> people;
private PersonDB()
{
people = new ArrayList<String>();
// fill "database" with dummy data
for (int i = 0; i < 20; i++)
people.add(i, "Person " + i);
}
public static PersonDB getInstance()
{
if (db == null)
db = new PersonDB();
return db;
}
public ArrayList<String> getPeople()
{
return people;
}
public String getPerson(int i)
{
return people.get(i);
}
public void deletePerson(int i)
{
people.remove(i);
}
}
EDIT: I noticed a bug with this code. When a row is deleted and the row below it moves up to fill that space, the text on the new row's buttonA appears left-justified. The only way I could think of to solve this was to replace this line:
((ArrayAdapter<String>) adapter).notifyDataSetChanged();
with these two lines:
adapter = new PersonArrayAdapter(people);
list.setAdapter(adapter);
If anyone has a better solution I would love to see it.

Related

How to Add Multiple Indexes in a single listview String

theList.add(data.getString(0));
theList.add(data.getString(1));
theList.add(data.getString(2));
theList.add(data.getString(3));
theList.add(data.getString(4));
I want to add all these indexes as a single row
I have Tried follwing code but it didn`t worked
theList.add(data.getString(0),data.getString(1),data.getString(2),data.getString(3),data.getString(4));
This is the Full Code of my Class. What i am trying to do is take data from my sqlite database and show in list view.
By this following code i am getting values in different rows but i want them in a single row
package com.example.project;
import android.database.Cursor;
import android.os.Bundle;
import android.widget.ArrayAdapter;
import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import java.util.ArrayList;
import java.util.List;
/**
* Created by Mitch on 2016-05-13.
*/
public class ViewListContents extends AppCompatActivity {
DBHelper myDB;
User user;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.viewlistcontents_layout);
ListView listView = (ListView) findViewById(R.id.listView);
myDB = new DBHelper(this);
//populate an ArrayList<String> from the database and then view it
ArrayList<String> theList = new ArrayList<>();
Cursor data = myDB.viewbuses();
if(data.getCount() == 0){
Toast.makeText(this, "There are no contents in this list!",Toast.LENGTH_LONG).show();
}else{
while(data.moveToNext()) {
theList.add(data.getString(0));
theList.add(data.getString(1));
theList.add(data.getString(2));
theList.add(data.getString(3));
theList.add(data.getString(4));
theList.add("");
ListAdapter listAdapter = new ArrayAdapter<>(this,android.R.layout.simple_list_item_1,theList);
listView.setAdapter(listAdapter);
}
}
}
}
Thanks in Advance
This is How I Resolved It
First of All Thanks to Mr. Zain He Helped me to get it done.
I Concatenated Strings and it worked.
I wanted to Give space Between Values so this is how I did it.
theList.add(data.getString(0)+" "+data.getString(1)+" "
+data.getString(2)+" " +data.getString(3)+" "+data.getString(4));
A Good Practice is to add .Concat() instead of "+"
Thank You!
I recommend using RecyclerView instead because it provides far more functionality than ListView. It also leads to better performance. You will have to extend RecyclerView.Adapter and RecyclerView.ViewHolder as shown below.
MyAdapter is similar to ArrayAdapter. It connects the RecyclerView to our data.
MyDataViewHolder stores all the views for a single item in the list. In our case that is a single TextView, but it could be more.
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyDataViewHolder> {
private List<String> mList;
public MyAdapter(List<String> list){
this.mList = list;
}
protected static class MyDataViewHolder extends RecyclerView.ViewHolder{
protected TextView viewData;
public MyDataViewHolder(View itemView) {
super(itemView);
viewData = (TextView) itemView.findViewById(R.id.data);
}
}
}
You will also have to implement the following methods inside MyAdapter.
onCreateViewHolder creates a MyDataViewHolder from xml.
onBindViewHolder populates the MyDataViewHolder using our data.
returns the number of elements shown.
#Override
public MyDataViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
View itemView = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.my_data, viewGroup, false);
return new MyDataViewHolder(itemView);
}
#Override
public void onBindViewHolder(MyDataViewHolder viewHolder, int i) {
String string = mList.get(i);
viewHolder.viewData.setText(person.getLastName());
}
#Override
public int getItemCount() {
return mList.size();
}
Now use this inside your onCreate function.
mRecyclerView = (RecyclerView) findViewById(R.id.recyclerview);
mRecyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(new GridLayoutManager(getActivity(), numberOfColumns));
mAdapter = new MyAdapter(mList);
mRecyclerView.setAdapter(mAdapter);

swapCursor() causes CursorIndexOutOfBoundsException, behaves abnormally

I got this problem several days ago, I'm working on a program where a ListView takes data from a database via a custom SimpleCursorAdapter, I used to use listView.setAdapter(adapter)to update the data in the ListView every time the data is changed. But that causes a problem, that everytime you update the data, the listView will automatically scroll to the top, so I decided to use swapCursor() instead, like this:
Cursor cursor = database.getData();
if(listView.getAdapter() == null){
//Toast.makeText(getApplicationContext(),"null",Toast.LENGTH_SHORT).show();
adapter = (new CustomSimpleCursorAdapter(this,R.layout.todolist,cursor,new String[] {LIST_TEXT},new int[]{R.id.text}));
listView.setAdapter(adapter);
}else {
Runnable runnable =new Runnable() {
#Override
public void run() {
Cursor finalCs = database.getData();
todoListAdapter.swapCursor(finalCs);
todoListAdapter.notifyDataSetChanged();
}
};
runOnUiThread(runnable);
}
But then the error appears every time I try to add a data to the database and display it in the listView:
**CursorIndexOutOfBoundsException: Index 12 requested, with a size of 12**
(Note that the data is added to the database, and no problem has been found previously using listView.setAdapter(adapter), I tried to remove todoListAdapter.notifyDataSetChanged();, but that didn't help at all. Also, when I try to remove data from the database and also update the listView with the change, it's always the last item in the listView got removed no matter which one I selected (the data by now is actually correctly removed from the database), and when I try to add data again, I can now add the equal amount of data like the previously deleted data amount(if I removed 4 item, then I can only add 4 item after that or the error will appear). Anyways, swapCursor()seems pretty broken as of my use of it, did I do something wrong? or I need something else for swapCursor() to work? Thanks in advance!
Update: Error traceback context:
android.database.CursorIndexOutOfBoundsException: Index 13 requested, with a size of 13
at android.database.AbstractCursor.checkPosition(AbstractCursor.java:460)
at android.database.AbstractWindowedCursor.checkPosition(AbstractWindowedCursor.java:136)
at android.database.AbstractWindowedCursor.getString(AbstractWindowedCursor.java:50)
at android.support.v4.widget.SimpleCursorAdapter.bindView(SimpleCursorAdapter.java:139)
Update: Custom SimpleCursorAdapter:
import android.content.Context;
import android.database.Cursor;
import android.support.v4.widget.SimpleCursorAdapter;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CheckBox;
import android.widget.TextView;
import java.util.ArrayList;
public class TodoListAdapter extends SimpleCursorAdapter {
private Cursor c;
private Context context;
private ArrayList<Long> itemChecked = new ArrayList<>();
protected int[] mFrom;
protected int[] mTo;
LayoutInflater inflater;
private int mStringConversionColumn = -1;
private CursorToStringConverter mCursorToStringConverter;
private ViewBinder mViewBinder;
MainActivity main;
String[] mOriginalFrom;
public TodoListAdapter(Context context, int layout, Cursor c, String[] from, int[] to) {
super(context, layout, c, from, to,1);
this.c = c;
this.context = context;
mTo = to;
mOriginalFrom = from;
inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
public ViewBinder getViewBinder() {
return mViewBinder;
}
public ArrayList returnSelected(){
return itemChecked;
}
public interface MyInterface{
public void foo();
}
public void setViewBinder(ViewBinder viewBinder) {
mViewBinder = viewBinder;
}
public View getView(final int pos, View inView, ViewGroup parent) {
c.moveToPosition(pos);
if (inView == null) {
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
inView = inflater.inflate(R.layout.todolist, null);
}
final TextView todoText = (TextView) inView.findViewById(R.id.titleText);
final CheckBox cBox = (CheckBox) inView.findViewById(R.id.multiSelectionBox);
System.out.println(c.getCount());
newView(context,c,parent);
bindView(inView,context,c);
final long id = getItemId(pos);
cBox.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
CheckBox cb = (CheckBox) v.findViewById(R.id.multiSelectionBox);
if (cb.isChecked()) {
if(context.toString().contains("MainActivity")){
((MainActivity)context).addSelectedId(id);
}else if(context.toString().contains("HistoryActivity")){
((HistoryActivity)context).addSelectedId(id);
}
System.out.println("checked " + id);
} else if (!cb.isChecked()) {
System.out.println("unchecked " + id);
if(context.toString().contains("MainActivity")){
((MainActivity)context).removeSelectedId(id);
}else if(context.toString().contains("HistoryActivity")){
((HistoryActivity)context).removeSelectedId(id);
}
}
}
});
return inView;
}
}
I finally got it, it's simply because I didn't change the cursor in the adapter to the passed in cursor, override bindView method and add this.c = cursor into the original code, then when calling getView, the cursor will be the new cursor. That's just a stupid mistake I made by myself.
Special thanks to #pskink for helping me to realize that, I don't need to override bindView or newView after all, but you mentioned the c.moveToPosition() made me realize the mistake.

Android: Create ListView with a timline

I have a ListView in my application with events that happen at different times.
In my ListView I want to show them ordered by time with the time on the left side.
| 12:00 | Event1
| 13:00 |
| 14:00 | Event2
| 15:00 | Event2
| 16:00 | Event3
Something like that, can anyone provide suggestions on where to start?
You have to create your own Adapter that will extend the BaseAdapter and on it create a specific layout file that will be used for every row!
Lets say you have a Map<String,String> mMap = new HashMap<String,String> and inside it you have the events and on the other position the time of the event.
Then you create your new Adapter, lets say it MyAdapter.
MyAdapter mAdapter = new MyAdapter(mMap);
you add the adapter to your ListView, by calling the .setAdapter() method.
eg. myListView.setAdapter(MyAdapter);
Inside your custom Adapter you will have to implement some methods. On of them is getView().
There you will have to parse the data by provided by the HashMap<String,String> you passed to your adapter.
In your row_layout.xml you must use relative layout and add the appropriate text fields for showing the info you want!
Hope it helps!!!
Check this link too: http://www.androidhive.info/2012/02/android-custom-listview-with-image-and-text/
Usually your list adapter is using some sort of data structure or container to store its objects. If you need to add a new element, add it to the container first, sort its elements and then call
adapter.notifyDataSetChanged();
to let it know its data has changed and needs to be updated.
Here is just a small example to lead you in the right direction. I hope you'll find it useful.
Define your ListActivity:
package com.myapp.listviewexample;
import android.app.ListActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
public class ListViewExampleActivity extends ListActivity {
static final String[] COUNTRIES = new String[] {
"Afghanistan", "Albania", "Algeria", "American Samoa", "Andorra",
"Angola", "Anguilla", "Antarctica", "Antigua and Barbuda", "Argentina",
"Armenia", "Aruba", "Australia", "Austria", "Azerbaijan"
};
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//setListAdapter(new ArrayAdapter<String>(this, R.layout.list_item, COUNTRIES));
final MyListAdapter adapter = new MyListAdapter(this, COUNTRIES);
setListAdapter(adapter);
ListView lv = getListView();
//lv.setTextFilterEnabled(true);
lv.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
adapter.removeItem(position);
adapter.notifyDataSetChanged();
// When clicked, show a toast with the TextView text
Toast.makeText(getApplicationContext(), ((TextView) view).getText() + " removed",
Toast.LENGTH_SHORT).show();
}
});
}
}
Define your list adapter:
package com.myapp.listviewexample;
import java.util.ArrayList;
import java.util.Arrays;
import android.content.Context;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;
public class MyListAdapter extends BaseAdapter {
private ArrayList<String> items;
private Context mContext;
public MyListAdapter(Context c, String[] countries) {
items = new ArrayList<String>(Arrays.asList(countries));
mContext = c;
Log.i("MyListAdapter", "countries.length == items.size() " + (countries.length == items.size()));
}
public int getCount() {
return items.size();
}
public Object getItem(int position) {
return items.get(position);
}
public long getItemId(int position) {
return position;
}
public void removeItem(int position) {
items.remove(position);
}
// create a new ImageView for each item referenced by the Adapter
public View getView(int position, View convertView, ViewGroup parent) {
View view;
if (convertView == null) { // if it's not recycled, initialize some attributes
LayoutInflater li = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view = li.inflate(R.layout.list_item, null);
} else {
view = convertView;
}
TextView tv = (TextView) view;//.findViewById(R.id.text_view_item);
tv.setText(items.get(position));
return view;
}
}
Consider using the ViewHolder pattern for the adapter, to avoid unnecessary inflating of views. This post might help: How can I make my ArrayAdapter follow the ViewHolder pattern?
Define your list_item.xml
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/text_view_item"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:padding="10dp"
android:textSize="16sp" >
</TextView>
You just need to define another TextView in your list element to suit your needs.
Don't forget to extend your adapter by a method addElement(..) which will add the element to the ArrayList (in this case) and then sort it using Collections.sort(..).
Consider using a pair of two strings, that has to implement Comparable, so you can sort according to the time or even something more sophisticated.

Can you point out the issue with ListView in this code?

Following is some test code , done to recreate a strange bug: After deleting some items from a ListView , it stops refreshing when data is invalidated. More items are deleted but list does not refresh. Even Log cat does not show debug messages for deletion. I will appreciate if any one could find out what's wrong.
Item Layout:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="horizontal">
<TextView android:id="#+id/nameTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
<Button android:id="#+id/deleteButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Delete"
/>
</LinearLayout>
Item class:
import android.content.Context;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
public class Item implements View.OnClickListener {
private String name;
private View itemView;
private MyActivity owner;
//--- getters--
public String getName() {
return name;
}
public View getView() {
return itemView;
}
public Item(String n, Context c , MyActivity o)
{
//---store the name given--
name = n;
//---store reference to the owner activity--
owner = o;
//--- create a View for this item----
LayoutInflater inflater = (LayoutInflater) c.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
itemView = inflater.inflate(R.layout.item,null);
//---set up data to show--
TextView nameTextView = (TextView) itemView.findViewById(R.id.nameTextView);
Button deleteButton = (Button) itemView.findViewById(R.id.deleteButton);
nameTextView.setText(name);
//---set up events to be handled--
deleteButton.setOnClickListener(this);
Log.d("My_Test","Item: Hello world, my name is " + name);
}
//----request owner to delete this item---
#Override
public void onClick(View view) {
Log.d("My_Test","Item:"+name+" requesting owner to delete me");
owner.deleteItem(this);
}
Activity layout:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<ListView android:id="#+id/myListView"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
/>
</LinearLayout>
Activity class:
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import java.util.ArrayList;
public class MyActivity extends Activity {
private ArrayList<Item> myItems;
private ListView myListView;
private ArrayAdapter<Item> myArrayAdapter;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
//-----adapter for item list----
//----since each item has its own view , it just returns the same---
myArrayAdapter = new ArrayAdapter<Item>(this,0){
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
Item item = getItem(position);
Log.d("My_Test","Adapter : View for Item: " + item.getName() +"is requested." );
return item.getView();
}
};
//-----set up my list view with the adapter------
myListView = (ListView) findViewById(R.id.myListView);
myListView.setAdapter(myArrayAdapter);
//------add items-------
//----each item has its own view and a reference to this activity as their owner----
myArrayAdapter.add(new Item("Sunday", this, this));
myArrayAdapter.add(new Item("Monday", this, this));
myArrayAdapter.add(new Item("Tuesday", this, this));
myArrayAdapter.add(new Item("Wednesday", this, this));
myArrayAdapter.add(new Item("Thursday", this, this));
myArrayAdapter.add(new Item("Friday", this, this));
myArrayAdapter.add(new Item("Saturday", this, this));
myArrayAdapter.notifyDataSetChanged();
}
//----- called by items requesting to be deleted from the item list----
public void deleteItem(Item item) {
myArrayAdapter.remove(item);
Log.d("My_Test","Owner : Deleted item :" + item.getName());
myArrayAdapter.notifyDataSetChanged();
}
}
Looks like ListView stops re-drawing it self. Even when List Item is no more in the item array, and myAdapter.notifyDataSetInvalidated(); is called, The List Item stays visible , with further code execution some how blocked.
Use an ArrayAdapter to do this. Try something like this instead...
import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ListView;
import android.widget.TextView;
public class MyActivity extends Activity{
private ListView myListView;
private ArrayAdapter<Item> myArrayAdapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
myArrayAdapter = new ArrayAdapter<Item>(this,R.layout.item){
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View returnedView = convertView;
//inflate your view here
if(returnedView == null){
LayoutInflater inflater = (LayoutInflater)getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
returnedView = inflater.inflate(R.layout.item,null);
}
final Item item = getItem(position);
//set the views
if(returnedView != null){
TextView nameTextView = (TextView) returnedView.findViewById(R.id.nameTextView);
nameTextView.setText(item.getName());
Button deleteButton = (Button) returnedView.findViewById(R.id.deleteButton);
deleteButton.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
remove(item);
notifyDataSetChanged();
}
});
}
return returnedView;
}
};
myArrayAdapter.add(new Item("Sunday"));
myArrayAdapter.add(new Item("Monday"));
myArrayAdapter.add(new Item("Tuesday"));
myArrayAdapter.add(new Item("Wednesday"));
myArrayAdapter.add(new Item("Thursday"));
myArrayAdapter.add(new Item("Friday"));
myArrayAdapter.add(new Item("Saturday"));
myListView = (ListView) findViewById(R.id.myListView);
myListView.setAdapter(myArrayAdapter);
}
}
public class Item{
private String name;
public Item(String n){
this.name = n;
}
public String getName() {
return name;
}
}
Looking inside the working of ListViews and ListAdapters, I came to know there's a lot of recycling of objects, specifically List View Item Objects which adapters produce. Here are the lessons learnt along with solution to Original problem:
When a ListView has to draw/show a list item, it requests a View from ListAdapter, and some times (NOT ALWAYS) also provides an old View object to reuse. This reuse of objects is there so as to increase performance,there's an in built Re-Cycler in ListView to do this, why inflate new layouts for each new list item, when there are already some whose properties can be modified so that they look like the new view item. Until this point , its OK for adapter to change some text on old views and give them back, or create new ones if no recycled views are available, or even discard recyclable views and always create new one.
However, If your List Item's state is more than just some text in a TextView , that is, another object is registered as an onClickListener for your list item, or your list item has a reference to some object somewhere and vice-verca; it is NOT OK for adapter to just change appearance of the reusable Views or simply discard them. Adapter has to update entire state of a reusable item. that includes de-registering old event listeners, re-registering new ones and updating all reference to external objects that may be there.
Changed getView() method for adapter to:
#Override
public View getView(int position, View convertView, ViewGroup parent) {
Item item = getItem(position);
Log.d("My_Test","Adapter : View for Item: " + item.getName() +"is requested." );
if(convertView != null)
{
(convertView.findViewById(R.id.deleteButton))
.setOnClickListener(item);
((TextView)convertView.findViewById(R.id.nameTextView))
.setText(item.getName());
return convertView;
}
else
{
return item.getView();
}
}
NOTE: While always creating new items in this case does not cause any errors, the ListView fails to detect changes and redraw. Making use of recycled items seems to solve this.

Clear listview content?

I have a little problem with ListView. How do I clear a ListView content, knowing that it has a custom adapter?
edit -
the custom adapter class extends BaseAdapter, it looks like this:
import android.app.Activity;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;
public class MyAdapter extends BaseAdapter {
private Activity activity;
private String[] data;
private static LayoutInflater inflater = null;
public MyAdapter(Activity a, String[] str) {
activity = a;
data = str;
inflater = (LayoutInflater) activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
public static class ViewHolder {
public TextView text;
}
#Override
public int getCount() {
return data.length;
}
#Override
public Object getItem(int position) {
return position;
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(int position, View view, ViewGroup parent) {
View v = view;
ViewHolder holder;
if (v == null) {
v = inflater.inflate(R.layout.rowa, null);
holder = new ViewHolder();
holder.text= v.findViewById(R.id.dexter);
v.setTag(holder);
} else {
holder = v.getTag();
}
holder.text.setText(data[position]);
return v;
}
}
Simply write
listView.setAdapter(null);
I guess you passed a List or an Array to the Adapter. If you keep the instance of this added collection, you can do a
collection.clear();
listview.getAdapter().notifyDataSetChanged();
this'll work only if you instantiated the adapter with collection and it's the same instance.
Also, depending on the Adapter you extended, you may not be able to do this. SimpleAdapter is used for static data, thus it can't be updated after creation.
PS. not all Adapters have a clear() method. ArrayAdapter does, but ListAdapter or SimpleAdapter don't
It's simple .First you should clear your collection and after clear list like this code :
yourCollection.clear();
setListAdapter(null);
As of Android versions M and N, following works for me and would be the correct approach. Emptying the ListView or setting the Adapter to null is not the right approach and would lead to null pointer issue, invalid ListView and/or crash of the app.
Simply do:
mList.clear();
mAdapter.notifyDataSetChanged();
i.e. first you clear the list altogether, and then let the adapter know about this change. Android will take care of correctly updating the UI with an empty list. In my case, my list is an ArrayList.
In case you are doing this operation from a different thread, run this code on the UI thread:
runOnUiThread(mRunnable);
Where mRunnable would be:
Runnable mRunnable = new Runnable() {
public void run() {
mList.clear();
mAdapter.notifyDataSetChanged();
}
};;
Simple its works me:)
YourArrayList_Object.clear();
Remove your items from your custom adapter and call notifyDataSetChanged().
There is a solution for the duplicate entry in listview.
You have to declare the onBackPress()-method on your activity and write down the highlight code given below:
#Override
public void onBackPressed() {
// TODO Auto-generated method stub
super.onBackPressed();
**
attendence_webdata.clear(); list.setAdapter(null);
--------------------------------------------------
**
}
Just put the code ListView.Items.Clear(); on your method
Call clear() method from your custom adapter .
You need to call both clear() from ArrayAdapter and notifyDataSetChanged() both.
Below is link
click

Categories

Resources