Add extra element to cursor adapter android
Asked Answered
G

8

12

I have a Cursor that contains all rows from my database. That Cursor I pass to a CursorAdapter, and display the data in a list. But I need to show one extra element in the beginning. How can I do that?

I read somewhere that maybe it can be done with a CursorWrapper, and it can inject extra values into the results. But I'm not quite sure how to do that.

If someone can show me an example (code), or have another idea how to solve this, please let me know. Thx!

Gibbsite answered 19/9, 2012 at 10:20 Comment(0)
R
2

You can use the list view's addHeaderView() or addFooterView():

TextView label = new TextView(context);
label.setText("Something Here");

listView.addHeaderView(label);

Just be sure to do so before calling setAdapter().

Rangoon answered 26/2, 2014 at 5:23 Comment(1)
This is the first time I see an answer that really addresses a good use case and is simple and worked immediately for the android tag. Thank you so much, and I am very surprised this answer is not upvoted.Killigrew
K
10

How about using a combination of MergeCursor and MatrixCursor as I've suggested in this question: How to insert extra elements into a SimpleCursorAdapter or Cursor for a Spinner?

Kalliekallista answered 31/1, 2013 at 10:1 Comment(1)
I solved this adding an extra element in the database. But maybe it can be done using what you've suggested. +1Gibbsite
T
4

Override getCount like this:

@Override
public int getCount() {
    final int count = super.getCount();
    return count+1;
}

and who ever uses the adapter gets one extra row. Just remember to handle this in getView ie.

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        if(position == 0) {
            final View v = inflater.inflate(R.layout.special_suggestion, parent,false);
            final TextView tv = (TextView) v.findViewById(android.R.id.text1);
            tv.setText("Search for '" + this.keyword + "'");
            return v;
        }
        else {
            try {
                return super.getView(position, convertView, parent);
            }
            catch (IllegalStateException e) {
                Log.e(TAG, "IllegalStateException: " + e);
            }
        }
        return inflater.inflate(this.layout, parent,false);
    }
Timbal answered 5/3, 2014 at 14:26 Comment(1)
You don't have to pass position - 1 to super.getView? The adapter will know to start at the first item when you've already taken that position in the list?Sympathize
R
2

You can use the list view's addHeaderView() or addFooterView():

TextView label = new TextView(context);
label.setText("Something Here");

listView.addHeaderView(label);

Just be sure to do so before calling setAdapter().

Rangoon answered 26/2, 2014 at 5:23 Comment(1)
This is the first time I see an answer that really addresses a good use case and is simple and worked immediately for the android tag. Thank you so much, and I am very surprised this answer is not upvoted.Killigrew
J
1

You can read data from Cursor into List<YourRow>, where YourRow is a class for data from your cursor row. Then just add new YourRow item to list and use BaseAdapter for your ListView. Read this to find how to deal with BaseAdapter.

Jestinejesting answered 19/9, 2012 at 10:30 Comment(1)
Thx for the suggestion. Still I think that it may be a little bit simpler if I can inject extra values into the result. Do you know how I can do that using CursorWrapper? I found this [groups.google.com/forum/?fromgroups=#!topic/android-developers/… ], but I have no idea how to accomplish that.Gibbsite
G
1

I ended up solving this problem by adding an extra element in the database. It was the simplest solution, because I needed the extra element at the beginning. So after creating my database, I insert a row in the table that I need extra element for, with the values that I want.

I also found this discussion [ https://groups.google.com/forum/?fromgroups=#!topic/android-developers/QSOGjgL8kXI ] so if someone has similar problem, it would be a starting point. Thx!

Gibbsite answered 19/9, 2012 at 12:57 Comment(3)
You can see @Jestinejesting answer also.Gibbsite
I did the same.. It's looks like an informal best practiceGiralda
This will be a somewhat reasonable solution right up until you provide a way for users to delete/ modify database entries, or need to reset the DB for any reason. Of course, if your entries are that static you probably shouldn't be using a DB in any case. The simplest, most future-proof solution is provided in my answer above.Rangoon
T
0

In the adapter you can probably show the extra data in the getView method. But it kinda depends on where the data comes from, what you want to do with it (just display it?), etc.

Threesquare answered 19/9, 2012 at 10:28 Comment(7)
I tried that, but if let's say I have 6 items in the cursor, getView gets called 6 times, so when I add the extra item, not all the items from the cursor are shown. There is always one item that is never shown.. That's why I wanted to add extra item in the cursorGibbsite
Yes, but when the hidden item comes into view, getView will be called on the adapter, will it not? Or I'm really confused!Threesquare
I tried this: getView gets called regularly for the items in the cursor, and if (position == 0) I add the extra item that i need. So afterwards getView gets called for the remaining items in the cursor, and along with the extra first one, there is always one item that is never shown. i tried calling getView one more time when I add the extra item, but it is not working properly. Maybe because I don't know what to put in convertView, parent variables from the function -> getView(int position, View convertView, ViewGroup parent)Gibbsite
Ah sorry! I completely misread what you wanted. I thought you wanted to add an extra column to your dataset, but it seems you want to add another row (a heading of some kind? Or just another normal row?). Correct?Threesquare
Yes I have a list, for which i pull data from my database and I want the first item to be: let's say "All items". But header does not work for me, I need it to be an item from the list.Gibbsite
Not sure if there is another option other than customizing the adapter. You'd need to inflate the counter by 1, then override the getItem function to get the current item+1, and if the requested item is 0, return your extra row.Threesquare
I ended up inserting another row in the database. It was the simplest solution at this time. But thx anyway.Gibbsite
W
0

Similar to adding an extra field to a database, you could add an additional field to the projection from the database. This saves you a little bit of space in your db and reduces information redundancy. It does mean that the field is recomputed each access instead of just stored.

Here is an example of a projection I have used to format a cost based off of the a price of an item (stored in cents) and an associated unit.

public static final String CONCATE_COST
        = "'$' || CASE WHEN SUBSTR(ROUND("+COLUMN_PRICE
            +"/100.0, 2), LENGTH(ROUND("+COLUMN_PRICE
            +"/100.0, 2))-1, 1)='.' THEN ROUND("+COLUMN_PRICE
            +"/100.0, 2) || '0' else ROUND("+COLUMN_PRICE
            +"/100.0, 2) end || "+COLUMN_UNIT;

Use that as a column to pass to your listview and you can pair it with a field in your view directly.

Westward answered 26/2, 2013 at 8:0 Comment(0)
Q
0

In those cases my solution is to execute an UNION query with static values. EX:

(Select -1 as id, "HERE GOES THE NAME" as name, "HERE GOES THE ADDRESS" as address) UNION (Select id, name, address from contacts order by name)

(doublecheck syntax, please, I'm doing by memory)

This way, you get a first row with -1|HERE GOES THE NAME|HERE GOES THE ADDRESS plus the rest of rows

So, you are not "polluting" the database and is easy to switch the first row on/off with conditions and playing with concatenations.

Qualifier answered 5/12, 2013 at 0:5 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.