I've been struggeling in the past few days trying to figure this out, I hope you can help me...
I have an Activity that shows a list of Players by setting a listadapter like this:
PlayerCursorAdapter playerAdapter = new PlayerCursorAdapter(this,
R.layout.players_row, c, columns, to);
setListAdapter(playerAdapter);
When clicking an item in the list, this code will be executed showing a dialog with an "Edit" and "Delete" option for editing and removing players:
private class OnPlayerItemClickListener implements OnItemClickListener {
public void onItemClick(AdapterView<?> parent, View view, int position,
long rowId) {
Toast.makeText(view.getContext(),
"Clicked Item [" + position + "], rowId [" + rowId + "]",
Toast.LENGTH_SHORT).show();
// Prepare Dialog with "Edit" and "Delete" option
final CharSequence[] choices = {
view.getContext().getString(R.string.buttonEdit),
view.getContext().getString(R.string.buttonDelete) };
AlertDialog.Builder builder = new AlertDialog.Builder(
view.getContext());
builder.setTitle(R.string.title_edit_delete_player);
builder.setItems(choices, new EditOrDeleteDialogOnClickListener(
view, rowId));
AlertDialog alert = builder.create();
// Show Dialog
alert.show();
}
Based on your choice (Edit or delete player), the following listener will be executed:
private class EditOrDeleteDialogOnClickListener implements
DialogInterface.OnClickListener {
private View view;
private long rowId;
public EditOrDeleteDialogOnClickListener(View view, long rowId) {
this.view = view;
this.rowId = rowId;
}
public void onClick(DialogInterface dialog, int item) {
if (item == 0) {
// Edit
showDialog(PlayGameActivity.DIALOG_EDIT_PLAYER_ID);
} else if (item == 1) {
// Delete from database
DatabaseHelper databaseHelper = new DatabaseHelper(
view.getContext());
databaseHelper.deletePlayer(rowId);
// Requery to update view.
((PlayerCursorAdapter) getListAdapter()).getCursor().requery();
Toast.makeText(
view.getContext(),
view.getContext().getString(
R.string.message_player_removed)
+ " " + rowId, Toast.LENGTH_SHORT).show();
}
}
}
The code for the adapter is here:
public class PlayerCursorAdapter extends SimpleCursorAdapter {
private LayoutInflater layoutInflater;
private int layout;
public PlayerCursorAdapter(Context context,
int layout, Cursor c, String[] from, int[] to) {
super(context, layout, c, from, to);
this.layout = layout;
layoutInflater = LayoutInflater.from(context);
}
#Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
Cursor c = getCursor();
View view = layoutInflater.inflate(layout, parent, false);
// Get Data
int nameCol = c.getColumnIndex(Player.COLUMN_PLAYER_NAME);
String name = c.getString(nameCol);
int gamesPlayedCol = c.getColumnIndex(Player.COLUMN_GAMES_PLAYED);
String gamesPlayed = c.getString(gamesPlayedCol);
int gamesWonCol = c.getColumnIndex(Player.COLUMN_GAMES_WON);
String gamesWon = c.getString(gamesWonCol);
// Set data on fields
TextView topText = (TextView) view.findViewById(R.id.topText);
if (name != null)
topText.setText(name);
TextView bottomText = (TextView) view.findViewById(R.id.bottomText);
if (gamesPlayed != null && gamesWon != null)
bottomText.setText(view.getContext().getString(
R.string.info_played_won)
+ gamesPlayed + "/" + gamesWon);
CheckBox checkBox = (CheckBox) view.findViewById(R.id.checkBox);
// Set up PlayerViewHolder
PlayerViewHolder playerViewHolder = new PlayerViewHolder();
playerViewHolder.playerName = name;
playerViewHolder.gamesPlayed = gamesPlayed;
playerViewHolder.gamesWon = gamesWon;
playerViewHolder.isChecked = checkBox.isChecked();
view.setTag(playerViewHolder);
return view;
}
private class PlayerViewHolder {
String playerName;
String gamesPlayed;
String gamesWon;
boolean isChecked;
}
#Override
public void bindView(View view, Context context, Cursor c) {
PlayerViewHolder playerViewHolder = (PlayerViewHolder) view.getTag();
TextView topText = (TextView) view.findViewById(R.id.topText);
topText.setText(playerViewHolder.playerName);
TextView bottomText = (TextView) view.findViewById(R.id.bottomText);
bottomText.setText(view.getContext()
.getString(R.string.info_played_won)
+ playerViewHolder.gamesPlayed
+ "/"
+ playerViewHolder.gamesWon);
CheckBox checkBox = (CheckBox) view.findViewById(R.id.checkBox);
checkBox.setChecked(playerViewHolder.isChecked);
}
}
Now, the problem is that after removing a few of the players in the list, the list gets screwed up, eg. it shows something different than what is actually available.
I've experimented a little and if I stop using the PlayerViewHolder in bindView and instead read the text from the cursor and assign it directly to the text fields, then it works.... So question is, why is my ViewHolder screwing up things???
Any help will be greatly appreciated!
Thanks!
Zyb3r
Found a solution...
Basically I reinitialize the Cursor and ListAdapter plus assigns the ListAdapter to the ListView all over again when I change the data in the database.
I'm not entirely sure why this is nessasary, but notifyDataSetChanged(), notifyDataSetInvalidated() and all the other things I tried didn't work, so now I'm using this approach. :o)
Zyb3r
Related
I read some posts and found that reQuery() is deprecated and some suggested using SwapCursor() or ChangeCursor().
I have a Favorite button on whose click I update DB and change color of the Button. When I scroll and come back to particular view(and Button) color is reset.
I know it is because view is recycled. I have a condition based on a DB column value to set the color of the Button.
I want view to get updated values from DB after I press the Button. For which I have to refresh/requery Cursor/DB.
How do I do that with CursorAdapter keeping in mind that my min. API is 19?
UPDATE
CursorAdapter code:
public class ToDoCursorAdapter extends CursorAdapter {
SparseBooleanArray selectionArrayAr = new SparseBooleanArray();
SparseBooleanArray selectionArrayRef = new SparseBooleanArray();
SparseBooleanArray selectionArrayFav = new SparseBooleanArray();
//Boolean isSet = false;
private MainButtons_Interface mAdapterCallback;
public ToDoCursorAdapter(Context context, Cursor cursor) {
super(context, cursor, 0);
}
#Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
ViewHolderItem viewHolder = new ViewHolderItem();
View rowView = LayoutInflater.from(context).inflate(R.layout.listview, parent, false);
viewHolder.engTextV = (TextView) rowView.findViewById(R.id.engText);
viewHolder.arTextV = (TextView) rowView.findViewById(R.id.arabText);
viewHolder.buttonIAV = (Button) rowView.findViewById(R.id.buttonIA); //For Arabic Text
viewHolder.refTextV = (TextView) rowView.findViewById(R.id.refText);
viewHolder.buttonIRV = (Button) rowView.findViewById(R.id.buttonIR); //For Ref Text
viewHolder.buttonIFV = (ImageButton) rowView.findViewById(R.id.buttonF);
rowView.setTag(viewHolder);
return rowView;
}
#Override
public void bindView(final View view, final Context context, final Cursor cursor) {
final ViewHolderItem viewHolder = (ViewHolderItem) view.getTag();
String arabic = cursor.getString(cursor.getColumnIndexOrThrow("PlainArab_Text")).trim().replaceAll("[\n]{2,}", "TWOFEEDS").replaceAll("\n", " ").replaceAll(" +", " ").replaceAll("<br/>", "\n").replaceAll("TWOFEEDS", "\n") + "\n";
String english = cursor.getString(cursor.getColumnIndexOrThrow("PlainEng_Text")).trim().replaceAll("[\n]{2,}", "TWOFEEDS").replaceAll("\n", " ").replaceAll(" +", " ").replaceAll("<br/>", "\n").replaceAll("TWOFEEDS", "\n") + "\n";
String ref = cursor.getString(cursor.getColumnIndexOrThrow("REF")).trim().replaceAll("<br/> <br/>", " ").replaceAll("<br/>", "\n");
final Integer HadithID = cursor.getInt(cursor.getColumnIndexOrThrow("ID"));
final Integer IsFav = cursor.getInt(cursor.getColumnIndexOrThrow("IsFavorite"));
viewHolder.arTextV.setText(arabic);
viewHolder.engTextV.setText(english);
viewHolder.refTextV.setText(ref);
final int position = cursor.getPosition();
boolean isSelectedA = selectionArrayAr.get(position);
boolean isSelectedR = selectionArrayRef.get(position);
boolean isSelectedF = selectionArrayFav.get(position);
if (isSelectedA) {
viewHolder.arTextV.setVisibility(view.GONE);
viewHolder.buttonIAV.setText("Show Arabic Version");
} else if (!isSelectedA){
viewHolder.arTextV.setVisibility(view.VISIBLE);
viewHolder.buttonIAV.setText("Hide Arabic Version");
}
if (isSelectedR) {
viewHolder.refTextV.setVisibility(view.GONE);
viewHolder.buttonIRV.setText("Show Refrence");
} else if (!isSelectedR){
viewHolder.refTextV.setVisibility(view.VISIBLE);
viewHolder.buttonIRV.setText("Hide Refrence");
}
//boolean isSelectedF = selectionArrayFav.get(position);
if(isSelectedF) {
viewHolder.buttonIFV.setImageResource(R.drawable.favoritebutton_afterclick);
} else if (!isSelectedF){
viewHolder.buttonIFV.setImageResource(R.drawable.favoritebutton);
}
//Arabic Button
viewHolder.buttonIAV.setOnClickListener(
new View.OnClickListener()
{ #Override
public void onClick(View v) {
boolean isSelectedAc = selectionArrayAr.get(position);
if(!isSelectedAc) {
viewHolder.arTextV.setVisibility(v.GONE);
viewHolder.buttonIAV.setText("Show Arabic Version");
setSelectedAr(position, true);
} else if (isSelectedAc){
viewHolder.arTextV.setVisibility(v.VISIBLE);
setSelectedAr(position, false);
viewHolder.buttonIAV.setText("Hide Arabic version");
}
}
}
);
//Ref Button
viewHolder.buttonIRV.setOnClickListener(
new View.OnClickListener()
{ #Override
public void onClick(View v) {
boolean isSelectedRc = selectionArrayRef.get(position);
if(!isSelectedRc) {
viewHolder.refTextV.setVisibility(v.GONE);
viewHolder.buttonIRV.setText("Show Reference");
setSelectedRef(position, true);
} else if (isSelectedRc){
viewHolder.refTextV.setVisibility(v.VISIBLE);
setSelectedRef(position, false);
viewHolder.buttonIRV.setText("Hide Reference");
}
}
}
);
//Fav Button
viewHolder.buttonIFV.setOnClickListener(
new View.OnClickListener()
{ #Override
public void onClick(View v) {
boolean isSelectedF = selectionArrayFav.get(position);
boolean IsSet = ((ListViewActivity) context).addRemFav(HadithID);
String mess ="";
if(IsSet){
mess = "Hadith add to Favorite list";
} else if(!IsSet){
mess = "Hadith removed from Favorite list";
}
if(!isSelectedF) {
viewHolder.buttonIFV.setImageResource(R.drawable.favoritebutton_afterclick);
setSelectedF(position, true);
} else if (isSelectedF){
viewHolder.buttonIFV.setImageResource(R.drawable.favoritebutton);
setSelectedF(position, false);
}
Toast.makeText(v.getContext(), mess, Toast.LENGTH_SHORT).show();
}
}
);
}
// our ViewHolder.
static class ViewHolderItem {
TextView engTextV;
TextView arTextV;
TextView refTextV;
Button buttonIAV;
Button buttonIRV;
ImageButton buttonIFV;
}
// Method to mark items in selection
public void setSelectedAr(int position, boolean isSelected) {
selectionArrayAr.put(position, isSelected);
}
public void setSelectedRef(int position, boolean isSelected) {
selectionArrayRef.put(position, isSelected);
}
public void setSelectedF(int position, boolean isSelected) {
selectionArrayFav.put(position, isSelected);
}
UPDATE
I added this logic to my function which was called on clicking the Button.
Cursor todoCursor1 = hadDB.rawQuery("SELECT ID as _id, * FROM HAD_TABLE WHERE ID < 7001 ", null);
todoAdapter.changeCursor(todoCursor1);
Basically, you just need to requery DB so that you get updated records/Data and then change your current cursor with new one, todoCursor1 is my case above.
Also, changeCursor() will close your current cursor, in case you would want to go back to old cursor you should use swapCursor() instead as it will return you old cursor.
Now my only thing I want to know is, if this will work for APIs 19 and up.
I added this logic to my function which was called on clicking the Button.
Cursor todoCursor1 = hadDB.rawQuery("SELECT ID as _id, * FROM HAD_TABLE WHERE ID < 7001 ", null);
todoAdapter.changeCursor(todoCursor1);
Basically, you just need to requery DB so that you get updated records/Data and then change your current cursor with new one, todoCursor1 is my case above.
Also, changeCursor() will close your current cursor, in case you would want to go back to old cursor you should use swapCursor() instead as it will return you old cursor.
Ok, so I'm trying to delete elements from a ListView, and everything goes alright until I try to delete the last element, but only if I delete the second last element and the try to delete the last one. Here's my code:
public class TestActivity extends ListActivity {
ListView list;
PAdapter adapter;
static SQLiteDatabase db;
static ArrayList<Profesor> datos;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test);
db = openOrCreateDatabase("DBLogin", MODE_PRIVATE, null);
db.execSQL("CREATE TABLE IF NOT EXISTS Profesor (Id integer primary key AUTOINCREMENT"
+ ", Nombre" + " varchar(30), Imagen varchar(15), Fecha" + " varchar(15)" +
", Direccion varchar(35), sexo varchar(10), Telefono varchar(15), creado int);");
list = (ListView) findViewById(android.R.id.list);
datos = new ArrayList<Profesor>();
datos = datos();
adapter = new PAdapter(this, R.layout.row, datos);
setListAdapter(adapter);
list.setOnItemLongClickListener(new OnItemLongClickListener(){
#Override
public boolean onItemLongClick(AdapterView<?> arg0, View arg1,
int arg2, long arg3) {
if (datos.get(arg2).getCreado() == 1) {
PopupMenu popup = new PopupMenu(TestActivity.this, list);
popup.getMenuInflater().inflate(R.menu.popup3, popup.getMenu());
final int id = arg2;
popup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
public boolean onMenuItemClick(MenuItem item) {
delete(datos.get((int)adapter.getItemId(id)));
datos = datos();
adapter = new PAdapter(TestActivity.this, R.layout.row, datos);
setListAdapter(adapter);
list.invalidateViews();
return true;
}
});
popup.show();
}
return false;
}
});
}
private ArrayList<Profesor> datos(){
ArrayList<Profesor> ap = new ArrayList<Profesor>();
Cursor cursor = db.rawQuery("SELECT * FROM Profesor", null);
if(cursor.moveToFirst()){
do {
Profesor p = new Profesor(null, null);
p.setId(cursor.getInt(0));
p.setNombre(cursor.getString(1));
p.setFecha(cursor.getString(3));
p.setDireccion(cursor.getString(4));
p.setSexo(cursor.getString(5));
p.setImagen(cursor.getString(2));
p.setCreado(cursor.getInt(7));
p.setTelefono(cursor.getString(6));
ap.add(p);
} while(cursor.moveToNext());
}
return ap;
}
public static void delete(Profesor p){
db.execSQL("DELETE FROM Profesor WHERE Id = " + p.getId() + ";");
}
Here is the class PAdapter:
public class PAdapter extends ArrayAdapter<Profesor> {
private Context context;
private int layout;
private ArrayList<Profesor> datos;
public PAdapter(Context context, int layout, ArrayList<Profesor> datos) {
super(context, layout, datos);
this.context = context;
this.layout = layout;
this.datos = datos;
}
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View item = inflater.inflate(layout, parent, false);
ImageView imagen = (ImageView) item.findViewById(R.id.imageView1);
datos.get(position).imagen(imagen, context, false);
TextView nombre = (TextView) item.findViewById(R.id.tNombre);
nombre.setText(datos.get(position).getNombre());
return item;
}
}
Funny thing is, it executes the code following the delete but doesn't delete the last element, neither does it throw me an exception. And again, it only happens with the last element, and only after I delete the one before it, if I close and reopen the app afterwards I can delete it normally.
I assumed you passed pos = 3 as parameter value. Because the size of list is 3, last element's position should be 2.
*EDIT:
Remember, start index of listview and adapter is different. The ListView item pos starts from "1" as first position, adapter (such as array) starts from index "0" as first position.
adapter.remove(adapter.getItem(pos-1));
You have some mistakes in your code. My following suggestion dont promise will solve your current problem, but lets try it :
Pay attention when you setting the adapter setListAdapter(adapter);, the list will set its adapter each time user did onClick - which is a waste.Use adapter.add()/adapter.remove() instead of reset all data by doing setListAdapter again and again.
You called list.invalidateViews(), for what? In your case, adapter.notifyDataSetChanged() is enough.
Try this:It's working fine for me.
ListView list;
adapter = new MyListAdapter(this);
list = (ListView) findViewById(android.R.id.list);
list.setAdapter(adapter);
list.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView<?> a, View v, int position, long id) {
AlertDialog.Builder adb=new AlertDialog.Builder(MyActivity.this);
adb.setTitle("Delete?");
adb.setMessage("Are you sure you want to delete " + position);
final int positionToRemove = position;
adb.setNegativeButton("Cancel", null);
adb.setPositiveButton("Ok", new AlertDialog.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
MyDataObject.remove(positionToRemove);
adapter.notifyDataSetChanged();
}});
adb.show();
}
});
I solved it by Adding this in the activity of the single item so if i get back to the ListView Activity it is refreshed because of finish(); function.[ 8 feb 2020]
#Override
public void onBackPressed() {
super.onBackPressed();
startActivity(new Intent(SingleItem.this, ListView.class));
finish();
}
I have a SimpleCursorAdapter class, it gets various data from DB and displays in ListView. It implements an onclicklistener that sends a messageGuid String to another activity. All this works fine.
In the row of the ListView i have added a CheckBox and set an onCheckChangeListener to it. At the moment when the checkbox is checked, the messageGuid is always the last one in the cursor.
I need to find a way to get the listview row id of the row which hold the checkbox that has been checked. I can then get the correct cursor row and then in turn the correct messageGuid.
I've commented what i would like within the onCheckedChanged method.
Thanks in advance Matt.
private class MyAdapter extends SimpleCursorAdapter implements OnItemClickListener {
Cursor c;
String messageGuid;
public MyAdapter(Context context, int layout, Cursor c, String[] from,
int[] to) {
super(context, layout, c, from, to);
}
#Override
public
View getView(int position, View convertView, ViewGroup parent) {
Log.e(TAG, "inside myadapter getview for messages");
View v = super.getView(position, convertView, parent);
if(v == null)
return null;
c = (Cursor)getItem(position);
Log.e(TAG, "(Cursor)getItem(position) = " + c + "position = " + position);
v.setTag(c);
//other code removed, not relevant
String messageSender = c.getString(c.getColumnIndex(LoginValidate.C_MESSAGE_SENDER));
String isRepliedTo = c.getString(c.getColumnIndex(LoginValidate.C_MESSAGE_REPLIED));
String isStandAlone = c.getString(c.getColumnIndex(LoginValidate.C_MESSAGE_IS_STANDALONE));
((TextView)v.findViewById(R.id.messagecreatedat)).setText(formattedMessCreatedAt );
((TextView)v.findViewById(R.id.messagetext)).setText(messageText);
((TextView)v.findViewById(R.id.messagesender)).setText(messageSender);
//#003F87 = blue
((TextView)v.findViewById(R.id.messagecreatedat)).setTextColor(Color.parseColor("#003F87"));
((TextView)v.findViewById(R.id.messagesender)).setTextColor(Color.parseColor("#003F87"));
((TextView)v.findViewById(R.id.messagetext)).setTextColor(Color.parseColor("#FF0000"));
CheckBox cb = ((CheckBox)v.findViewById(R.id.list_checkbox));
cb.setOnCheckedChangeListener(new OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
//i'd like to something like below where i can specify the row which contains
//the checkbox that has been check and map that to the row in the cursor.
// So if the checkbox in the 2nd row in the listview has been clicked then the messageGuid from the 2nd row in the cursor is found
//c.moveToPosition(the row position of the listview which holds the checkbox that has been clicked );
messageGuid = null;
messageGuid = c.getString(c.getColumnIndex(LoginValidate.C_MESSAGE_GUID));
if(isChecked == true){
Log.e(TAG, "checkBox true and guid = " + messageGuid);
}else{
Log.e(TAG, "checkBox false and guid = " + messageGuid);
}
}
});
return v;
}
#Override
public void onItemClick(AdapterView<?> parent, View view, int pos,
long id) {
Cursor itemCursor = (Cursor) view.getTag();
String messageGuid = itemCursor.getString(itemCursor.getColumnIndex(LoginValidate.C_MESSAGE_GUID));
String messageText = itemCursor.getString(itemCursor.getColumnIndex(LoginValidate.C_MESSAGE_TEXT));
String messageCreatedAt = itemCursor.getString(itemCursor.getColumnIndex(LoginValidate.C_MESSAGE_CREATED_AT));
String messageSender = itemCursor.getString(itemCursor.getColumnIndex(LoginValidate.C_MESSAGE_SENDER));
String messageReplied = itemCursor.getString(itemCursor.getColumnIndex(LoginValidate.C_MESSAGE_REPLIED));
String messageSeen = itemCursor.getString(itemCursor.getColumnIndex(LoginValidate.C_MESSAGE_SEEN));
String isStandAlone = itemCursor.getString(itemCursor.getColumnIndex(LoginValidate.C_MESSAGE_IS_STANDALONE));
Intent i = new Intent(ViewMessagesActivity.this, ReplyToMessageActivity.class);
i.putExtra("guid", messageGuid);
i.putExtra("message", messageText);
i.putExtra("createdat", messageCreatedAt);
i.putExtra("sender", messageSender);
i.putExtra("messagereplied", messageReplied);
i.putExtra("messageseen", messageSeen);
i.putExtra("isstandalone", isStandAlone);
startActivity(i);
}
}// end of adapter
Make position final and use that on onCheckedChanged
or
make cb final
Add before cb.setOnCheckedChangeListener
cb.setTag(position);
And in public void onCheckedChanged you can retrieve the position
int pos = (Integer) cb.getTag();
I have a custom SimpleCursorAdapter and a list view. Each row of the list have a name and a button. When I press the button for each name, a dialog appears with a description.
Inside the custom SimpleCursorAdapter I set the onclick method for the button. When I have a large list, my listView gets a scroll bar. And I dont know why, when I scroll down, the last rows of my list doesnt show the correct description for each row. This is my code:
public class listServicesCursorAdapter extends SimpleCursorAdapter{
private Context context;
private int layout;
private String[] from;
private int[] to;
public listServicesCursorAdapter (Context context, int layout, Cursor c,
String[] from, int[] to, int flags) {
super(context, layout, c, from, to, flags);
this.context = context;
this.layout = layout;
this.from = from;
this.to = to;
}
#Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
final LayoutInflater inflater = LayoutInflater.from(context);
View v = inflater.inflate(layout, parent, false);
//Column of BD that we want to recover
String column = null;
//Index of the column of DB
int nameCol = 0;
//Result of obtain the index of the column of DB
String nombre = null;
//Name of the textView in the Layout where we want to show the result
TextView name_text= null;
String description = null;
String nameService = null;
//For each value of DB, we show it in the text view.
for (int i=0; i<from.length; i++){
column= from[i];
nameCol = cursor.getColumnIndex(column);
name = cursor.getString(nameCol);
//the values to[i] equals to 0 indicates values that we need but
//that we are not showing in the list directly
//0 -> description
if(to[i] == 0){
description = name;
}else{
nameService = name;
name_text = (TextView) v.findViewById(to[i]);
if (name_text != null) {
name_text.setText(name);
}
}
}
ImageButton buttonDescription = (ImageButton) v.findViewById(R.id.imageButtonDescription);
//we store in a bundle the name and description of the service, so we can use it in
// the setOnClickListener method.
final Bundle mArguments = new Bundle();
mArguments.putString("name", nameService);
mArguments.putString("description", description);
buttonDescription .setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v){
AlertDialog.Builder builder = new AlertDialog.Builder(v.getContext());
builder.setMessage(mArguments.getString("description"))
.setTitle(mArguments.getString("name"))
.setCancelable(false)
.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
dialog.cancel();
}
});
AlertDialog alert = builder.create();
alert.show();
}});
return v;
}
}
This is where I call the adapter:
ServiceSqliteDao serviceDao = new ServiceSqliteDao();
//get the services for DB
Cursor mCursorServices = serviceDao.listServices(getActivity());
if(mCursorServices.getCount()>0){
//indicate the fields we want to show (from) and where (to)
String[] from = new String[] { "name", "description"};
int[] to = new int[] { R.id.checkBoxService,0};
ListView lvServices = (ListView) v.findViewById (R.id.listViewServices);
ListServicesCursorAdapter notes = new ListServicesCursorAdapter (getActivity(), R.layout.activity_file_service, mCursorServices, from, to, 0);
lvServices.setAdapter(notes);
Why do I get this behavior?. I get all the names in the list right but when I press the button in horizontal way (I mean a put the tablet horizontally) and get the scroll bar in my list, I dont get the right description. By the other hand, if I use the tablet vertically, I dont get the scroll bar in my list and I get the right description in each button.
This is my layout:
<ListView
android:id="#+id/listViewServices"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1" >
</ListView>
SOLUTION:
newView should look like this:
#Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
final LayoutInflater inflater = LayoutInflater.from(context);
View v = inflater.inflate(layout, parent, false);
return v;
}
and bindView should look like this:
#Override
public View bindView(View v, Context context, Cursor cursor) {
//Column of BD that we want to recover
String column = null;
//Index of the column of DB
int nameCol = 0;
//Result of obtain the index of the column of DB
String nombre = null;
//Name of the textView in the Layout where we want to show the result
TextView name_text= null;
String description = null;
String nameService = null;
//For each value of DB, we show it in the text view.
for (int i=0; i<from.length; i++){
column= from[i];
nameCol = cursor.getColumnIndex(column);
name = cursor.getString(nameCol);
//the values to[i] equals to 0 indicates values that we need but
//that we are not showing in the list directly
//0 -> description
if(to[i] == 0){
description = name;
}else{
nameService = name;
name_text = (TextView) v.findViewById(to[i]);
if (name_text != null) {
name_text.setText(name);
}
}
}
/********************************NEW CODE ************************************/
String uniMedition = cursor.getString(cursor.getColumnIndex("unitMedition"));
if(uniMedition.equals("none")){
EditText etMedida = (EditText) v.findViewById(R.id.editTextMedida);
etMedida.setVisibility(View.INVISIBLE);
TextView tvUniMedition = (TextView) v.findViewById(R.id.textViewUniMedition);
tvUniMedition .setVisibility(View.INVISIBLE);
}else{
EditText etMedida = (EditText) v.findViewById(R.id.editTextMedida);
etMedida.setVisibility(View.VISIBLE);
TextView tvUniMedition = (TextView) v.findViewById(R.id.textViewUniMedition);
tvUniMedition .setVisibility(View.VISIBLE);
tvUniMedition .setText(uniMedition);
}
/********************************END NEW CODE ************************************/
ImageButton buttonDescription = (ImageButton) v.findViewById(R.id.imageButtonDescription);
//we store in a bundle the name and description of the service, so we can use it in
// the setOnClickListener method.
final Bundle mArguments = new Bundle();
mArguments.putString("name", nameService);
mArguments.putString("description", description);
buttonDescription .setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v){
AlertDialog.Builder builder = new AlertDialog.Builder(v.getContext());
builder.setMessage(mArguments.getString("description"))
.setTitle(mArguments.getString("name"))
.setCancelable(false)
.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
dialog.cancel();
}
});
AlertDialog alert = builder.create();
alert.show();
}});
}
}
Now everything works fine!.
Why do I get this behavior?. I get all the names in the list right but
when I press the button in horizontal way (I mean a put the tablet
horizontally) and get the scroll bar in my list, I dont get the right
description.
When your ListView doesn't have space to show all of the rows it will recycle the row view for performance reasons. The problem is that in your SimpleCursorAdapter you override the newView() method which will be called only when the ListView doesn't have a recycled view. Override bindView() to do the work as that method is called for each row, in the newView() method just inflate/build the row layout.
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!