Adding data to a listView using custom CursorAdapter - android

Hi I want to achieve the following result in my ListActivity:
First item, descritpion
Second item, description
...
where Name and description come from
Cursor c = db.rawQuery(...);
I used a SimpleCursorAdapter and I had no problems. Then I decided to make some modification to data that I have in cursor before displaying it. I wanted to have a internal counter that would increment every time cursor adapter dislays a new view. That's why I decided to implement my own CustomCursorAdapter extending SimpleCursorAdapter:
public class TrainingsListCursorAdapter extends SimpleCursorAdapter{
private Context context;
private int layout;
int list_item_order_number = 1;
public TrainingsListCursorAdapter(Context context, int layout, Cursor c,
String[] from, int[] to) {
super(context, layout, c, from, to);
this.context = context;
this.layout = layout;
}//contructor
#Override
public View newView(Context context, Cursor cursor, ViewGroup parent){
Cursor c = getCursor();
final LayoutInflater inflater = LayoutInflater.from(context);
View v = inflater.inflate(layout, parent, false);
String durationCol = c.getString(c.getColumnIndex("duration"));
if(durationCol != null){
durationCol = minutesForSeconds(durationCol);
}
TextView textViewDuration = (TextView) v.findViewById(R.id.duration);
TextView order_number = (TextView) v.findViewById(R.id.list_item_num);
if(order_number != null){
order_number.setText(String.valueOf(list_item_order_number));
}
if(textViewDuration != null){
textViewDuration.setText(durationCol);
}
list_item_order_number++;
return v;
}
I have a member variable _list_item_order_number_ that is incremented by one every time a view/row is drawn (by calling newView() method). This number is displayed in every view/list item and it corresponds to list item order...
The problem I have is that when I'm rotating the screen this number doesn't correspond to list items anymore. For example my 3rd item has value 1 and so on...
I guess this has something to do with the order Android is drawing the views. If I scroll the list to, let's say, the middle and then rotate, these numbers are all mixed like this:
First Item
Second item
Third item

Related

Android: Display Multiple Pieces of Cursor Data Together in TextViews instead of a ListView

I am able to accomplish pulling a random row of different column indexes and populate a ListView in my Main Activity with the data using a custom ArrayAdapter (List<String>). I want to take that same data and use it to populate a single textview (or LinearLayout containing two TextViews) in the Main Activity. That TextView(s) would be in this format:
String Int:Int
Entry
BookName Chapter#:Entry#
Entry
I have the following code to pull my random information from my SQLite Database and it works:
public List<String> getEntry() {
List<String> list = new ArrayList<>();
Cursor cursor = database.rawQuery("SELECT * FROM bookdatabase ORDER BY RANDOM() LIMIT 1", null);
cursor.moveToFirst();
while (cursor != null && cursor.getCount() > 0 & !cursor.isAfterLast()) {
list.add(cursor.getString(3));
list.add(cursor.getString(4));
list.add(cursor.getString(5));
list.add(cursor.getString(6));
cursor.moveToNext();
}
cursor.close();
return list;
}
Here is my custom adapter that works to show the data in a ListView:
public EntryAdapter(Context context, int resource1, List<String> entries) {
super(context, resource1, entries);
mContext = context;
mResource1 = resource1;
mEntries = entries;
}
#NonNull
#Override
public View getView(int position, #Nullable View convertView, #NonNull ViewGroup parent) {
View listItem = convertView;
if (listItem == null) {
listItem = LayoutInflater.from(mContext).inflate(mResource1, parent, false);
}
TextView entryTextView = (TextView) listItem.findViewById(R.id.bookName);
entryTextView.setText(mEntries.get(position));
return listItem;
}
Here is where I am trying access it from my main activity to populate a TextView which currently works to show it in a ListView:
databaseAccess.open();
mEntry = databaseAccess.getEntry();
databaseAccess.close();
mEntryAdapter = new EntryAdapter(this,
R.layout.entry_item, mEntry);
this.mEntryListView.setAdapter(mEntryAdapter);
Thank you, in advance.
After much research, I solved my problem. I ended up using the information contained in one post on stack over flow and another on GitHub; both about CursorAdapters. Bottom line, I created a cursor adapter instead of an array adapter and it woks perfectly. The posts are here in case anyone encounters this same problem:
Cursor adapter and sqlite example
https://github.com/codepath/android_guides/wiki/Populating-a-ListView-with-a-CursorAdapter

Android: Custom CursorAdapter to alternate resources

This problem has been stuck for a while in my head.
What I need to do:
Show a listview with alternating resources for the items in the listView.
What is my problem:
So far I can alternate resources and show no data, or show the data but not alternate resources. The first item works well every time, but not form there onwards. I think I'm very close but I just can't think what is going wrong...
What have I done:
I have used a custom simple cursor adapter.
Where is the code:
public class DialogCursor extends SimpleCursorAdapter {
private LinearLayout wrapper;
private TextView burbuja;
public DialogCursor(Context context, int layout, Cursor c, String[] from,
int[] to, int flags) {
super(context, layout, c, from, to, flags);
// TODO Auto-generated constructor stub
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View row = convertView;
if (row == null) {
Context context = parent.getContext();
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
row = inflater.inflate(R.layout.dialogo_row, parent, false);
}
burbuja = (TextView) row.findViewById(R.id.idiomaselec);
wrapper = (LinearLayout) row.findViewById(R.id.wrapper);
//get reference to the row
View view = super.getView(position, convertView, parent);
Log.d("Dialogo","enters getview");
Log.d("Dialogo",Integer.toString(position));
//check for odd or even to set alternate colors to the row background
if(position % 2 == 0){
Log.d("Dialogo","Even");
burbuja.setBackgroundResource(R.drawable.bubble_green);
wrapper.setGravity(Gravity.LEFT);
}
else {
Log.d("Dialogo","not even");
burbuja.setBackgroundResource(R.drawable.bubble_yellow);
wrapper.setGravity(Gravity.RIGHT);
}
return row;
}
}
The cursor adapter is called from this other class (just showing relevant part)
String[] from = new String[] { DialogoTable.TABLE_DIALOGO + "." + columna };
// Fields on the UI to which we map
final int[] to = new int[] { R.id.idiomaselec};
Log.d("Dialogo","entra en fillData2");
getLoaderManager().initLoader(0, null, this);
if (bot) {
Log.d("Dialogo","entra en fillData2.5");
getLoaderManager().restartLoader(0, null, this);
}
adapter2 = new DialogCursor(this, R.layout.dialogo_row, null, from, to, 0);
setListAdapter(adapter2);
And the output:
If I return row (last line of code)
I get the background resources in the right place but with no data
If I return view (last line of code)
I get the data but only the first item has the right background resources.
One last note:
I have followed this example
http://adilsoomro.blogspot.com/2012/12/android-listview-with-speech-bubble.html
but I dont want to create a class message since I wnat the data from my DB.
Thank you for your help :)
In a similar case I was able to have a custom cursorAdapter alternate resources based on the cursor position. I put the following code in my bindView where entryView is the passed in view. I am overriding getView at all.
if(cursor.getPosition()%2 == 1){
entryView.findViewById(R.id.title_relative).setBackgroundColor(getResources().getColor(R.color.orange));
}else{
entryView.findViewById(R.id.title_relative).setBackgroundColor(getResources().getColor(R.color.blue));
}

null cursor in custom adapter?

I'm having an issue that I just can't seem to trace down the cause of. This may be simply due to my lack of familiarity with loaders...
I have a custom adapter I use to set a prompt for a spinner in the "closed" position (single line display) until the first selection is made. I've used this before with great success, but this time it's not working. The only difference is that now I'm using loaders.
When the adapter tries to access the cursor in my overridden getView method, the cursor is null and of course I get a force close with a null pointer exception. I don't understand how the cursor can be null there as obviously the getDropDownView method (which I don't override) has access to the cursor as the dropdown is populated...
All I can think is that for some reason the getView method is retaining the original null that is passed in as a placeholder while the loader does it's work. I would think that when I use changeCursor that reference would change as well, but it seems that it isn't.
main activity adapter call
adapter = new CursorAdapter_SpinnerPrompt(this,
R.layout.rowlayout_black, null, new String[] { ThreadMillDB.THREADMILL_THREAD }, new int[] { R.id.ListItem });
mThreadChooser.setAdapter(adapter);
relevant loader code
#Override
public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
adapter.changeCursor(cursor);
}
adapter code
public class CursorAdapter_SpinnerPrompt extends SimpleCursorAdapter {
private Context context;
private int layout;
private Cursor c;
private String[] from;
private int[] to;
public static boolean spinnerFlag = false;
public CursorAdapter_SpinnerPrompt(Context context, int layout, Cursor c,
String[] from, int[] to) {
super(context, layout, c, from, to);
this.context = context;
this.layout = layout;
this.c = c;
this.from = from;
this.to = to;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null)
convertView = View.inflate(context, layout, null);
if (spinnerFlag != false) {
c.moveToPosition(position); // cursor is null here... why? How to fix?
TextView tv = (TextView) convertView;
tv.setText(c.getString(c.getColumnIndex(ThreadMillDB.THREADMILL_THREAD)));
} else {
TextView tv = (TextView) convertView;
tv.setText("Choose a thread");
tv.setTextColor(Color.parseColor("#778899"));
}
return convertView;
}
}
UPDATE
And of course in typing this out I figured out a solution. I moved the creation of the adapter out of my activity onCreate and into onLoadFinished and put the cursor into the call. However, this seems messier than the way I was trying to do it. Is there any modification I can make to my original methods (shown above) to make it work without having to move the adapter instantiation to the onLoadFinished method?
your suspicious is correct.
The cursor reference you remembered on your constructor is not the same that you passed on chageCursor(Cursor c).
The proper way to get the cursor on a CursorAdapter is calling getCursor() than you'll get the reference to the cursor you passed on changeCursor(Cursor c).

Multiple List Views?

I'm trying to display high scores for a game I'm creating, with two columns, one for their name, and the other for the amount of moves it took them to complete the game.
Currently it is all stored in a SQLiteDatabase and presented in a list view, where it appears as one column in the format
name,moves
But I'd like to get the moves on the opposite of the screen, would this require multiple list views or would it require editing of the one list view, or its adapter?
The code currently used is:
datasource = new HighScoreDataSource(this);
datasource.open(); //Open the connection
List<HighScore> values = datasource.getAllHighScores(); //Retrieve all the data
//Using a simple cursor adapted to show the elements
ArrayAdapter<HighScore> adapter = new ArrayAdapter<HighScore>(this, android.R.layout.simple_list_item_1, values);
setListAdapter(adapter);
Make a row layout with two TextViews placed the way you want and implement a simple custom ArrayAdapter:
public class CustomAdapter extends ArrayAdapter<HighScore> {
private LayoutInflater inflater;
public CustomAdapter(Context context, int textViewResourceId,
List<HighScore> objects) {
super(context, textViewResourceId, objects);
inflater = LayoutInflater.from(context);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = inflater.inflate(R.layout.new_row_layout, parent, false);
}
HighScore item = getItem(position);
TextView name = (TextView) findViewById(R.id.name_id_textview);
name.setText(/*get the name from the item HighScore object*/);
TextView moves = (TextView) findViewById(R.id.moves_id_textview);
moves.setText(/*get the moves from the item HighScore object*/);
return convertView;
}
}
Another option is to break your List<HighScore> values in a List of HashMaps(containing two entries, one for name and one for moves) and use a SimpleAdapter(with the row layout above).

display information, that is contained of an object, to a ListView

I'm trying to display information about an object, concretely a customer. I mean name, last name, telephone number, adress, .... that is the result by a query on my database.
I want to display this on a ListView, so better if my activity inherit of a ListActivity because ListView is self-contained by default.
I do the next: I have a class called Customer that saves all information by the query (Cursor) that only return one record(customer) and I don't know how to pass this object ,I don't find the most appropriate adapter.
Can I do this by this way or I must convert this object into an ArrayList that contains all information and, in fact, use ArrayAdapter for my adapter?
Anyone knows how to do this??
Thanks.
Once you have your cursor queried you should do something like this
String[] from = new String[]{"FirstName"};
int[] to = new int[]{R.id.row};
SimpleCursorAdapter sca = new SimpleCursorAdapter(this, R.layout.row_item, cur, from, to);
setListAdapter(sca);
check here the documentation for SimpleCursorAdapter.
If you need to do something more complicated with your views you should implement your own custom Cursor adapter:
public class ExampleCursorAdapter extends CursorAdapter {
public ExampleCursorAdapter(Context context, Cursor c) {
super(context, c);
}
#Override
public void bindView(View view, Context context, Cursor cursor) {
TextView summary = (TextView)view.findViewById(R.id.summary);
summary.setText(cursor.getString(
cursor.getColumnIndex(ExampleDB.KEY_EXAMPLE_SUMMARY)));
}
#Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
LayoutInflater inflater = LayoutInflater.from(context);
View v = inflater.inflate(R.layout.item, parent, false);
bindView(v, context, cursor);
return v;
}
}
And finally, I can find the solution it would be. I'm going to tell you how I did.
I wanted to display details customer by this way:
row 1-> Name: name_value
row 2-> Last Name: lastname_value
row 3-> Phone: phone_value
...
N. n row -> n_field: n_value
Fields that describe what value is going to show, i mean "Name:", "Last Name:", "Phone:", ...
I put all this values on a string-array . I captured that by a String [] .
Values, show proper value next the correct field. I put all this inside a ArrayList
and next only have to write the proper adapter:
This Activity inherit ListActivity, ListView by default.
SimpleCursorAdapter is not proper because we have to pass the cursor as argument of this adapter but my Cursor only returns only one result, only one record .
And CursorAdapter is refused by the same reason. What can I do next? ArrayAdapter :
public class DetalleClienteAdapter extends ArrayAdapter<String>
{
private String[] campos_cliente;
private ArrayList<String> detalles_cliente;
public DetalleClienteAdapter(Context contexto, int layout, ArrayList<String> detalles)
{
super(contexto,layout,detalles);
//mInflater = LayoutInflater.from(contexto);
// LOS VALORES DE LOS CAMPOS:
detalles_cliente = detalles;
// CAMPOS DE DETALLES: nombre, apellidos, etc...
android.content.res.Resources res = getResources();
campos_cliente = res.getStringArray(R.array.array_detalle_cliente);
}
#Override
public View getView(int position, View convertView, ViewGroup parent)
{
// TODO Auto-generated method stub
//return super.getView(position, convertView, parent);
LayoutInflater inflater= getLayoutInflater();
View fila = inflater.inflate(R.layout.detalles_cliente, parent, false);
TextView campo =(TextView)fila.findViewById(R.id.detalles_campo);
TextView valor =(TextView)fila.findViewById(R.id.detalles_valor);
campo.setText(campos_cliente[position]);
valor.setText(detalles_cliente.get(position));
return fila;
}
}
Now I'm going to write a more efficient adapter, with ViewHolder. What is your opinion about that?
Thanks.

Categories

Resources