Refresh ListView when item in adapter is removed - java

I have created a ListView of items that each one of them looks as follows:
In simplified code, It looks like this:
public class MyBAdapter extends ArrayAdapter {
private static class ViewHolder {
public ImageButton ib_Delete;
public ToggleButton tb_Status;
}
public MyBAdapter(Context context, ArrayList<MyB> aB) {
super(context, 0, aB);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
final MyB b = getItem(position);
ViewHolder viewHolder;
if (convertView == null) {
viewHolder = new ViewHolder();
LayoutInflater inflater = (LayoutInflater)getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate( R.layout.item_b_myb, parent, false);
viewHolder.ib_DeleteB = convertView.findViewById( R.id.ib_DeleteB );
viewHolder.tb_Status = convertView.findViewById( R.id.tb_Status );
convertView.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) convertView.getTag();
}
return convertView;
}
}
Now, I had like that once a user clicks on the ToggleButton of on the x button, that it will remove this item from the list and that the view will be updated on this screen.
How can I do it?
I saw that for this case notifyDataSetChanged() won't work.
Basically what I'm trying to do is to refresh the list without calling again the activity.
Thank you

You can try like this:
public static class MyBAdapter extends ArrayAdapter {
private ArrayList<String> aB;
private class ViewHolder {
public ImageButton ib_Delete;
public ToggleButton tb_Status;
public TextView text;
}
public MyBAdapter(Context context, ArrayList<String> aB) {
super(context,0, aB);
this.aB = aB;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder viewHolder;
if (convertView == null) {
viewHolder = new ViewHolder();
LayoutInflater inflater = (LayoutInflater)getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate( R.layout.item_b_myb, parent, false);
viewHolder.ib_Delete = convertView.findViewById( R.id.ib_DeleteB );
viewHolder.tb_Status = convertView.findViewById( R.id.tb_Status );
viewHolder.text = convertView.findViewById( R.id.text );
convertView.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) convertView.getTag();
viewHolder.tb_Status.setChecked(false);
}
viewHolder.text.setText(aB.get(position));
viewHolder.ib_Delete.setTag(position);
viewHolder.ib_Delete.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if(viewHolder.tb_Status.isChecked()){
delete((Integer)view.getTag());
}
}
});
return convertView;
}
private void delete(int position) {
aB.remove(position);
notifyDataSetChanged();
}
#Override
public int getCount() {
return aB.size();
}
}

Related

Listview lag when scrolling, and crash when add item

I have a custom listview with a button to add more elements
but when I add and element the app crash, but when I restart I find that the element is added, (rarely it doesn't crash)
And i
I use custom adapter
class CustomAdapter extends BaseAdapter {
ArrayList<ListItem> listItems = new ArrayList<ListItem>();
CustomAdapter(ArrayList<ListItem> list){
this.listItems = list;
}
#Override
public int getCount() {
return listItems.size();
}
#Override
public Object getItem(int position) {
return listItems.get(position).name;
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(int i, View convertView, ViewGroup parent) {
LayoutInflater inflater = getLayoutInflater();
View view = inflater.inflate(R.layout.list_item,null);
TextView name = (TextView) view.findViewById(R.id.name);
TextView lastm = (TextView) view.findViewById(R.id.last);
TextView time = (TextView) view.findViewById(R.id.time);
CircleImageView pic= (CircleImageView) view.findViewById(R.id.pic);
name.setText(listItems.get(i).name);
lastm.setText(listItems.get(i).lastm);
time.setText(listItems.get(i).time);
Bitmap bmp = BitmapFactory.decodeByteArray(listItems.get(i).pic,0,listItems.get(i).pic.length);
pic.setImageBitmap(bmp);
return view;
}
}
and when I add an element the app crashs
add.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
EditText editText=(EditText) mView.findViewById(R.id.name);
String name=editText.getText().toString();
boolean result=myDataBase.insertData(imageViewToByte(img),name,"no messages yet","");
if (result) {
Toast.makeText(Main2Activity.this, "Saved in DATABASE", Toast.LENGTH_SHORT).show();
viewLastData();
dialog.dismiss();
}
If your ListView lags it's because you used wrap_content for the listView's layout_height. It forces your ListView to count all the items inside and it has a huge performance impact.
So replace wrap_content by match_parent to avoid those lags.
EDIT: Use a ViewHolder pattern too in your Adapter, see this link.
Here is an example:
// ViewHolder Pattern
private static class ViewHolder {
TextView name, status;
}
#Override #NonNull
public View getView(int position, View convertView, #NonNull ViewGroup parent) {
ViewHolder holder;
if (convertView == null) {
LayoutInflater vi = LayoutInflater.from(getContext());
convertView = vi.inflate(R.layout.list_item, parent, false);
holder = new ViewHolder();
holder.name = (TextView) convertView.findViewById(R.id.text_name);
holder.status = (TextView) convertView.findViewById(R.id.another_text);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
// Then do the other stuff with your item
// to populate your listView
// ...
return convertView
}

EditText Values getting cleared on scrolling listview android

public class Custom_Student_marks_list_faculty_adapter extends ArrayAdapter<MarksStudentListFacultyObject> {
private Activity context;
private List<MarksStudentListFacultyObject> studentlist;
public Custom_Student_marks_list_faculty_adapter(Activity context,List<MarksStudentListFacultyObject> studentlist) {
super(context,R.layout.custom_listview_marks_faculty,studentlist);
this.context=context;
this.studentlist=studentlist;
}
#Override
public View getView(final int position, #Nullable View convertView, #NonNull ViewGroup parent) {
final ViewHolder holder;
if(convertView==null) {
LayoutInflater inflater = context.getLayoutInflater();
convertView = inflater.inflate(R.layout.custom_listview_marks_faculty, null);
holder = new ViewHolder();
holder.name = (TextView) convertView.findViewById(R.id.custom_listview_marks_faculty_stu_name_id);
holder.marks = (EditText) convertView.findViewById(R.id.custom_listview_marks_faculty_stu_marks_id);
String mark = holder.marks.getText().toString();
MarksStudentListFacultyObject student_list = studentlist.get(position);
holder.name.setText(student_list.getName());
holder.marks.setText(mark);
holder.marks.setTag(position);
convertView.setTag(holder);
} else {
holder =(ViewHolder)convertView.getTag();
}
holder.name.setText(studentlist.get(position).getName());
holder.marks.setText(studentlist.get(position).getMakrs());
return convertView;
}
}
class ViewHolder {
protected TextView name;
protected EditText marks;
}
I have seen many solution for it but it is not working out for me. Every time on scrolling, ListView values are getting cleared.
Hope this will work...
public Custom_Student_marks_list_faculty_adapter(Activity context,List<MarksStudentListFacultyObject> studentlist) {
super(context,R.layout.custom_listview_marks_faculty,studentlist);
this.context=context;
this.studentlist=studentlist;
}
#NonNull
#Override
public View getView(final int position, #Nullable View convertView, #NonNull ViewGroup parent) {
final ViewHolder holder;
if(convertView==null) {
LayoutInflater inflater = context.getLayoutInflater();
convertView = inflater.inflate(R.layout.custom_listview_marks_faculty, null);
holder = new ViewHolder();
holder.name = (TextView) convertView.findViewById(R.id.custom_listview_marks_faculty_stu_name_id);
holder.marks = (EditText) convertView.findViewById(R.id.custom_listview_marks_faculty_stu_marks_id);
convertView.setTag(holder);
} else {
holder =(ViewHolder)convertView.getTag();
}
MarksStudentListFacultyObject student_list = studentlist.get(position);
holder.name.setText(student_list.getName());
//holder.marks.setText(student_list.getMarks());
return convertView;
}
You will need to update the edittext values again in your student list because of the recycling nature of list view and also set the value on each time getview method is called.
Something like:
public View getView(final int position, #Nullable View convertView, #NonNull ViewGroup parent) {
final ViewHolder holder;
if(convertView==null) {
LayoutInflater inflater = context.getLayoutInflater();
convertView = inflater.inflate(R.layout.custom_listview_marks_faculty, null);
holder = new ViewHolder();
holder.name = (TextView) convertView.findViewById(R.id.custom_listview_marks_faculty_stu_name_id);
holder.marks = (EditText) convertView.findViewById(R.id.custom_listview_marks_faculty_stu_marks_id);
convertView.setTag(holder);
} else {
holder =(ViewHolder)convertView.getTag();
}
MarksStudentListFacultyObject student_list = studentlist.get(position);
holder.name.setText(student_list.getName());
holder.marks.setText(student_list.getMarks());
holder.marks.addTextChangedListener(new TextWatcher() {
#Override
public void onTextChanged(CharSequence s, int start,
int before, int count) {
//set data to array when changed
student_list.setMarks(s.toString());
}
#Override
public void beforeTextChanged(CharSequence s, int start,
int count, int after) {
}
#Override
public void afterTextChanged(Editable s) {
}
});
return convertView;
}
Try:
#Override
public View getView(final int position, #Nullable View convertView, #NonNull ViewGroup parent) {
final ViewHolder holder;
if(convertView==null) {
LayoutInflater inflater = context.getLayoutInflater();
convertView = inflater.inflate(R.layout.custom_listview_marks_faculty, null);
holder = new ViewHolder();
holder.name = (TextView) convertView.findViewById(R.id.custom_listview_marks_faculty_stu_name_id);
holder.marks = (EditText) convertView.findViewById(R.id.custom_listview_marks_faculty_stu_marks_id);
convertView.setTag(holder);
} else {
holder =(ViewHolder)convertView.getTag();
}
String mark = holder.marks.getText().toString();
MarksStudentListFacultyObject student_list = studentlist.get(position);
holder.name.setText(student_list.getName());
holder.marks.setText(mark);
return convertView;
}
}
Try this:
#Override
public View getView(final int position, #Nullable View convertView, #NonNull ViewGroup parent) {
if(convertView==null) {
LayoutInflater inflater = context.getLayoutInflater();
convertView = inflater.inflate(R.layout.custom_listview_marks_faculty, null);
}
TextView name = (TextView) convertView.findViewById(R.id.custom_listview_marks_faculty_stu_name_id);
EditText marks = (EditText) convertView.findViewById(R.id.custom_listview_marks_faculty_stu_marks_id);
name.setText(studentlist.get(position).getName());
marks.setText(studentlist.get(position).getMakrs());
return convertView;
}
Edit :
Override getCount() method in ArrayAdaptor:
#Override public int getCount(){ return studentlist.size(); }

All checkbox in listview is not getting visible from invisible state when button is clicked from Mainactivity

I am new to android. I am struggling with the checkbox in listview. By default I made my checkbox in listview to be in INVISIBLE mode when the button is clicked from MainActivity. I want to all checkbox in listview to be in VISIBLE mode but when I am clicking the button check box is VISIBLE in only one list row in all other rows. Still the check box is in INVISIBLE mode.
FavouriteListAdapter
public class FavouriteListAdapter extends BaseAdapter {
private Context mContext;
private LayoutInflater mInflater;
ArrayList<FavouritesArray> mArrFavourites;
ViewHolder viewHolder;
String favId;
//Make checkbox to visible in all rows in listview
public void setcheckbox() {
viewHolder.favCheckbox.setVisibility(View.VISIBLE);
}
public static class ViewHolder {
public TextView favName;
public TextView favUrl;
public TextView favAddress;
public CheckBox favCheckbox;
}
public FavouriteListAdapter(Context context, ArrayList<FavouritesArray> lArrFavourites) {
mContext = context;
mArrFavourites = lArrFavourites;
}
#Override
public int getCount() {
if (mArrFavourites == null) {
return 0;
}
return mArrFavourites.size();
}
#Override
public Object getItem(int position) {
return null;
}
#Override
public long getItemId(int position) {
return 0;
}
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
mInflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
if (convertView == null) {
viewHolder = new ViewHolder();
convertView = mInflater.inflate(R.layout.favouritelistadapter, parent, false);
viewHolder.favName = (TextView) convertView.findViewById(R.id.fav_name);
viewHolder.favUrl = (TextView) convertView.findViewById(R.id.fav_url);
viewHolder.favAddress = (TextView) convertView.findViewById(R.id.fav_address);
viewHolder.favCheckbox = (CheckBox) convertView.findViewById(R.id.fav_checkbox);
viewHolder.favCheckbox .setVisibility(View.INVISIBLE);
convertView.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) convertView.getTag();
}
final FavouritesArray chooseService = mArrFavourites.get(position);
viewHolder.favName.setText(chooseService.getFavouritename());
viewHolder.favAddress.setText(chooseService.getFavouritelocation());
viewHolder.favCheckbox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (isChecked) {
favId = chooseService.getFavouritename();
((MainActivity) mContext).check(favId);
}
}
});
return convertView;
}}
I think you need boolean varibale showCheckBox and check it state in method getView.
Look at this sample:
private boolean showCheckBox = false;
public void showChecBox(boolean show) {
showCheckBox = show;
}
public View getView(final int position, View convertView, ViewGroup parent) {
mInflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
if (convertView == null) {
viewHolder = new ViewHolder();
convertView = mInflater.inflate(R.layout.favouritelistadapter, parent, false);
viewHolder.favName = (TextView) convertView.findViewById(R.id.fav_name);
viewHolder.favUrl = (TextView) convertView.findViewById(R.id.fav_url);
viewHolder.favAddress = (TextView) convertView.findViewById(R.id.fav_address);
viewHolder.favCheckbox = (CheckBox) convertView.findViewById(R.id.fav_checkbox);
convertView.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) convertView.getTag();
}
final FavouritesArray chooseService = mArrFavourites.get(position);
viewHolder.favName.setText(chooseService.getFavouritename());
viewHolder.favAddress.setText(chooseService.getFavouritelocation());
int checkBoxVisibility = showCheckBox : View.VISIBLE ? View.INVISIBLE;
viewHolder.favCheckbox.setVisibility(checkBoxVisibility);
viewHolder.favCheckbox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (isChecked) {
favId = chooseService.getFavouritename();
((MainActivity) mContext).check(favId);
}
}
});
return convertView;
}}
when a button is clicked in activity you need to call adapter.showCheckBoxes(true) of your adapter. then set a field to showCheckBoxes=true; in that function and also refresh the list using notifyDataSetChanged() which will cause the getView method to be called for all the rows.
In getView check if showCheckBoxes is true or not and show check boxes accordingly.
public class FavouriteListAdapter extends BaseAdapter {
private Context mContext;
private LayoutInflater mInflater;
ArrayList<FavouritesArray> mArrFavourites;
ViewHolder viewHolder;
String favId;
boolean showCheckBoxes = false;
//Make checkbox to visible in all rows in listview
public void setcheckbox() {
viewHolder.favCheckbox.setVisibility(View.VISIBLE);
}
public static class ViewHolder {
public TextView favName;
public TextView favUrl;
public TextView favAddress;
public CheckBox favCheckbox;
}
public FavouriteListAdapter(Context context, ArrayList<FavouritesArray> lArrFavourites) {
mContext = context;
mArrFavourites = lArrFavourites;
}
#Override
public int getCount() {
if (mArrFavourites == null) {
return 0;
}
return mArrFavourites.size();
}
#Override
public Object getItem(int position) {
return null;
}
#Override
public long getItemId(int position) {
return 0;
}
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
mInflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
if (convertView == null) {
viewHolder = new ViewHolder();
convertView = mInflater.inflate(R.layout.favouritelistadapter, parent, false);
viewHolder.favName = (TextView) convertView.findViewById(R.id.fav_name);
viewHolder.favUrl = (TextView) convertView.findViewById(R.id.fav_url);
viewHolder.favAddress = (TextView) convertView.findViewById(R.id.fav_address);
viewHolder.favCheckbox = (CheckBox) convertView.findViewById(R.id.fav_checkbox);
viewHolder.favCheckbox .setVisibility(View.INVISIBLE);
convertView.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) convertView.getTag();
}
final FavouritesArray chooseService = mArrFavourites.get(position);
viewHolder.favName.setText(chooseService.getFavouritename());
viewHolder.favAddress.setText(chooseService.getFavouritelocation());
if(showCheckBoxes){
viewHolder.favCheckbox .setVisibility(VISIBLE);
}else{
viewHolder.favCheckbox .setVisibility(INVISIBLE);
}
viewHolder.favCheckbox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (isChecked) {
favId = chooseService.getFavouritename();
((MainActivity) mContext).check(favId);
}
}
});
return convertView;
}}
public void showCheckBoxes(boolean showCheckBoxes){
this.showCheckBoxes=showCheckBoxes;
notifyDataSetChanged();
}
in your button click function:
void onClick(View v){
mAdapter.showCheckBoxes(true);
}

My simple custom listview show wrong items, not working as intended. Can't see what is wrong

I am trying to create something like this: https://i.stack.imgur.com/l8ZOc.png
However, i ran into a problem. When i create the list with my adapter, it is supposed to be a list of 8 items. However, it just shows the first 4 of these items in a random order two times. Do you see what is wrong with my code?
public class MyActivity extends Activity{
String headers[];
String image_urls[];
List<MyMenuItem> menuItems;
ListView mylistview;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_my);
menuItems = new ArrayList<MyMenuItem>();
headers = getResources().getStringArray(R.array.header_names);
image_urls = getResources().getStringArray(R.array.image_urls);
for (int i = 0; i < headers.length; i++) {
MyMenuItem item = new MyMenuItem(headers[i], image_urls[i]);
menuItems.add(item);
}
mylistview = (ListView) findViewById(R.id.list);
MenuAdapter adapter = new MenuAdapter(this, menuItems);
mylistview.setAdapter(adapter);
mylistview.setOnItemClickListener(this);
}
public class MyMenuItem {
private String item_header;
private String item_image_url;
public MyMenuItem(String item_header, String item_image_url){
this.item_header=item_header;
this.item_image_url=item_image_url;
}
public String getItem_header(){
return item_header;
}
public void setItem_header(String item_header){
this.item_header=item_header;
}
public String getItem_image_url(){
return item_image_url;
}
public void setItem_image_url(String item_image_url){
this.item_image_url=item_image_url;
}
}
public class MenuAdapter extends BaseAdapter{
Context context;
List<MyMenuItem> menuItems;
MenuAdapter(Context context, List<MyMenuItem> rowItems) {
this.context = context;
this.menuItems = rowItems;
}
#Override
public int getCount() {
return menuItems.size();
}
#Override
public Object getItem(int position) {
return menuItems.get(position);
}
#Override
public long getItemId(int position) {
return menuItems.indexOf(getItem(position));
}
private class ViewHolder {
ImageView ivMenu;
TextView tvMenuHeader;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder = null;
LayoutInflater mInflater = (LayoutInflater) context.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
if (convertView == null) {
convertView = mInflater.inflate(R.layout.menu_item, null);
holder = new ViewHolder();
holder.tvMenuHeader = (TextView) convertView.findViewById(R.id.tvMenuHeader);
holder.ivMenu = (ImageView) convertView.findViewById(R.id.ivMenuItem);
MyMenuItem row_pos = menuItems.get(position);
Picasso.with(context)
.load(row_pos.getItem_image_url())
.placeholder(R.drawable.empty)
.error(R.drawable.error)
.into(holder.ivMenu);
holder.tvMenuHeader.setText(row_pos.getItem_header());
Log.e("Test", "headers:" + row_pos.getItem_header());
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
return convertView;
}
}
You are setting the data only when the convertView is null.So when it is not null,list items are inflated with data of previous list items. getView should be something like this
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder = null;
LayoutInflater mInflater = (LayoutInflater) context.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
if (convertView == null) {
convertView = mInflater.inflate(R.layout.menu_item, null);
holder = new ViewHolder();
holder.tvMenuHeader = (TextView) convertView.findViewById(R.id.tvMenuHeader);
holder.ivMenu = (ImageView) convertView.findViewById(R.id.ivMenuItem);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
MyMenuItem row_pos = menuItems.get(position);
Picasso.with(context)
.load(row_pos.getItem_image_url())
.placeholder(R.drawable.empty)
.error(R.drawable.error)
.into(holder.ivMenu);
holder.tvMenuHeader.setText(row_pos.getItem_header());
Log.e("Test", "headers:" + row_pos.getItem_header());
return convertView;
}
I think this is the solution
else {
holder = (ViewHolder) convertView.getTag();
holder.tvMenuHeader.setText(row_pos.getItem_header());
}
I also encountered this problem earlier and this one works for me.

Custom Adapter No Id Value

Hi im trying to populate a listview from a baseadapter and when selected on a listview the wrong id is propagated.
here is my adapter
public class MyCustomBaseAdapter extends BaseAdapter {
private static ArrayList<Custom> AList;
private LayoutInflater inflat;
public MyCustomBaseAdapter(Context context, ArrayList<Custom> results) {
AList = results;
inflat = LayoutInflater.from(context);
}
public int getCount() {
return AList.size();
}
public Object getItem(int position) {
return AList.get(position);
}
public long getItemId(int position) {
return position;
}
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null) {
convertView = inflat.inflate(R.layout.suspect_list, null);
holder = new ViewHolder();
holder.txtName = (TextView) convertView.findViewById(R.id.suspect_name);
holder.txtSex = (TextView) convertView.findViewById(R.id.suspect_sex);
holder.txtId = (TextView) convertView.findViewById(R.id.suspect_id);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
holder.txtName.setText(AList.get(position).getName());
holder.txtSex.setText(AList.get(position).getSex());
holder.txtId.setText(AList.get(position).getID());
return convertView;
}
static class ViewHolder {
TextView txtName;
TextView txtSex;
TextView txtId;
}
}
Any Help you can provide would be great
More code can be availble upon request
Your getItemId() should return id.
So it should be like this->
public long getItemId(int position) {
return AList.get(position).getID();
}
Assuming that ID is long, if it is not then use -> Long.parseLong(AList.get(position).getID());

Categories