Listview to SQLite - android

I have created a listview which displays the installed applications. It has app icon + app name + check box. I want to select apps from this list and store the app names in a sqlite DB how should I begin with this?
Like how to identify the selected apps?

here's an adapter I made for one of my apps. This is a classroom attendance function that shows the student's name, photo and a couple of checkboxes (one for here, for for late). The list comes from a SQlite query, but I need to do something with each checkbox that is clicked.
public class MyDataAdapter extends SimpleCursorAdapter {
private Cursor c;
private Context context;
private Long classnum;
private gradeBookDbAdapter mDbHelper;
public static final int LATE=2;
public static final int ATTEND=1;
int idxCol;
int idx;
// itemChecked will store the position of the checked items.
public MyDataAdapter(Context context, int layout, Cursor c, String[] from,
int[] to, Long mRowId) {
super(context, layout, c, from, to);
this.c = c;
this.context = context;
mDbHelper = new gradeBookDbAdapter(context);
mDbHelper.open();
classnum = mRowId;
c.moveToFirst();
}
public class ViewHolder{
public TextView text;
public TextView text2;
public ImageView image;
public CheckBox here;
public CheckBox late;
}
public View getView(final int pos, View inView, ViewGroup parent) {
Bitmap bm;
ImageView studentPhoto;
View vi=inView;
final ViewHolder holder;
if (inView == null) {
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
vi = inflater.inflate(R.layout.show_attendance, null);
holder=new ViewHolder();
holder.text=(TextView)vi.findViewById(R.id.stuname);
holder.text2=(TextView)vi.findViewById(R.id.stuIndex);
holder.image=(ImageView)vi.findViewById(R.id.icon);
holder.here=(CheckBox)vi.findViewById(R.id.attend);
holder.late=(CheckBox)vi.findViewById(R.id.late);
vi.setTag(holder);
}
else
holder=(ViewHolder)vi.getTag();
c.moveToPosition(pos);
int index = c.getColumnIndex(gradeBookDbAdapter.KEY_NAME);
String name = c.getString(index);
holder.text.setText(name);
index = c.getColumnIndex(gradeBookDbAdapter.KEY_ROWID);
String Index = c.getString(index);
holder.text2.setText(Index);
bm = gradeBookDbAdapter.getStudentPhoto(name);
if (bm != null) {
holder.image.setImageBitmap(bm);
}
else {
// use icon image
holder.image.setImageResource(R.drawable.person_icon);
}
// pull out existing attend/late fields and set accordingly
int attend = c.getInt(c.getColumnIndex(gradeBookDbAdapter.KEY_ATTEND));
if(attend==1){
holder.here.setChecked(true);
itemCheckedHere.set(pos, true);
}
//else {
// holder.here.setChecked(false);
// itemCheckedHere.set(pos, false);
//}
int late = c.getInt(c.getColumnIndex(gradeBookDbAdapter.KEY_LATE));
if (late==1){
holder.late.setChecked(true);
itemCheckedLate.set(pos, true);
}
//else {
// holder.late.setChecked(false);
// itemCheckedLate.set(pos, false);
//}
holder.here.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
CheckBox cb = (CheckBox) v.findViewById(R.id.attend);
if (cb.isChecked()) {
itemCheckedHere.set(pos, true);
int Index = new Integer(holder.text2.getText().toString());
mDbHelper.updateAttend(Index, classnum, ATTEND, 1, attendDate );
} else if (!cb.isChecked()) {
itemCheckedHere.set(pos, false);
int Index = new Integer(holder.text2.getText().toString());
mDbHelper.updateAttend(Index, classnum, ATTEND, 0, attendDate );
}
}
});
holder.late.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
CheckBox cb = (CheckBox) v.findViewById(R.id.late);
if (cb.isChecked()) {
itemCheckedLate.set(pos, true);
int Index = new Integer(holder.text2.getText().toString());
mDbHelper.updateAttend(Index, classnum, LATE, 1, attendDate );
} else if (!cb.isChecked()) {
itemCheckedLate.set(pos, false);
int Index = new Integer(holder.text2.getText().toString());
mDbHelper.updateAttend(Index, classnum, LATE, 0, attendDate );
}
}
});
holder.here.setChecked(itemCheckedHere.get(pos)); // this will Check or Uncheck the
holder.late.setChecked(itemCheckedLate.get(pos)); // this will Check or Uncheck the
// CheckBox in ListView
// according to their original
// position and CheckBox never
// loss his State when you
// Scroll the List Items.
return vi;
}
}
Notice I have two sparse arrays "ItemCheckedHere' and "ItemCheckLate". these keep track of which items I've selected. Android doesn't keep track and will reuse a view, so scrolling a list of checkboxes will result in boxes getting checked or unchecked seemingly at random without these arrays I use to maintain the checked status.

you'll need to make a custom listView adapter. You can make each item selectable and then when the user selects an app, you can call the code to insert it into your DB

Related

Get tags from Radiobuttons in ListView Android

I have a custom listView built with ArrayAdapter. In ListView each item contents a TextView and a RadioGroup (with 4 RadioButton). I can choose one RadioButton to be selected for each list item. On the bottom of ListView i have a footer with button. What i want is to get all data when i click on button like this:
name1 - 1
name2 - 3
name3 - 2
name4 - 3
...
First column - Text from TextView
Second column - Tag of selected RadioButton
Atcivity with view:
public class MarksAdd extends ListActivity {
ArrayList<String> itemlist = new ArrayList<String>();
private Context context = null;
private ListView listView;
private Button BtnDone;
#Override
public void onCreate(Bundle saveInstanceState) {
super.onCreate(saveInstanceState);
setContentView(R.layout.marks_add);
Intent intent = getIntent();
int day = intent.getIntExtra("day", 0);
int month = intent.getIntExtra("month", 0);
int year = intent.getIntExtra("year", 0);
String dayStr = String.valueOf(day);
String monthStr = String.valueOf(month);
String yearStr = String.valueOf(year);
if (day != 0) {
if(dayStr.length()==1){
dayStr = "0"+dayStr;
}
if(monthStr.length()==1){
monthStr = "0"+monthStr;
}
yearStr = yearStr.substring(2);
String date = dayStr+"."+monthStr+"."+yearStr;
Toast.makeText(this, date, Toast.LENGTH_SHORT).show();
}
final ArrayAdapter<Model> adapter = new InteractiveArrayAdapter(this,
getModel());
listView = getListView();
LayoutInflater inflater = getLayoutInflater();
listView.addFooterView(inflater.inflate(R.layout.list_footer, null), null, false);
setListAdapter(adapter);
BtnDone = (Button) findViewById(R.id.markListBtn);
BtnDone.setOnClickListener( new View.OnClickListener() {
#Override
public void onClick(View v) {
//get Values ?????
}
});
}
private List<Model> getModel() {
List<Model> list = new ArrayList<Model>();
dbHelper sql = new dbHelper(this);
SQLiteDatabase db = sql.getWritableDatabase();
Cursor cursor = db.query(
PreferenceManager.getDefaultSharedPreferences(getBaseContext()).getString("group", ""), new String[]{
"Id", "Name"},
null, // The columns for the WHERE clause
null, // The values for the WHERE clause
null, // don't group the rows
null, // don't filter by row groups
"Name ASC" // The sort order
);
while (cursor.moveToNext()) {
// GET COLUMN INDICES + VALUES OF THOSE COLUMNS
int id = cursor.getInt(cursor.getColumnIndex("Id"));
String name = cursor.getString(cursor
.getColumnIndex("Name"));
list.add(get(name));
}
cursor.close();
// Initially select one of the items
return list;
}
private Model get(String question) {
return new Model(question);
}
}
ArrayAdapter:
public class InteractiveArrayAdapter extends ArrayAdapter<Model> {
private final List<Model> list;
private final Activity context;
public InteractiveArrayAdapter(Activity context, List<Model> list) {
super(context, R.layout.simple_list_item1_marks, list);
this.context = context;
this.list = list;
}
class ViewHolder {
TextView t = null;
RadioGroup group;
ViewHolder(View v) {
t = (TextView) v.findViewById(R.id.personName);
group = (RadioGroup) v.findViewById(R.id.myRgroup);
}
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View v = convertView;
ViewHolder holder = null;
if (v == null) {
LayoutInflater inflater = context.getLayoutInflater();
v = inflater.inflate(R.layout.simple_list_item1_marks, parent, false);
holder = new ViewHolder(v);
v.setTag(holder);
final View finalV = v;
holder.group
.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
public void onCheckedChanged(RadioGroup group,
int checkedId) {
Integer pos = (Integer) group.getTag(); // To identify the Model object i get from the RadioGroup with getTag()
// an integer representing the actual position
Model element = list.get(pos);
switch (checkedId) { //set the Model to hold the answer the user picked
case R.id.rb1:
element.current = Model.ANSWER_ONE_SELECTED;
break;
case R.id.rb2:
element.current = Model.ANSWER_TWO_SELECTED;
break;
case R.id.rb3:
element.current = Model.ANSWER_THREE_SELECTED;
break;
case R.id.rb4:
element.current = Model.ANSWER_FOUR_SELECTED;
break;
default:
element.current = Model.NONE; // Something was wrong set to the default
}
}
});
} else {
holder = (ViewHolder) v.getTag();
}
holder.group.setTag(position); // I passed the current position as a tag
holder.t.setText(list.get(position).question); // Set the question body
if (list.get(position).current != Model.NONE) {
RadioButton r = (RadioButton) holder.group.getChildAt(list
.get(position).current);
r.setChecked(true);
} else {
holder.group.clearCheck(); // This is required because although the Model could have the current
// position to NONE you could be dealing with a previous row where
// the user already picked an answer.
}
return v;
}
}
Model:
public class Model {
String question; // hold the question
int current = NONE; // hold the answer picked by the user, initial is NONE(see below)
public static final int NONE = 1000; // No answer selected
public static final int ANSWER_ONE_SELECTED = 0; // first answer selected
public static final int ANSWER_TWO_SELECTED = 1; // second answer selected
public static final int ANSWER_THREE_SELECTED = 2; // third answer selected
public static final int ANSWER_FOUR_SELECTED = 3; // forth answer selected
public Model(String question) {
this.question = question;
}
}
I was doing this according to that tutorial with some changes. Actualy i'm realy newbie in development, so im asking you to help me. Sorry if my question is not correct, my english is not realy good.
Well be very thankfull for any help here.
The first thought would be to iterate over the ListView and get the checked button in each row. This won't actually work because ListView does not contain all of its children all of the time.
Instead, you should store the checked item when the user actually makes a selection. Then when you press the button, you already have all the data stored and don't have to iterate over the ListView. Also, having the current selections saved this way will be useful if you scroll back up the list because you can set the current checked radio button for previous items in getView().
Let's assume the row layout has this in it:
<RadioGroup android:id="#+id/radio_group" ... >
<RadioButton android:id="#+id/radio_button_1" ... />
<RadioButton android:id="#+id/radio_button_2" ... />
<RadioButton android:id="#+id/radio_button_3" ... />
<RadioButton android:id="#+id/radio_button_4" ... />
</RadioGroup>
In your adapter's getView(), give the RadioGroup an OnCheckedChangedListener defined in the adapter itself (so you have one OnCheckedChangedListener instead of one per row). Tag the RadioGroup with the position of the list item so that you can differentiate it in the callback.
#Override
public View getView(int position, View convertView, ViewGroup parent) {
...
Model model = getItem(position);
int checkedId = ... //figure out checked id from model
viewHolder.group.check(checkedId);
viewHolder.group.setTag(position);
viewHolder.group.setOnCheckedChangedListener(checkChangedListener);
...
}
private OnCheckedChangedListener checkChangedListener = new OnCheckedChangedListener() {
#Override
public void onCheckChanged(RadioGroup group, int checkId) {
Object tag = group.getTag();
if (!(tag instanceof Integer)) {
// you have a bug. Fix it!
return;
}
int position = (Integer) tag;
Model model = getItem(position);
switch(checkedId) {
case R.id.radio_button_1:
model.setCurrent(Model.ANSWER_ONE_SELECTED); break;
case R.id.radio_button_1:
model.setCurrent(Model.ANSWER_TWO_SELECTED); break;
case R.id.radio_button_1:
model.setCurrent(Model.ANSWER_THREE_SELECTED); break;
case R.id.radio_button_1:
model.setCurrent(Model.ANSWER_FOUR_SELECTED); break;
}
}
};
Now you just need to get your list of Models from the adapter.

how to bind a checkbox to a listview

I have a listview containing on each row a textview with a checkbox, so when the checkbox is checked and we scroll down through the listview the checkbox instance will be taken from a place to another (reused..) and I have several checked checkboxes how to fix that I tried to bind the checkbox to the listview but that didn't work my code is:
SimpleCursorAdapter adapter =new SimpleCursorAdapter(this,R.layout.rating,cu,new String[]{"Title","Favorites"}, new int[]{R.id.text1,R.id.bt_rating},CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER);
listv.setAdapter(adapter);
adapter.setViewBinder(new SimpleCursorAdapter.ViewBinder(){
/** Binds the Cursor column defined by the specified index to the specified view */
public boolean setViewValue(View view, Cursor cursor, int columnIndex){
if(view.getId() == R.id.bt_rating){
((CheckBox)view).setChecked(Boolean.valueOf(cursor.getString(cursor.getColumnIndex("Favorites"))));
((CheckBox)view).setOnCheckedChangeListener(myCheckChangList);
return true; //true because the data was bound to the view
}
return false;
}
});
OnCheckedChangeListener myCheckChangList = new OnCheckedChangeListener() {
public void onCheckedChanged(CompoundButton buttonView,
boolean isChecked) {
buttonView.setChecked(isChecked);
}
};
My xml code of the content of the row of my listview is:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal" >
<CheckBox
android:id="#+id/bt_rating"
android:focusable="false"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:button="#android:drawable/btn_star"/>
<TextView
android:id="#+id/text1"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textSize="#dimen/fsinlistview"
/>
</LinearLayout>
It looks like your OnCheckedChangedListener is the problem here. If you look at your code, see that every checkbox is getting a reference to the same listener. So when you check one box, you're setting every other box as checked too - and you're not updating your backing data, either.
Your OnCheckedChangedListener should not be updating the view state of the checkbox - the callback is fired because the state has already changed.
So you need to do the following steps when a user checks the checkbox:
Figure out which item was checked, and how that corresponds to your data
Update your data to suit the new checked/unchecked state
Notify your adapter of a data change/update your cursor
You could do this something like the following, tagging the view with the ID of the row it represents:
public boolean setViewValue(View view, Cursor cursor, int columnIndex){
if(view.getId() == R.id.bt_rating){
view.setTag(cursor.getInt(cursor.getColumnIndex(SomeDBContract.ID)));
((CheckBox)view).setChecked(Boolean.valueOf(cursor.getString(cursor.getColumnIndex("Favorites"))));
((CheckBox)view).setOnCheckedChangeListener(myCheckChangList);
return true; //true because the data was bound to the view
}
return false;
}
Then, in your listener you can update your database according to that ID:
CheckedChangeListener myCheckChangList = new OnCheckedChangeListener() {
public void onCheckedChanged(CompoundButton buttonView,
boolean isChecked) {
int rowId = (int) buttonView.getTag();
// Handle updating the database as per normal
updateSomeDbRowAsChecked(rowId, isChecked);
}
};
Finally, you'll need to update your cursor adapter with a new cursor once the database row is updated:
myAdapter.swapCursor(newCursor);
You'll have to adjust all of this to suit your code, but it should give you an idea of one way you can approach this problem.
In any Listview, the view are reused. As you scroll through the list, those that scroll up and off screen are recycled and used with newer information as it comes in below.
You need to keep track of your checkboxes with a sparse array. Mark the index in the array as cherked/unchecked as the user touches each. You then set the state of the checkbox based on the value in the array.
Here is some example code from an an older app, that does both a "select all" checkboxes as well as manages the entire list of those checked and unchecked. It was for a classroom attendance app I wrote, so it was much easier for a teacher to select "ALL" being in class and then unselect those that weren't present.
I have two checkboxes in this listview, and two sparse arrays, itemCheckedHere and itemCheckedLate (whether a student is in class, or was late).
public class MyDataAdapter extends SimpleCursorAdapter {
private Cursor c;
private Context context;
private Long classnum;
private gradeBookDbAdapter mDbHelper;
public static final int LATE=2;
public static final int ATTEND=1;
int idxCol;
int idx;
// itemChecked will store the position of the checked items.
public MyDataAdapter(Context context, int layout, Cursor c, String[] from,
int[] to, Long mRowId) {
super(context, layout, c, from, to);
this.c = c;
this.context = context;
mDbHelper = new gradeBookDbAdapter(context);
mDbHelper.open();
classnum = mRowId;
c.moveToFirst();
}
public class ViewHolder{
public TextView text;
public TextView text2;
public ImageView image;
public CheckBox here;
public CheckBox late;
}
public View getView(final int pos, View inView, ViewGroup parent) {
Bitmap bm;
ImageView studentPhoto;
View vi=inView;
final ViewHolder holder;
if (inView == null) {
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
vi = inflater.inflate(R.layout.show_attendance, null);
holder=new ViewHolder();
holder.text=(TextView)vi.findViewById(R.id.stuname);
holder.text2=(TextView)vi.findViewById(R.id.stuIndex);
holder.image=(ImageView)vi.findViewById(R.id.icon);
holder.here=(CheckBox)vi.findViewById(R.id.attend);
holder.late=(CheckBox)vi.findViewById(R.id.late);
vi.setTag(holder);
}
else
holder=(ViewHolder)vi.getTag();
c.moveToPosition(pos);
int index = c.getColumnIndex(gradeBookDbAdapter.KEY_NAME);
String name = c.getString(index);
holder.text.setText(name);
index = c.getColumnIndex(gradeBookDbAdapter.KEY_ROWID);
String Index = c.getString(index);
holder.text2.setText(Index);
bm = gradeBookDbAdapter.getStudentPhoto(name);
if (bm != null) {
holder.image.setImageBitmap(bm);
}
else {
// use icon image
holder.image.setImageResource(R.drawable.person_icon);
}
// pull out existing attend/late fields and set accordingly
int attend = c.getInt(c.getColumnIndex(gradeBookDbAdapter.KEY_ATTEND));
if(attend==1){
holder.here.setChecked(true);
itemCheckedHere.set(pos, true);
}
//else {
// holder.here.setChecked(false);
// itemCheckedHere.set(pos, false);
//}
int late = c.getInt(c.getColumnIndex(gradeBookDbAdapter.KEY_LATE));
if (late==1){
holder.late.setChecked(true);
itemCheckedLate.set(pos, true);
}
//else {
// holder.late.setChecked(false);
// itemCheckedLate.set(pos, false);
//}
if (selectAllTouched) {
if(selectAll){
holder.here.setChecked(true);
itemCheckedHere.set(pos, true);
int who= new Integer(holder.text2.getText().toString());
mDbHelper.updateAttend(who, classnum, ATTEND, 1, attendDate );
}
else{
holder.here.setChecked(false);
itemCheckedHere.set(pos, false);
int who = new Integer(holder.text2.getText().toString());
mDbHelper.updateAttend(who, classnum, ATTEND, 0, attendDate );
}
}
holder.here.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
CheckBox cb = (CheckBox) v.findViewById(R.id.attend);
if (cb.isChecked()) {
itemCheckedHere.set(pos, true);
int Index = new Integer(holder.text2.getText().toString());
mDbHelper.updateAttend(Index, classnum, ATTEND, 1, attendDate );
} else if (!cb.isChecked()) {
itemCheckedHere.set(pos, false);
int Index = new Integer(holder.text2.getText().toString());
mDbHelper.updateAttend(Index, classnum, ATTEND, 0, attendDate );
}
}
});
holder.late.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
CheckBox cb = (CheckBox) v.findViewById(R.id.late);
if (cb.isChecked()) {
itemCheckedLate.set(pos, true);
int Index = new Integer(holder.text2.getText().toString());
mDbHelper.updateAttend(Index, classnum, LATE, 1, attendDate );
} else if (!cb.isChecked()) {
itemCheckedLate.set(pos, false);
int Index = new Integer(holder.text2.getText().toString());
mDbHelper.updateAttend(Index, classnum, LATE, 0, attendDate );
}
}
});
holder.here.setChecked(itemCheckedHere.get(pos)); // this will Check or Uncheck the
holder.late.setChecked(itemCheckedLate.get(pos)); // this will Check or Uncheck the
// CheckBox in ListView
// according to their original
// position and CheckBox never
// loss his State when you
// Scroll the List Items.
return vi;
}
}
}

Pre-fill the CheckedTextViews in a ListView

Here is my first question on StackOverFlow, I usually always find an answer by myself but I am really stuck on a weird problem that I will explain here:
I implemented a ListView in a fragment activity, this listview contains a list of categories related to the current record that I get from the SQLLite database.
All is working fine, I created a SimpleCursorAdapter to retrieve the data from the DB and I display the categories correctly in the ListView.
The problem is related to the pre-fill of the checkboxes (it is a multiselection list), depending on how I try to pre-check the checkboxes, I get 2 cases:
First, the checkboxes are well pre-checked, but I cannot toggle the checkboxes anymore by clicking them. Second the click toggle well the checkboxes, but they are not pre-checked anymore...
Here is the part of the code where I have the problem:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
//super.onCreate(savedInstanceState);
View v = inflater.inflate(R.layout.rate_fragment, container,false);
dbCategories = "";
displayCategories = resources.getText(R.string.no_categories).toString();
/** INITIALIZATION */
mViewSwitcher = (ViewSwitcher)v.findViewById(R.id.profileSwitcher);
/** Edition view */
rateGroup = (RadioGroup)v.findViewById(R.id.rate_group);
rateOne = (RadioButton)v.findViewById(R.id.one_button);
rateOne.setTag(1);
rateTwo = (RadioButton)v.findViewById(R.id.two_button);
rateTwo.setTag(2);
rateThree = (RadioButton)v.findViewById(R.id.three_button);
rateThree.setTag(3);
rateFour = (RadioButton)v.findViewById(R.id.four_button);
rateFour.setTag(4);
rateFive = (RadioButton)v.findViewById(R.id.five_button);
rateFive.setTag(5);
descET = (EditText)v.findViewById(R.id.editdescription);
descTextSize = descET.getTextSize();
descET.addTextChangedListener(new TextWatcher() {
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
#Override
public void afterTextChanged(Editable s) {
}
});
categoriesTV_edit = (TextView)v.findViewById(R.id.edit_categories);
categoriesBT = (Button) v.findViewById(R.id.select_categories);
categoriesBT.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
View categoriesListTitle = getActivity().getLayoutInflater().inflate(R.layout.category_list_title, null);
AlertDialog.Builder alt_bld = new AlertDialog.Builder(v.getContext()).setCustomTitle(categoriesListTitle);
categories = db.getAllCategoriesByRate(currentRate);
categoriesList = new ListView(getActivity());
categoriesList.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
categoriesList.setClickable(true);
String[] fromColumns = new String[] {
DatabaseHandler.CATEGORY_NAME
};
int[] toViews = new int[]{
R.id.cat_checked
};
//mAdapter = new SimpleCursorAdapter(getActivity(), android.R.layout.simple_list_item_multiple_choice, categories, fromColumns, toViews, 0);
mAdapter = new SimpleCursorAdapter(getActivity(), R.layout.category_item, categories, fromColumns, toViews, 0);
mAdapter.setViewBinder(new ViewBinder() {
public boolean setViewValue(View view, Cursor cursor, int columnIndex) {
if (columnIndex == 1) {
CheckedTextView categRow = (CheckedTextView) view;
String catName = cursor.getString(1);
mAdapter.setViewText((TextView) view, catName);
int catChecked = cursor.getInt(2);
//boolean checkedCat = catChecked==1;
//categoriesList.setItemChecked(cursor.getPosition(),checkedCat);
categRow.setChecked(catChecked==1);
int catID = cursor.getInt(0);
categRow.setTag(catID);
return true;
}
else {
return false;
}
}
});
categoriesList.setAdapter(mAdapter);
alt_bld.setView(categoriesList);
To have one case or another, all depends on these 2 lines:
//boolean checkedCat = catChecked==1;
//categoriesList.setItemChecked(cursor.getPosition(),checkedCat);
If they are commented, the checkboxes are not pre-checked, but the toggle on the clicks is working. But if I comment these lines out, the toggle is not working anymore but the categories are prechecked.
What I also don't understand is that this line is not working:
categRow.setChecked(catChecked==1);
But this one is working well (I succeed to retrieve the tag):
categRow.setTag(catID);
So I hope someone will succeed to explain to me what I do wrong, I guess there is something I misunderstood here...
NOTE: I get 3 columns from the cursor "categories", first one is the ID of the category, second one is the name, and third one is the status: checked or not (1 or 0).
Thanks in advance for your time.
Finally I ended up creating my own custom adapter, this way I could at least understand more easily what was happening.
I had to create actually several multiselect lists, some populated with data from the database, others from the shared preferences.
For this one displaying data from the DB, I created the following adapter (I commented out the lines about the icons because I did not set them up yet):
public class CategoriesLVAdapter extends BaseAdapter {
private Context mContext;
private LayoutInflater mInflater;
private List<Category> categoriesList;
// Constructor
public CategoriesLVAdapter(Context c, List<Category> categories_list){
mContext = c;
mInflater = LayoutInflater.from(c);
categoriesList = categories_list;
}
public List<Category> getCategoriesList(){
return categoriesList;
}
#Override
public int getCount() {
return categoriesList.size();
}
#Override
public Object getItem(int position) {
return categoriesList.get(position);
}
#Override
public long getItemId(int position) {
return categoriesList.get(position).getID();
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder = null;
if (convertView == null) {
convertView = mInflater.inflate(R.layout.categories_list_row, null);
//convertView.setLayoutParams(new ListView.LayoutParams(200, 90));
holder = new ViewHolder();
holder.title = (TextView) convertView.findViewById(R.id.categories_list_row_tv);
//holder.icon = (ImageView) convertView.findViewById(R.id.categories_list_row_iv);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
//holder.icon.setImageResource(categoriesList.get(position).getDrawableID());
//holder.icon.setAdjustViewBounds(true);
//holder.icon.setScaleType(ImageView.ScaleType.CENTER_CROP);
holder.title.setText(categoriesList.get(position).getName());
return convertView;
}
static class ViewHolder {
TextView title;
//ImageView icon;
}
}
In my activity, I use this adapter when the AlertDialog is called to populate the ListView, then I pre-select the categories using the last ones saved in the shared preferences:
private void categoriesFilter(){
AlertDialog.Builder alt_bld = new AlertDialog.Builder(this);
alt_bld.setTitle(resources.getText(R.string.select_categories).toString());
LayoutInflater inflater = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE);
View layout = inflater.inflate(R.layout.categories_list,(ViewGroup) findViewById(R.id.categories_layout_root));
categoriesLV = (ListView) layout.findViewById(R.id.categories_list);
alt_bld.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
String selectedCategoriesString = getSelectedValues(categoriesLV);
//Update the shared preferences
prefs.edit().putString(RateDayApplication.PREF_KEY_CATEGORIES, selectedCategoriesString).commit();
updateFilterDisplay(resources.getText(R.string.cat_title).toString(), selectedCategoriesString, searchedCategoriesTV, "Category");
}
});
alt_bld.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
dialog.cancel();
}
});
String selectedCategoriesString = prefs.getString(RateDayApplication.PREF_KEY_CATEGORIES, new String());
categoriesLV.setAdapter(new CategoriesLVAdapter(this, categoriesList));
String[] selectedCategoriesArray = selectedCategoriesString.split(",");
int categoriesLVLength = categoriesLV.getCount();
for(int i = 0; i < categoriesLVLength; i++){
int categoryID = ((Category) categoriesLV.getItemAtPosition(i)).getID();
if(Arrays.asList(selectedCategoriesArray).contains(String.valueOf(categoryID))){
categoriesLV.setItemChecked(i, true);
}
}
alt_bld.setView(layout);
AlertDialog alert = alt_bld.create();
alert.show();
}
Finally here is the function I call from my database handler to get the list of catagories:
// Getting All Categories By ID desc
public List<Category> getCategoriesList() {
String selectQuery = "SELECT " + CATEGORY_ID + ", " + CATEGORY_NAME + " FROM " + CATEGORY_TABLE + " ORDER BY " + CATEGORY_ID + " ASC";
SQLiteDatabase db = this.getReadableDatabase();
Cursor cursor = db.rawQuery(selectQuery, null);
List<Category> categoriesList = new ArrayList<Category>();//String[] categoriesList = {};
// looping through all rows and adding to list
if (cursor.moveToFirst()) {
do {
Category category = new Category(cursor.getInt(0), cursor.getString(1), false);
categoriesList.add(category);
} while (cursor.moveToNext());
}
cursor.close();
db.close();
return categoriesList;
}
I think my problem before was coming from the fact that the function "setItemChecked" is a little misleading because it does not mean necessarily that anything is checked.
When you use the function "setItemChecked", the item in the list view becomes selected, with or without a checkbox (my rows only contain text views).
The rows selected in my list appear in a different color, and that's enough in my opinion for a simple multi selection list.
The layouts I used are quite simple, "categories_list" contains a ListView in a LinearLayout and "categories_list_row" contains a TextView in a LinearLayout.
Hope it may guide someone!

Android Spinners in ListView, do I have to use a ViewHolder?

I have an issue with Spinners in a ListView. I have a ListView with a CheckBox, a label, and two Spinners. The Spinner are populated from SQLite and that is working fine. I am not using the ViewHolder method because so far when the ListView row is clicked the CheckBoxes are checked or unchecked and the change is immediately saved to the database. When the row is checked the Spinners are made visible but are not visible when the row is not checked.
So the issue that I haven't managed to find a solution for is that I have no idea how to get the actual Spinner or even get the ListItem row that the clicked Spinner is on. The Activity extends ListActivity. Anyone know a way I can do this without using a ViewHolder or do I have to use a ViewHolder?
Here is the code that declares and populates the ListView:
mSsCursor = mDbHelper.fetchAllSsPlaylistSs(mPlId);
startManagingCursor(mSsCursor);
String[] from = new String[]{"pl_selected", BTDbAdapter.KEY_NAME, BTDbAdapter.KEY_NAME2};
int[] to = new int[]{R.id.pl_selected, R.id.name, R.id.name2};
mAllSs = new SimpleCursorAdapter(this, R.layout.pl_edit_ss_row, mSsCursor, from, to);
mAllSs.setViewBinder(new SimpleCursorAdapter.ViewBinder() {
//custom handling of setting the value
public boolean setViewValue(View view, Cursor cursor, int columnIndex) {
if(columnIndex == 3) {
ViewGroup row = (ViewGroup)view.getParent().getParent();
mSId = cursor.getInt(0);
if (cursor.getInt(3) > 0) {
mCheckBox = (CheckBox) row.findViewById(R.id.pl_selected);
mCheckBox.setChecked(true);
mTSpin = (Spinner) row.findViewById(R.id.pl_t_spin);
mMSpin = (Spinner) row.findViewById(R.id.pl_m_spin);
mtvT = (TextView) row.findViewById(R.id.pl_t);
mtvM = (TextView) row.findViewById(R.id.pl_m);
mTSpin.setVisibility(View.VISIBLE);
mtvT.setVisibility(View.VISIBLE);
mMSpin.setVisibility(View.VISIBLE);
mtvM.setVisibility(View.VISIBLE);
//set the values in the t spinner
PopulateTSpinner(cursor.getInt(4));
//set the values in the m spinner
PopulateMSpinner(cursor.getInt(5));
}
else {
mCheckBox = (CheckBox) row.findViewById(R.id.pl_selected);
mCheckBox.setChecked(false);
mTSpin = (Spinner) row.findViewById(R.id.pl_t_spin);
mMSpin = (Spinner) row.findViewById(R.id.pl_m_spin);
mtvT = (TextView) row.findViewById(R.id.pl_t);
mtvM = (TextView) row.findViewById(R.id.pl_m);
mTSpin.setVisibility(View.GONE);
mtvT.setVisibility(View.GONE);
mMSpin.setVisibility(View.GONE);
mtvM.setVisibility(View.GONE);
}
return true;
}
return false;
}
});
setListAdapter(mAllSs);
Thanks.
I don't know if I understood your question: If your app flow is:
show a list of data(CheckBox + TextView(Spinners hidden)) ->
user clicks a row(the Spinners appear for that row with(individual) data) ->
user selects something in those Spinners->
save that selection in the database
then I think you should go with a custom adapter and take care yourself of the row creation + data binding(I don't see how you would set a listener for the Spinners). Below is a small example on how you might do this(although probably not a pretty way of doing it):
public class CustomAdapter extends SimpleCursorAdapter {
private LayoutInflater mInflater;
public CustomAdapter(Context context, int layout, Cursor c,
String[] from, int[] to) {
super(context, layout, c, from, to);
mInflater = LayoutInflater.from(context);
}
#Override
public void bindView(View view, Context context, Cursor cursor) {
ViewHolder holder = (ViewHolder) view.getTag(); // the holder
// pattern
// set the text for the TextView in your row
holder.name
.setText(cursor.getString(cursor.getColumnIndex("name")));
// status of the CheckBox from the database
int status = cursor.getInt(cursor.getColumnIndex("pl_selected"));
// set the CheckBox status
holder.ckb.setChecked((status > 0) ? true : false);
// get the id of this particular row, we'll use this later in the
// Spinner's listeners
long theId = cursor.getLong(cursor.getColumnIndex("_id"));
// see if it is time to show the Spinners
if (status > 0) {
// it is time to show the Spinners. Here you would do stuff
// like: setting up the Spinner's adapters + setting the
// listener
// I used a Spinner with entries set in the xml layout(so my
// selection result is a String)
holder.spin1.setVisibility(View.VISIBLE);
holder.spin2.setVisibility(View.VISIBLE);
// set theId as a tag so you know which Spinner was acted on
holder.spin1.setTag(new Long(theId));
holder.spin1
.setOnItemSelectedListener(new OnItemSelectedListener() {
#Override
public void onItemSelected(AdapterView<?> parent,
View view, int position, long id) {
Long realRowId = (Long) parent.getTag();
// I don't know
ContentValues cv = new ContentValues();
// the column where I saved the spinner selected
// item is called "saved_item"
cv.put("saved_item", (String) parent
.getItemAtPosition(position));
// mDb is my SQLiteDatabase instance
mDb.update("tbl", cv, "_id = ?",
new String[] { String
.valueOf(realRowId) });
// I don't know how you saved the data, the
// above is just an example
}
#Override
public void onNothingSelected(AdapterView<?> parent) {
}
});
// also implement the second Spinner like the first one
} else {
// required to prevent a recycled View from causing damage
holder.spin1.setVisibility(View.GONE);
holder.spin2.setVisibility(View.GONE);
}
}
#Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
View v = mInflater.inflate(R.layout.adapters_listspinner_row,
parent, false);
ViewHolder holder = new ViewHolder();
holder.spin1 = (Spinner) v.findViewById(R.id.spinner1);
holder.spin1.setFocusable(false);
holder.spin2 = (Spinner) v.findViewById(R.id.spinner2);
holder.spin2.setFocusable(false);
holder.name = (TextView) v.findViewById(R.id.textView1);
holder.ckb = (CheckBox) v.findViewById(R.id.checkBox1);
holder.ckb.setFocusable(false);
v.setTag(holder);
return v;
}
class ViewHolder {
Spinner spin1, spin2;
TextView name;
CheckBox ckb;
}
}
Also, the required onListItemcClick method:
#Override
protected void onListItemClick(ListView l, View v, int position, long id) {
// manage the CheckBox state
CheckBox ckb = (CheckBox) v.findViewById(R.id.checkBox1);
ckb.setChecked(!ckb.isChecked());
ContentValues cv = new ContentValues();
cv.put("pl_selected", ckb.isChecked() ? 1 : 0);
mDb.update("tbl", cv, "_id = ?",
new String[] { String.valueOf(id) });
// requery the database so the changes are seen by the adapter, this is horrible!
Cursor re = mDb.query("tbl", null, null, null, null, null, null);
mAllSs.changeCursor(re);
}
As an advice, maybe you could modify the layout of your app and move the Spinners out of the ListView row.

getView not getting called?

I have an adapter that extends simplecursoradapter. The new view is supposed to take a cursor from a database along with an image, populate a list with a couple of checkboxes. For some reason I can't seem to see, my getView is not even being called. I have a breakpoint inside getView and it never gets there and the list just shows up empty.
Can anyone take a look thru and see what I've done wrong
public class TakeStudentAttendance extends ListActivity {
private gradeBookDbAdapter mDbHelper;
private Long mRowId;
private TextView mNameText;
private String classname;
private Boolean new_attendance = false;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Cursor stud;
mDbHelper = new gradeBookDbAdapter(this);
mDbHelper.open();
mRowId = (savedInstanceState == null) ? null
: (Long) savedInstanceState
.getSerializable(gradeBookDbAdapter.KEY_ROWID);
if (mRowId == null) {
Bundle extras = getIntent().getExtras();
mRowId = extras != null ? extras
.getLong(gradeBookDbAdapter.KEY_ROWID) : null;
}
// pull in class data
stud = mDbHelper.fetchClass(mRowId);
startManagingCursor(stud);
classname = stud.getString(
stud.getColumnIndexOrThrow(gradeBookDbAdapter.KEY_CLASSNAME));
String title = "Attendance for " + classname;
setTitle(title);
setContentView(R.layout.attendance_list);
Button doneButton = (Button) findViewById(R.id.Done);
doneButton.setOnClickListener(mAttendanceActivity);
// check previous attendance date
String prevdate = stud.getString(
stud.getColumnIndexOrThrow(gradeBookDbAdapter.KEY_PREVDATE));
stud = mDbHelper.fetchAttendanceByClass(mRowId); // this query yields _id, name,
// attend, late, dtime
if (mDbHelper.getClassDate() == prevdate){
// previous date is the same, so we're doing attendance again: retain values
new_attendance = false;
}
else {
// dates are different, so we're starting from scratch and all students are
// absent until counted present. I just need names and will populate attendance
new_attendance = true;
// upon attendance start-up, NO ONE is present. Set all entries in DB to not present (0)
setNoAttend(stud, mRowId);
// reset cursor position
stud.moveToFirst();
}
// Create an array to specify the fields we want to display in the list
String[] from = new String[]{gradeBookDbAdapter.KEY_NAME,
gradeBookDbAdapter.KEY_ROWID,
gradeBookDbAdapter.KEY_ATTEND,
gradeBookDbAdapter.KEY_LATE,
gradeBookDbAdapter.KEY_DTIME};
// and an array of the fields we want to bind those fields to (in this case just text1)
int[] to = new int[]{R.id.stuname,
R.id.stuIndex,
R.id.attend,
R.id.late,
R.id.stuIndex};
// Now create a simple cursor adapter and set it to display
// mRowId holds the class index.
MyDataAdapter studs =
new MyDataAdapter(this, R.layout.show_attendance, stud, from, to, mRowId, new_attendance);
setListAdapter(studs);
}
Here's my adapter code:
public class MyDataAdapter extends SimpleCursorAdapter {
private Cursor c;
private Context context;
private Long classnum;
private gradeBookDbAdapter mDbHelper;
private Boolean newValues;
private ArrayList<String> list = new ArrayList<String>();
private ArrayList<Boolean> itemCheckedHere = new ArrayList<Boolean>();
private ArrayList<Boolean> itemCheckedLate = new ArrayList<Boolean>();
private ArrayList<Integer> itemCheckedIdx = new ArrayList<Integer>();
int idxCol;
int idx;
// itemChecked will store the position of the checked items.
public MyDataAdapter(Context context, int layout, Cursor c, String[] from,
int[] to, Long mRowId, Boolean new_attendance) {
super(context, layout, c, from, to);
this.c = c;
this.context = context;
mDbHelper = new gradeBookDbAdapter(context);
mDbHelper.open();
classnum = mRowId;
newValues = new_attendance;
c.moveToFirst();
for (int i = 0; i < c.getCount(); i++) {
itemCheckedHere.add(i, false); // initializes all items value with false
itemCheckedLate.add(i, false); // initializes all items value with false
}
}
public View getView(final int pos, View inView, ViewGroup parent) {
File file;
ImageView studentPhoto;
if (inView == null) {
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
inView = inflater.inflate(R.layout.show_attendance, null);
}
// set up name field
final TextView studentName = (TextView) inView.findViewById(R.id.stuname);
final TextView studentIndex = (TextView) inView.findViewById(R.id.stuIndex);
if (studentName != null)
{
c.moveToPosition(pos);
int index = c.getColumnIndex(gradeBookDbAdapter.KEY_NAME);
String name = c.getString(index);
studentName.setText(name);
index = c.getColumnIndex(gradeBookDbAdapter.KEY_STUDENT);
String Index = c.getString(index);
studentIndex.setText(Index);
// set up photo icon
file = new File(Environment.getExternalStorageDirectory () +
"/gradeBook/" + name + ".jpg");
studentPhoto = (ImageView) inView.findViewById(R.id.icon);
if (file.exists()) {
String fileName = file.getAbsolutePath();
BitmapFactory.Options opts = new BitmapFactory.Options();
Bitmap bm;
bm = BitmapFactory.decodeFile(fileName, opts);
studentPhoto.setImageBitmap(bm);
}
else {
// use icon image
studentPhoto.setImageResource(R.drawable.person_icon);
}
}
final CheckBox cBoxH = (CheckBox) inView.findViewById(R.id.attend);
final CheckBox cBoxL = (CheckBox) inView.findViewById(R.id.late);
cBoxH.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
CheckBox cb = (CheckBox) v.findViewById(R.id.attend);
if (cb.isChecked()) {
itemCheckedHere.set(pos, true);
int Index = new Integer(studentIndex.getText().toString());
mDbHelper.insertAttend(Index, classnum, 1 );
} else if (!cb.isChecked()) {
itemCheckedHere.set(pos, false);
int Index = new Integer(studentIndex.getText().toString());
mDbHelper.deleteAttend(Index, classnum );
}
}
});
cBoxL.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
CheckBox cb = (CheckBox) v.findViewById(R.id.late);
if (cb.isChecked()) {
itemCheckedLate.set(pos, true);
// do some operations here
} else if (!cb.isChecked()) {
itemCheckedLate.set(pos, false);
// do some operations here
}
}
});
cBoxH.setChecked(itemCheckedHere.get(pos)); // this will Check or Uncheck the
cBoxL.setChecked(itemCheckedLate.get(pos)); // this will Check or Uncheck the
// CheckBox in ListView
// according to their original
// position and CheckBox never
// loss his State when you
// Scroll the List Items.
return inView;
}
}
This got answered in the comment, but it might as well get a real answer ^^
getCount() is actually returning 0, so the problem is in the query coming back empty, and not in the adapter.
There can be another reason, why getView is never called. In my case I had two elements in LinearLayout - TextView and ListView. The attribute layout_height of TextView was set to fill_parent and ListView element was out of screen bounds because of this. As getView method is called only when ListView item becomes visible to user, so it has never been called. Changing layout_height property to wrap_content solved this problem.
Another thing is to make sure you have called setContentView() with the appropriate argument.

Categories

Resources