I have a ListView that uses a custom adapter. Each row contains 2 CheckBoxes that I want to check if they are ticked.
How would I loop through each row to check this and then, if they are checked, change a boolean array at the row position to true, then save these arrays using SharedPreferences?
And how would I set each CheckBox after opening the activity again by looking if the array at the position is true or false?
Thanks.
ListAdapter
public class LockerAdapter extends ArrayAdapter<LockerData> {
private Context mContext;
private int mLayoutResourceId;
LockerData[] mData = null;
CheckBox checkBoxHwk;
CheckBox checkBoxLkr;
//trying to change these arrays if boxes are ticked
public boolean[] homeworkCheck = new boolean[6];
public boolean[] lockerCheck = new boolean[6];
public LockerAdapter(Context context, int resource, LockerData[] objects) {
super(context, resource, objects);
this.mContext = context;
this.mLayoutResourceId = resource;
this.mData = objects;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View row = convertView;
LockerHolder holder = null;
if(row == null){
LayoutInflater inflater = LayoutInflater.from(mContext);
row = inflater.inflate(mLayoutResourceId,parent,false);
holder = new LockerHolder();
holder.theLessonName = (TextView) row.findViewById(R.id.generalLessonName);
holder.hwkCheck = (CheckBox) row.findViewById(R.id.homeworkCheck);
holder.lkrCheck = (CheckBox) row.findViewById(R.id.lockerCheck);
row.setTag(holder);
}else {
holder = (LockerHolder) row.getTag();
}
LockerData lesson = mData[position];
holder.theLessonName.setText(lesson.lessonsName);
return row;
}
public class LockerHolder{
TextView theLessonName;
CheckBox hwkCheck;
CheckBox lkrCheck;
}
}
Activity
public class HomeworkLockerActivity extends Activity {
private ListView hwkListview;
private LockerAdapter lockerAdapter;
private CheckBox checkBoxChem;
private CheckBox checkBoxPhys;
private CheckBox checkBoxMech;
private CheckBox checkBoxFP;
private CheckBox checkBoxCore;
private CheckBox checkBoxStats;
/*LockerData is just a class that takes in a single string in the
constructor to store the data*/
public LockerData[] lessons = {
new LockerData("Chemistry"),
new LockerData("Physics"),
new LockerData("Mechanics"),
new LockerData("Further Pure"),
new LockerData("Core 1"),
new LockerData("Statistics"),
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.layout_homework_locker);
hwkListview = (ListView) findViewById(R.id.homeworkListview);
lockerAdapter = new LockerAdapter(getApplicationContext(),R.layout.list,lessons);
hwkListview.setAdapter(lockerAdapter);
}
}
I recommend editing your LockerData class to accept three inputs: the name (ex: Chemistry), whether the homework is checked, and whether the locker is checked. Then you could edit your getView() in your adapter to case over the boolean values within the LockerData class instance, updating your checkboxes accordingly. With this approach, your two lists homeworkCheck and lockerCheck are not necessary.
As for Shared Preferences, I believe that you can only store primitive values (ex: boolean, int, string, etc.) and not lists. I would use an onCheckChanged Listener to update your shared preferences every time a checkbox is updated; so something like:
holder.hwkCheck.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
SharedPreferences.Editor editor = settings.edit();
//check what kind of button this is, in this case its chemistry
editor.putBoolean("chemistryCheck", isChecked);
}
}
);
I would retrieve these shared preferences in your Activity's onCreate class, and initialize your LockerData[] lessons accordingly.
Related
I think I have searched through all the posts relating to my question but could not find a solution to my problem. I have A ListView with two textviews and one Toggle button. Toggle button Changes its state when I scroll up or down (go out of view). I am using viewholder (suggested on the forum) that does make the button to retain its state but then the recycling property comes into play and mess up my application i.e multiple toggle buttons change their state on one click.
What I want?
I want my toggle button to retain its previous state when it goes out of view and comes back plus when I click one toggle button only that toggle button should work.
Here is my Code for Listview (pardon me for not putting much comments)
public class ActivityB extends AppCompatActivity {
ListView list;
Button edit;
public String text= "";
public SharedPreferences.Editor editor;
public SharedPreferences sharedPreferences;
private ArrayList<String> data = new ArrayList<String>();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_b);
list = (ListView) findViewById(R.id.listView);
generateListContent();
list.setAdapter(new MyListadapter(this,R.layout.constraint,data));
edit= (Button) findViewById(R.id.button);
sharedPreferences=getSharedPreferences("MyData",Context.MODE_PRIVATE);
editor=sharedPreferences.edit();
text=sharedPreferences.getString("Text","Null");
//Toast.makeText(this,text,Toast.LENGTH_LONG).show();
}
public void generateListContent() {
for (int i = 0; i < 11; i++) {
data.add("This is item no " + i);
}
}
private class MyListadapter extends ArrayAdapter<String> {
private int layout;
ArrayList<String> list;
public MyListadapter(#NonNull Context context, #LayoutRes int resource, #NonNull List<String> objects) {
super(context, resource, objects);
layout=resource;
list= (ArrayList<String>) objects;
}
#NonNull
#Override
public View getView(final int position, #Nullable View convertView, #NonNull ViewGroup parent) {
ViewHolder mainviewHolder=null;
if(convertView==null){
LayoutInflater inflater=LayoutInflater.from(getContext());
convertView= inflater.inflate(layout,parent,false);
final ViewHolder viewHolder = new ViewHolder();
viewHolder.title= (TextView) convertView.findViewById(R.id.textView);
viewHolder.lastone= (TextView) convertView.findViewById(R.id.textView2);
viewHolder.button= (ToggleButton) convertView.findViewById(R.id.toggleButton);
//mainviewHolder.title.setText(getItem(position));
viewHolder.button.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (isChecked) {
buttonView.setChecked(true);
Toast.makeText(getContext(), "Button is On" + position , Toast.LENGTH_LONG).show();
} else {
buttonView.setChecked(false);
Toast.makeText(getContext(), "Button is OFF" + position + buttonView.getId(),Toast.LENGTH_LONG).show();
}
}
});
convertView.setTag(viewHolder);
}
else{
mainviewHolder = (ViewHolder) convertView.getTag();
mainviewHolder.title.setText(getItem(position));
}
return convertView;
}
}
public class ViewHolder{
TextView title;
TextView lastone;
ToggleButton button;
}
}
check this...
Recyclerview Changing Items During Scroll
if above does not work....
Method 1
things you can try...
1.check button status outside toggle method....so that every time the listviewe loaded it can assign a value rather no value.
create a method togglebtn(viewHolder) // pass the instance of this perticualr item
Inside togglebtn....modify the toggle btn by reference with the instance.
togglebtn(viewHolder v)
{
}
Method 2
create a public data structure to hold the status of the button....preferebaly hasmap to store item no+check status....then check this value every time and update.
Feel free to ask.
Instead of creating array list of strings, create a custom object something like below.
Class A {
public String title;
public boolean isChecked;
}
Set correct value to isChecked(true/false) depending on toggle button state.
Also add one more line inside getview()
button.setChecked(list.get(position).isChecked)
Thanks Everyone for sparing your time and answering my question.
With these answers and a little help from forum' other posts, I found a solution.
Since I have a limited number of views so i removed the if/else condition on layout inflater. This solved the reuse of position variable. Now every view object has a unique position. Secondly the random button status behavior is resolved by saving the toggle button state in a separate array and keeping it outside my getview() method.
I'm trying to make a simple to-do list where you would long-press an item to mark it as 'done', in which case it will be greyed out and strikethrough.
I'm working on the strikethrough first and found some sample code here creating a strikethrough text in Android? . However the problem is that the setPaintFlags() method only seems to work on TextView whereas the items on my list are String. I can't cast a String to a TextView, and I found a workaround here but apparently it's highly discouraged to do it: Cast String to TextView . Also I looked up SpannableString but it doesn't seem to work for strings of varying length.
So I'm back at square one - is it at all possible to implement what I'm trying to do? Or will I have to store my list items differently instead?
Relevant code:
public class MainActivity extends ActionBarActivity {
private ArrayList<String> items;
private ArrayAdapter<String> itemsAdapter;
private ListView lvItems;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//Setting what the ListView will consist of
lvItems = (ListView) findViewById(R.id.lvItems);
readItems();
itemsAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, items);
lvItems.setAdapter(itemsAdapter);
// Set up remove listener method call
setupListViewListener();
}
//Attaches a long click listener to the listview
private void setupListViewListener() {
lvItems.setOnItemLongClickListener(
new AdapterView.OnItemLongClickListener() {
#Override
public boolean onItemLongClick(AdapterView<?> adapter,
View item, int pos, long id) {
// Trying to make the onLongClick strikethrough the text
String clickedItem = items.get(pos);
//What do I do here??
// Refresh the adapter
itemsAdapter.notifyDataSetChanged();
writeItems();
// Return true consumes the long click event (marks it handled)
return true;
}
});
}
Let's take a step back and consider your app. You want to show a list of jobs to the user. Each job has a description. And each job has two possible states: 'done' or 'not done'.
So I would like to introduce a class 'Job'
class Job
{
private String mDescription;
private boolean mDone;
public Job(String description)
{
this.mDescription = description;
this.mDone = false;
}
// ... generate the usual getters and setters here ;-)
// especially:
public boolean isDone()
{
return mIsDone;
}
}
This way your ArrayList 'items' becomes be a ArrayList< Job >. Wether a job is done or not will be stored together with its description. This is important because you want to show the current state of the job to the user by changing the look of the UI element, but you need to keep track of the job's state on the data level as well.
The UI element - the TextView - will be configured to present information about the job to the user. One piece of information is the description. The TextView will store this as a String. The other piece of information is the state (done/ not done). The TextView will (in your app) store this by setting the strike-through flag and changing its color.
Because for performance reasons a ListView uses less elements than the data list ('items') contains, you have to write a custom adapter. For brevity's sake, I'm keeping the code very simple, but it's worth the time to read up on the View Holder pattern:
Let's use a layout file 'mytextviewlayout.xml' for the list rows:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceMedium"
android:text="Medium Text"
android:id="#+id/textView"/>
</LinearLayout>
Now the code for the adapter looks like this:
EDIT changed from ArrayAdapter to BaseAdapter and added a view holder (see comments):
public class MyAdapter extends BaseAdapter
{
private ArrayList<Job> mDatalist;
private int mLayoutID;
private Activity mCtx;
private MyAdapter(){} // the adapter won't work with the standard constructor
public MyAdapter(Activity context, int resource, ArrayList<Job> objects)
{
super();
mLayoutID = resource;
mDatalist = objects;
mCtx = context;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View rowView = convertView;
if (rowView == null) {
LayoutInflater inflater = mCtx.getLayoutInflater();
rowView = inflater.inflate(mLayoutID, null);
ViewHolder viewHolder = new ViewHolder();
viewHolder.tvDescription = (TextView) rowView.findViewById(R.id.textView);
rowView.setTag(viewHolder);
}
ViewHolder vholder = (ViewHolder) rowView.getTag();
TextView tvJob = vholder.tvDescription;
Job myJob = mDatalist.get(position);
tvJob.setText(myJob.getJobDescription());
if (myJob.isDone())
{
// apply changes to TextView
tvJob.setPaintFlags(tvJob.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG);
tvJob.setTextColor(Color.GRAY);
}
else
{
// show TextView as usual
tvJob.setPaintFlags(tvJob.getPaintFlags() & (~Paint.STRIKE_THRU_TEXT_FLAG));
tvJob.setTextColor(Color.BLACK); // or whatever is needed...
}
return rowView;
}
#Override
public int getCount()
{
return mDatalist.size();
}
#Override
public Object getItem(int position)
{
return mDatalist.get(position);
}
#Override
public long getItemId(int position)
{
return position;
}
static class ViewHolder
{
public TextView tvDescription;
}
}
Due to the changed adapter,
in the MainActivity, you have to declare 'items' and 'itemsAdapter' as follows:
private ArrayList<Job> items;
private MyAdapter itemsAdapter;
...and in your 'onCreate()' method, you write:
itemsAdapter = new MyAdapter<String>(this, R.layout.mytextviewlayout, items);
Don't forget to change the 'readItems()' and 'writeItems()' methods because 'items' now is a ArrayList< Job >.
Then, finally, the 'onItemLongClick()' method:
EDIT use 'parent.getItemAtPosition()' instead of 'items.get()', see comments
#Override
public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id)
{
// items.get(position).setDone(true);
Object o = parent.getItemAtPosition(position);
if (o instanceof Job)
{
((Job) o).setDone(true);
}
// and now indeed the data set has changed :)
itemsAdapter.notifyDataSetChanged();
writeItems();
return true;
}
Here is my method:
#Override
public void onRestoreInstanceState(Bundle savedInstanceState) {
DataBaseHandler handler = new DataBaseHandler(getApplicationContext());
//set the spinner for measurement type
Spinner measurementTypeSpinner = (Spinner) findViewById(R.id.MeasurementTypes);
ArrayAdapter adapter = (ArrayAdapter) measurementTypeSpinner.getAdapter();
int typePos = adapter.getPosition(savedInstanceState.getString("measurementtype"));
measurementTypeSpinner.setSelection(typePos);
//set the spinner for the measurement unit
Spinner measurementUnitSpinner = (Spinner) findViewById(R.id.MeasurementSubValues);
ArrayAdapter arrayAdapter = (ArrayAdapter) measurementUnitSpinner.getAdapter();
int unitPos = arrayAdapter.getPosition(savedInstanceState.getString("measurementunit"));
measurementUnitSpinner.setSelection(unitPos);
//set the value
EditText value = (EditText) findViewById(R.id.unit_value);
value.setText(savedInstanceState.getString("value"));
/**
* The list view stuff
*/
ListView unitsList = (ListView) findViewById(R.id.units_list);
unitsList.setItemsCanFocus(true);
MeasurementType mType = handler.getMeasurementType(savedInstanceState.getString("measurementtype"));
//create the converter
Converter converter = new Converter(MeasurementType.getMeasurementType(savedInstanceState.getString("measurementtype")), savedInstanceState.getString("measurementunit"), savedInstanceState.getString("value"));
//convert the values
ArrayList<Unit> convertedValues = converter.convert();
//set the adapter for the list view
unitAdapter = new UnitListAdapter(this, convertedValues, mType);
unitsList.setAdapter(unitAdapter);
}
Basically, there is another activity with a list of items and when the user checks one, it updates the database setting an int property to 1, so that when the ArrayAdapter goes through an arraylist it picks up the property as 1 and displays it, instead of 0 in which case it doesn't display it.
Now on pressing the back button, both the spinners are populated with the values I stored, the value for the EditText is restored, but the ListView is not updated, yet when I leave the app and come back in, the value that was checked is there in the list...
This says to me that I might need to do something with onStop() and onRestart() could someone please advice me. The comment saying 'the list view stuff' is where I am trying to update the list view, it just isn't working and when I debug it won't go into the restore method at all, which is confusing.
EDIT
public class UnitListAdapter extends ArrayAdapter<Unit> {
private Context context;
private ArrayList<Unit> units;
private MeasurementType type;
public UnitListAdapter(Context context, ArrayList<Unit> units, MeasurementType type) {
super(context, R.layout.unit, R.id.unit_name, units);
this.context = context;
this.units = units;
this.type = type;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View rowView = inflater.inflate(R.layout.unit, parent, false);
final TextView unitName = (TextView) rowView.findViewById(R.id.unit_name);
final EditText unitValue = (EditText) rowView.findViewById(R.id.unit_value);
if(units.get(position) != null) {
if(units.get(position).getView() == 1) {
unitName.setText(units.get(position).getUnitName());
unitValue.setText(units.get(position).getValue().toString());
} else {
unitName.setVisibility(View.GONE);
unitValue.setVisibility(View.GONE);
}
}
return rowView;
}
#Override
public void add(Unit u) {
units.add(u);
notifyDataSetChanged();
}
#Override
public void clear() {
units.clear();
notifyDataSetChanged();
}
#Override
public int getCount() {
return units.size();
}
}
As asked for. Sorry about confusion whilst editing.
onRestoreInstanceState() is not called when the user presses the back button. Most likely you need to move your logic to onResume(). I suggest that you read about the Activity lifecycle to get a better understanding about when each of the onXxx() methods are called.
After updating the list you need to call notifyDataSetChanged() to repopulate the listview.
http://developer.android.com/reference/android/widget/ArrayAdapter.html#notifyDataSetChanged()
I have a ListView with CheckBox on it. and i am using Custom Adapter to populate the ListView.
In my xml file i have a Button at bottom. what i want is let user select number of rows in ListView and when he/she clicked on the Button get the position of the selected items so that i could get the object for particular row for further calculations.
In the customadapter's getview method, do
//use the actual id of your checkbox of course
Checkbox checkbox = (CheckBox)findViewById(R.id.checkbox);
checkbox.setFocusable(false);
checkbox.setFocusableInTouchMode(false);
now the checkbox is clickable as is the listitem.
To solve this problem you will have to create a custom Item class which will represent your individual checkboxes on the list. The array of these items will then be used by the adapter class to display your check boxes.
This Item class will have a boolean variable isSelected which will determine if the checkbox is selected or not. You will have to set the value of this variable in your OnClick Method of your custom adapter class
For Example
class CheckBoxItem{
boolean isSelected;
public void setSelected(boolean val) {
this.isSelected = val;
}
boolean isSelected(){
return isSelected;
}
}
For your CustomAdapter Class which look like following:
public class ItemsAdapter extends ArrayAdapter implements OnClickListener {
// you will have to initialize below in the constructor
CheckBoxItem items[];
// You will have to create your check boxes here and set the position of your check box
/// with help of setTag method of View as defined in below method, you will use this later // in your onClick method
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View v = convertView;
CheckBox cBox = null;
if (v == null) {
LayoutInflater vi = (LayoutInflater) apUI.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = vi.inflate(R.layout.attachphoto, null);
}
CheckBoxItemItem it = items[position];
cBox =(CheckBox) v.findViewById(R.id.apCheckBox);
cBox.setOnClickListener(this);
cBox.setTag(""+position);
Log.d(TAG, " CHECK BOX IS: "+cBox+ " Check Box selected Value: "+cBox.isChecked()+" Selection: "+it.isSelected());
if(cBox != null){
cBox.setText("");
cBox.setChecked(it.isSelected());
}
return v;
}
public void onClick(View v) {
CheckBox cBox =(CheckBox) v.findViewById(R.id.apCheckBox);
int position = Integer.parseInt((String) v.getTag());
Log.d(TAG, "CLicked ..."+cBox.isChecked());
items[position].setSelected(cBox.isChecked());
}
}
Later you will will declare and array of your CheckBoxItem class which will be contained by your Adapter class in this case it will be ItemsAdapter class.
Then when the user presses the button you can iterate through all the items in the array and check which one is selected by using the isSelected() method of CheckBoxItem class.
In your activity you will have:
ArrayList getSelectedItems(){
ArrayList selectedItems = new ArrayList();
int size = items.length;
for(int i = 0; i<size; i++){
CheckBoxItem cItem = items[i];
if(cItem.isSelected()){
selectedItems.add(cItem);
}
}
return selectedItems;
}
I had the exact same problem. I solved it in this way
public class myActivity extends Activity {
//ActionBarSherlock mSherlock = ActionBarSherlock.wrap(this);
public ListView listview;
private ArrayList<Object> itemlist=new ArrayList<Object>();
Button button;
private myAdapter adapter;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
listview=(ListView)findViewById(R.id.listview1);
button=(Button)findViewById(R.id.button1);
/*add some data to ur list*/ itemlist.add(something);
adapter=new Adapter(myActivity.this, 0, itemlist);
listview.setAdapter(adapter);
**listview.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
listview.setItemsCanFocus(false);**
button.setOnClickListner(new OnClickListner()
{
#Override
public void OnClick(View v)
{
/* this returns the checked item positions in the listview*/
**ArrayList<Integer> itempositions=adapter.getcheckeditemcount();**
for(int i:itempositions)
{
/* This is the main part...u can retrieve the object in the listview which is checked and do further calculations with it*/
**Object info=adapter.getItem(i);**
Log.d(TAG,"checked object info= ",info.something);
}
}
});
}
private class myAdapter extends ArrayAdapter<Object> {
private Context context;
private ArrayList<Object> list;
**private ArrayList<Integer> checkedpositions;**
public myAdapter(Context localContext,int textViewResourceId, ArrayList<Object> objects) {
super(localContext,textViewResourceId,objects);
context = localContext;
this.list=objects;
this.checkedpositions=new ArrayList<Integer>();
//Log.d("adapter","list size= "+objects.size());
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ImageView picturesView;
View v = convertView;
TextView Mainitem;
final CheckBox check;
if (v == null)
{
LayoutInflater vi = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = vi.inflate(R.layout.albumview, null);
Object item=list.get(position);
if(item!=null)
{
check = (CheckBox)v.findViewById(R.id.checkBox1);
/* set a tag for chekbox with the current view position */
**check.setTag(position);**
/*set a onchecked change listner for listning to state of checkbox toggle */
check.setOnCheckedChangeListener(new OnCheckedChangeListener()
{
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked)
{
/*get the tag of the checkbox...in this case this will give the (position of view)*/
Object tag=check.getTag();
if ( isChecked )
{
// perform logic
count++;
Log.d("Checkbox","added "+tag);
checkedpositions.add((Integer) tag);
}
else
{
count--;
checkedpositions.remove(tag);
Log.d("Checkbox","removed "+(Integer)tag);
}
/* if u dont have a textview in ur listview then ignore this part */
Mainitem = (TextView) v.findViewById(R.id.textView1);
Mainitem.setText(item.Album_name);
} catch (IOException e) {
// TODO Auto-generated catch block
Log.d("error", "wall");
}
}
}
return v;
}
/* Finally create a method which return the checkeditem postions in the listview */
**public ArrayList<Integer> getcheckeditemcount()
{
return this.checkedpositions;
}**
}
}
I hope this helps.
I've created a custom ListView with checkboxes. I wanted to delete the selected items on "Delete" menu option selection.
I am handling the onCheckedChanged event on CheckBox. Here I maintain an ArrayList to note down the selected elements position. Now when the user selects the "Delete" menu item I do remove the choosen items from ListAdapter's ArrayList.
Below is my code,
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
names = new ArrayList<String>();
names.add("first");
names.add("second");
names.add("three");
names.add("four");
names.add("five");
names.add("six");
names.add("seven");
names.add("eight");
names.add("nine");
listAdapter = new SelfAdapter(this,names);
this.setListAdapter(listAdapter);
}
#Override
public boolean onOptionsItemSelected(MenuItem menuItem){
int menuId = menuItem.getItemId();
ArrayList<Integer> selectedItems;
switch(menuId){
case R.id.delitem:
Log.d(TAG,"del item selected");
selectedItems = listAdapter.getSelected();
**//pick the selected position items and delete them from the
// listadapter arraylist**
for(Integer element: selectedItems){
Log.d(TAG,"Selected:"+element.toString());
names.remove(element.intValue());
listAdapter.notifyDataSetChanged();
}
}
return true;
}
Here is the code for custom adapter,
class SelfAdapter extends ArrayAdapter<String>{
ViewHolder holder = new ViewHolder();
private Activity context;
private ArrayList<String> names;
private String TAG = "SelfAdapter";
ArrayList<Integer> checkedPos; **//contains the selected items position**
public SelfAdapter(Context context, ArrayList names) {
super(context,R.layout.checkboxnlist, names);
this.context = (Activity) context;
this.names = names;
checkedPos = new ArrayList<Integer>();
}
#Override
public View getView(int position, View convertView, ViewGroup parent){
final int listPosition = position;
if(convertView == null){
LayoutInflater inflater = context.getLayoutInflater();
convertView = inflater.inflate(R.layout.checkboxnlist,parent,false);
holder.chkBox = (CheckBox)convertView.findViewById(R.id.chkvw);
holder.txtView = (TextView)convertView.findViewById(R.id.txtvw);
convertView.setTag(holder);
}
else{
holder = (ViewHolder) convertView.getTag();
}
holder.txtView.setText(names.get(position));
holder.chkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener(){
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
Log.d(TAG,"listPosition:"+listPosition);
if(isChecked){
checkedPos.add(new Integer(listPosition));
}
else{
checkedPos.remove(listPosition);
}
}
});
return convertView;
}
public ArrayList<Integer> getSelected(){
return checkedPos;
}
static class ViewHolder{
TextView txtView;
CheckBox chkBox;
}
}
Now the problem is that if select 1st,2nd items (for example) then I see the wrong items get deleted and the listview populate after this is completely wrong. Later if I attempt to delete the items it's throwing "Index out of bounds exception". I guess the code is going wrong in getView method.
Can some one help me in finding out what am doing wrong here.
Thanks
When you remove elements from names, you also need to remove elements from the checkedPos array. Otherwise, the two arrays will have different lengths. Then when you try again, checkedPos will be longer than names and you end up with the index out of bounds exception.
Also, when you are deleting from names, you can't use a normal iterator through . If you are supposed to delete names at indexes 1 and 2, then when you delete name 1, name 2 moves up to position 1. But your indexing isn't updated accordingly. The easiest solution is to iterate backwards through the position array, deleting from the end of names before deleting from the beginning.
P.S. It's a little weird to switch from ordinal numbers ("first", "second") to cardinal numbers ("three", "four", etc.) in the middle of the list.
you must delete
names = new ArrayList< STRING >();
but you delete selectedItems;