Concat result from Cursor into a single listview element - android

I have a android listview and it has a two_line_list_item layout.... text1 and text2
I have a SQL query which returns me my Cursor.... in the below example I have set NameA from the SQL to text1 and NameB to text2
// Create an array to specify the fields we want to display in the list (only TITLE)
String[] from = new String[]{"NameA", "NameB"};
// and an array of the fields we want to bind those fields to (in this case just text1)
int[] to = new int[]{android.R.id.text1, android.R.id.text2};
// Now create a simple cursor adapter and set it to display
SimpleCursorAdapter matches = new SimpleCursorAdapter(this, android.R.layout.two_line_list_item, MatchesCursor, from, to);
setListAdapter(matches);
How could I go about concatenating the two names (without changing my SQL query) so text1 will be "NameA v NameB"...
Thanks in advance

In your Query do
NameA || "v" || NameB AS NameAB
Then remove the second textView (android.R.text2)
In your return projections put "NameAB" leave out the other columns (keep KEY_ID) as you will no longer be needing them.

It seems to me that you need to write custom Adapter which extends BaseAdapter.

A dirty way would be using 3 views in your xml:
<TextView
android:id="#+id/nameA"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="30dp" />
<TextView
android:id="#+id/separator"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text=" vs "
android:textSize="30dp" />
<TextView
android:id="#+id/nameB"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="30dp" />
wrapping everything in a horizontal LinearLayout.

You need to write your own adapter that extends BaseAdapter
public class CustomAdapter extends BaseAdapter {
private Context context;
private int listItemLayout;
private String[] nameAs;
private String[] nameBs;
public CustomAdapter(Context context, int listItemLayout, String[] nameAs, String[] nameBs) {
this.context = context;
this.listItemLayout = listItemLayout;
this.nameAs = nameAs;
this.nameBs = nameBs;
}
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
if(convertView==null)
convertView = LayoutInflater.from(context).inflate(listItemLayout, null);
TextView textView1 = (TextView)findViewById(android.R.id.text1);
textView1.setText(nameAs[position] + " v " + nameBs[position]);
return convertView;
}
}
Now all you need to do is to modify a bit of your database access function to return you the two arrays of names, and pass them to the constructor of CustomAdapter
Eventually, call:
CustomAdapter myAdapter = new CustomAdapter(this, android.R.layout.two_line_list_item, nameAs, nameBs);
setListAdapter(myAdapter);
As a note, please also try to follow the ViewHolder pattern suggested in the link.

Related

having one spinner in each card view - card view in recyclerview

I am following this tutorial https://www.simplifiedcoding.net/android-recyclerview-cardview-tutorial/ However my requirements are different.
Instead of having set values like a name, description, rating like the tutorial has, I am wanting to have a spinner, edit text, textbox and checkbox in each Cardview. (when the user presses the FAB button, another card view is added, which also has a spinner, textbox, checkbox and edit text)
But the thing is, the spinner is populated by items in a csv file and this is where I am having trouble. I have a previous program file without card view and recycler view, where the spinners are populated with csv file values and when you press the FAB, spinner appears. However im having trouble integrating the recycler view with this.
In my previous program file I had a MyListAdapter.java.This is the adapter for the spinner i believe.
public class MyListAdapter extends ArrayAdapter<String> {
int groupid;
List<String> items;
Context context;
String path;
public MyListAdapter(Context context, int vg, int id, List<String> items) {
super(context, vg, id, (List<String>) items);
this.context = context;
groupid = vg;
this.items = items;
}
static class ViewHolder {
public TextView textid;
public TextView textname;
}
#Override
public View getDropDownView(int position, View convertView, ViewGroup parent) {
{
View rowView = convertView;
if (rowView == null) {
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
rowView = inflater.inflate(groupid, parent, false);
ViewHolder viewHolder = new ViewHolder();
viewHolder.textid = (TextView) rowView.findViewById(R.id.txtid);
viewHolder.textname = (TextView) rowView.findViewById(R.id.txtname);
rowView.setTag(viewHolder);
}
// Fill data in the drop down.
ViewHolder holder = (ViewHolder) rowView.getTag();
String row = items.get(position);
//holder.textid.setText(row[0]); //prints aisle number, dont need
holder.textname.setText(row);
return rowView;
}
}
}
Additionally then, in my mainacttivity I had this code which read the csv file.
private class CSVFile {
InputStream inputStream;
public CSVFile(InputStream inputStream) {
this.inputStream = inputStream;
}
public List<String> read() {
List<String> resultList = new ArrayList<String>();
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
try {
String line;
while ((line = reader.readLine()) != null) {
String[] row = line.split(",");
//TODO I edited this part so that you'd add the values in our new hash map variable
numberItemValues.put(row[1], row[0]);
resultList.add(row[1]);
}
} catch (IOException e) {
Log.e("Main", e.getMessage());
} finally {
try {
inputStream.close();
} catch (IOException e) {
Log.e("Main", e.getMessage());
}
}
return resultList;
}
}
But the tutorial asks for a two classes, Product.java and product adapter.java. (if you click the tutorial you will see their code) I am confused how to integrate my code above with this tutorial situation?
*-first of all create your recyclerview row layout xml file with items you want
*-load csv file in your main activity or fragment and pass them to your adapter, declare a parameter in your adapter constructor
*-inside your recuclerview adapter class, in onCreateViewHolder method inflate that layouts(just like example)
*-in your RecyclerView.ViewHolder constructor get all your comonent like Spinner and etc, just like example
TextView textViewTitle = itemView.findViewById(R.id.textViewTitle);
...
Spinner spinner = itemView.findViewById(R.id.spinner);
*-in your onBindViewHolder method fill spinner with loaded csv file, same as before
ArrayAdapter<String> adapter = new ArrayAdapter<String>(mContext, android.R.layout.simple_spinner_item, spinnerArray);
spinner.setAdapter(adapter);//mContext should be passed from your activity to your adapter, so you should add it to your adapter constructor
First, you don't need a custom adapter for your spinner if all you need is to display a simple spinner with list of strings. Add the following snippet to your onBindViewHolder() method to populate your spinner.
String[] dataArray = new String[]{"Spinner data1", "data 2"}
ArrayAdapter<String> adapter = new ArrayAdapter<String>(mContext, android.R.layout.simple_spinner_item, dataArray);
holder.spinner.setAdapter(adapter);
Read the tutorial and follow every steps including creating a Product.java class. Create a layout and replace the layout_product.xml with the new layout. I have created one for you below, copy the code and rearrange the components to meet your want and paste it in the new layout file. Lets call the new file, card_layout.
card_layout.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:orientation="vertical"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="match_parent"
android:orientation="vertical"
android:layout_height="match_parent">
<CheckBox
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<Spinner
android:padding="7dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<TextView
android:textAppearance="?android:textAppearanceMedium"
android:text="Hey, its me"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
</android.support.v7.widget.CardView>
I don't understand the TextBox part, but you can add it yourself if its not already the above code snippet. Now, replace the layout in recyclerview adapter with the new layout. It should work now.

Using different ListView layouts based on SQLite DB data

I am developing an extremely simple list app to save items to an SQLite DB, and populate a ListView with it's contents.
This can be done using a SimpleCursorAdapter, which I do like this:
mySQLiteAdapter.openToRead();
cursor = mySQLiteAdapter.queueAll();
String[] from = new String[]{mySQLiteAdapter.getKeyContent()};
int[] to = new int[]{R.id.normal};
cursorAdapter = new SimpleCursorAdapter(this, R.layout.row, cursor, from, to, 0);
listView.setAdapter(cursorAdapter);
mySQLiteAdapter.close();
Now however I would like to implement the ability to either strike out text on a row by click or long click, or change the row to a different layout (which could also strike the text)
At first I simply set the onClickListener for the listview and changed the paint flags to strike the text. This works fine until there are enough items in the list to scroll the view, or until the activity is reloaded. In the latter the strike is gone (since nothing was persistent), and in the former other rows are striked, and the intended ones are not. Then is changes as you scroll around. See Custom ListView adapter, strange ImageView behavior for a similar situation to my own.
From this I have found that I will need use a custom adapter to do what I want. So I have created a CustomCursorAdapter which extends SimpleCursorAdapter and overriden some methods to attempt to inflate a seperate layout with a background colour. I am not having much luck.
Here is what I have so far:
// Creating a new instance of the custom adapter and assigning it to the listview
mySQLiteAdapter.openToRead();
cursor = mySQLiteAdapter.queueAll();
String[] from = new String[]{mySQLiteAdapter.getKeyContent()};
int[] to = new int[]{R.id.normal};
cursorAdapter = new CustomCursorAdapter(this, R.layout.row, cursor, from, to, 0);
listView.setAdapter(cursorAdapter);
mySQLiteAdapter.close();
and
// CustomCursorAdapter class
private class MyCursorAdapter extends SimpleCursorAdapter {
private LayoutInflater inflater;
public MyCursorAdapter(Context context, int layout, Cursor c, String[] from, int[] to, int flags) {
super(context, layout, c, from, to, flags);
inflater = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
// Get reference to the row
View view = super.getView(position, convertView, parent);
//View view;
if (getItemViewType(position) == 0) {
view = inflater.inflate(R.layout.row, null);
}
else {
view = inflater.inflate(R.layout.rowstrike, null);
}
return view;
}
#Override
public int getItemViewType(int position) {
int row;
if (cursor.getInt(cursor.getColumnIndex(mySQLiteAdapter.getKeyStrike())) == 1) {
Log.d("DEBUG", "Row " + position + " is STRIKED");
row = 1;
}
else {
Log.d("DEBUG", "Row " + position + " is normal");
row = 0;
}
return row;
}
}
The implementation of the CustomCursorAdapter works and shows the correct amount of rows. The logic to determine if the row should contain striked text by querying the db is correct, however the returned inflated views are completely blank. I think it may be to do with the way my XML files are arranged and which ones I pass to the adapter but all my testing and tinkering to try to get this working have failed spectacularly so far.
Here are my XML files for the layouts
// activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
android:paddingBottom="#dimen/activity_vertical_margin"
tools:context=".MainActivity">
<EditText
android:layout_width="fill_parent"
android:layout_height="35dp"
android:id="#+id/editText"
android:hint="Press here to add an item"
android:maxLines="1"
android:imeOptions="actionDone"
android:inputType="textAutoCorrect"/>
<ListView
android:layout_width="match_parent"
android:layout_height="fill_parent"
android:id="#+id/listView"
android:layout_below="#id/editText"/>
</RelativeLayout>
.
// row.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="5dp" >
<TextView
android:id="#+id/normal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textStyle="bold"/>
</RelativeLayout>
.
//rowstrike.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="5dp" >
<TextView
android:id="#+id/striked"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#F05"/>
</RelativeLayout>
I have been searching on this for days and days, each time getting closer but nothing seems to work, or the explanations are not beginner friendly for someone like myself.
The closest post I have found to what I am after is
ListView view recycling with CustomAdapter
However I think I need more code snippets as I must be doing something wrong elsewhere in my app?
There is a mention of overriding the getViewTypeCount method but I am unsure of how this is done...
There is also
How would I use a different row layout in custom CursorAdapter based on Cursor data?
However I am not quite sure where to go from this post...
EDIT: Solution based on Luksprogs post.
mySQLiteAdapter.openToRead();
cursor = mySQLiteAdapter.queueAll();
String[] from = new String[]{mySQLiteAdapter.getKeyContent()};
int[] to = new int[]{R.id.normal};
cursorAdapter = new SimpleCursorAdapter(this, R.layout.row, cursor, from, to, 0);
cursorAdapter.setViewBinder(new SimpleCursorAdapter.ViewBinder() {
#Override
public boolean setViewValue(View view, Cursor cursor, int columnIndex) {
if (view.getId() == R.id.normal) {
TextView tv = (TextView)view.findViewById(R.id.normal);
if (cursor.getInt(cursor.getColumnIndex(mySQLiteAdapter.getKeyStrike())) == 1) {
tv.setPaintFlags(tv.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG);
}
else {
tv.setPaintFlags(tv.getPaintFlags() & (~Paint.STRIKE_THRU_TEXT_FLAG));
}
}
return false;
}
});
listView.setAdapter(cursorAdapter);
mySQLiteAdapter.close();
and I have an OnItemClickListener as follows to strike and unstrike rows
private ListView.OnItemClickListener listViewOnItemClickListener
=new ListView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
final int rowID = cursor.getInt(cursor.getColumnIndex(mySQLiteAdapter.getKeyID()));
mySQLiteAdapter.openToWrite();
if (cursor.getInt(cursor.getColumnIndex(mySQLiteAdapter.getKeyStrike())) == 0) {
mySQLiteAdapter.setKeyStrike(rowID, 1);
}
else {
mySQLiteAdapter.setKeyStrike(rowID, 0);
}
cursor = mySQLiteAdapter.queueAll();
cursorAdapter.swapCursor(cursor);
mySQLiteAdapter.close();
};
however the returned inflated views are completely blank.
As a side note, you shouldn't override the getView() method of a Cursor based adapter because this type of adapters implemented getView() to separate building the row layout and binding the data in two separate methods, newView() and bindView(). This two methods should be overridden. Also, SimpleCursorAdapter is a class designed for basic scenarios, if you need to implement (really) different row types then extending CursorAdapter would be a better approach.
You get blank row layouts because you don't do any data binding on them. In the getView() method you do:
View view = super.getView(position, convertView, parent);
which will return you a properly built row layout(by the SimpleCursorAdapter class implementation)only to discard that view and inflate a new row layout based on the row type(the if-else piece of code). You don't bind any data to those views so you return just the inflated layout which will be blank.
If your two rows are only different by a strikethrough text then you shouldn't be using two row types(different row types should be used when the rows are different in structure). You could implement what you want through a ViewBinder:
cursorAdapter = new SimpleCursorAdapter(this, R.layout.row, cursor, from, to, 0);
cursorAdapter.setViewBinder(new ViewBinder() {
#override
public void setViewValue(View view, Cursor cursor, int columnIndex) {
if (view.getId() == R.id.normal) {
// I'm assuming that the TextView with the id R.id.normal
// is the on to strike through
// use the cursor to get the value from the column on which you
// do the strikethrough
if (cursor.getInt(cursor.getColumnIndex(mySQLiteAdapter.getKeyStrike()) == 1) {
// strike the text
} else {
// otherwise un-strike the text
}
}
return false;
}
});
listView.setAdapter(cursorAdapter);
If you want
I would like to implement the ability to either strike out text on a
row by click or long click
Then you need to remember the row status somewhere so you can use it to restore it.

Spinner reset value when scrolling in a custom listview with ArrayAdapter

I am a beginner in android....I need your help.
In my app I created a listview using custom adapter and custom row layout. I am successful in doing so & I have added one image, textview and a spinner drop down in all rows. In the drop down there is number of items (from 0 to 9 for eg.)
But my problem is when I select drop down and set some value, on scrolling the list the spinner resets itself to initial value (here 0)..I am using a String of values 0 to 9 for Spinner.
What can I do to avoid this issue? Any help would be greatly appreciated....Thanks in advance.
//This is my custom adapter code....
public class MyProductsArrayAdapter extends ArrayAdapter<Products> {
Context context;
int resourceId;
Products data[] = null;
public MyProductsArrayAdapter(Context context, int resourceId,
Products data[]) {
super(context, resourceId, data);
this.context = context;
this.resourceId = resourceId;
this.data = data;
}
static class ProductsItemViewHolder {
ImageView image;
TextView name;
Spinner number;
}
String[] mArray = new String[] { "0", "1", "2", "3", "4", "5", "6", "7",
"8", "9" };
public View getView(final int position, View convertView, ViewGroup parent) {
View rowView = convertView;
ProductsItemViewHolder holder = null;
LayoutInflater mInflater = (LayoutInflater) context
.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
if (rowView == null) {
rowView = mInflater.inflate(R.layout.main2, parent, false);
holder = new ProductsItemViewHolder();
holder.image = (ImageView) rowView.findViewById(R.id.item_icon);
holder.name = (TextView) rowView.findViewById(R.id.tvListItemText);
holder.number = (Spinner) rowView.findViewById(R.id.NumberSpinner);
rowView.setTag(holder);
} else {
holder = (ProductsItemViewHolder) rowView.getTag();
}
Products f = data[position];
holder.image.setImageResource(f.itemIcon);
holder.name.setText(f.itemName);
ArrayAdapter<String> adapter = new ArrayAdapter<String>(context,
android.R.layout.simple_spinner_item, mArray);
holder.number.setAdapter(adapter);
return rowView;
}
}
//And here is my row_layout code
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal" >
<ImageView
android:id="#+id/item_icon"
android:layout_width="40dp"
android:layout_height="40dip"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true"
android:layout_marginLeft="10dip"
android:gravity="center_vertical"
android:src="#drawable/ic_launcher" >
</ImageView>
<TextView
android:id="#+id/tvListItemText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginLeft="10dp"
android:layout_toRightOf="#id/item_icon"
android:maxWidth="180dp"
android:maxLines="2"
android:text="Hello testing"
android:textColor="#color/brown"
android:textSize="15dp"
android:typeface="normal" />
<Spinner
android:id="#+id/NumberSpinner"
android:layout_width="80dp"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:layout_marginLeft="0dp" />
</RelativeLayout>
in the getView() of your List's adapter, you must call YOUR_SPINNER.setSelected(position you set earlier);
This is happening because, once the list is created you are always getting the convertView in getView and as its default stae of spinner in it is 0 position it gets there.
Also, you are doing setAdapter to spinner always in getView method, so this will always initialize it when ever getView() will be called ie. on scrolling the list.
What I am saying is set setOnItemSelectedListener() on your spinner and in onItemSelected() method of this listener set the value as the tag of your spinner object.
holder.number.setTag(POSITION)
After the statement holder.number.setAdapter() do holder.number.setSelection(Integer.parseInt(number.getTag));
This way you are saving the value you selected, and you are setting the same index to it when ever the getView() is called.
Editted:
yes, set the value you got as parameter in method onItemSelected(View v, int arg2).
This arg2 is the position system is telling you that this position is selected by you for this spinner (simple callback provided by the system).
Now, in the same method's implementation, you must set this value as the tag of this view object, which is the first argument of this callback.
Also, if you are not getting this tag value in getView() you must initialize your spinner every time instead of getting it from convertView, as it might contain the reused view of the row which is not in view.
Also, if you continue to get problem in implementing what I have said, you van follow another approach that make a static HashTable<integer, integer> where key would be the index of row and value will be the index of spinner item selected.
So, in getView you can set holder.number.setSelection(hashtable.get(position));
declare the 'LayoutInflater mInflater;' as global variable.
initialize the 'mInflater = (LayoutInflater) context .getSystemService(Activity.LAYOUT_INFLATER_SERVICE);' inside
constructor.

Can I make one ListView item have a different Text Color?

I have the layout:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<ListView
android:id="#+id/ListView01"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="1.0"
android:textColor="#android:color/white"
android:dividerHeight="1px"
android:listSelector="#drawable/highlight_sel"
/>
</LinearLayout>
And the code:
private ListView lv1;
private String lv_arr[]={"Item 1","Item 2","Item 3","Item 4"};
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.newsmenu);
lv1=(ListView)findViewById(R.id.ListView01);
// By using setAdpater method in listview we an add string array in list.
lv1.setAdapter(
new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_1,
lv_arr));
}
I want the text color of Item 2 (or 1 or 3 or 4) to appear dynamically as red (denoting a new item) or white (default). Is there a way to do this?
I already have a selector present, which is why I used ListView. I've search the Internet and this site, and I have not seen this question broached.
So is it possible?
Yes everything is possible. you need to write your own adapter implementation basically overriding the getView Method in the adapter. search google and stack you will find many tutorials on how to write an adapter.
Writing a special adapter to override getView in simple adapter is the way to change the text color alternating on the lines of your choice in a listview. I took the example which has been repeated many times on this website and added a way to change the text color. position mod length to select the color position can be replaced with any scheme you like. The text view "business" can be the first line of your layout like mine--or use the android.R.id.text1.
public class SpecialAdapter extends SimpleAdapter {
private int[] colors = new int[] { 0x30FF0000, 0x300000FF };
public SpecialAdapter(Context context, List<HashMap<String, String>> items, int resource, String[] from, int[] to) {
super(context, items, resource, from, to);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = super.getView(position, convertView, parent);
int colorPos = position % colors.length;
//view.setBackgroundColor(colors[colorPos]); //old example
TextView tv1 = (TextView)view.findViewById(R.id.business); //new
tv1.setTextColor(colors[colorPos]); //new
return view;
}
}
Just use SpecialAdapter instead of SimpleAdapter in your app.
Here's an example of a getView method. Note that it's using a viewholder for efficiency. If you want to know more about that, let me know.
public View getView(int position, View convertView, ViewGroup parent) {
tempDeal = exampleBoxArrayList.get(position);
ViewHolder holder;
if (convertView == null) {
convertView = inflator.inflate(R.layout.list_item_example_box, null);
holder = new ViewHolder();
holder.divider = (RelativeLayout) convertView.findViewById(R.id.example_box_divider);
holder.merchantName = (TextView) convertView.findViewById(R.id.example_box_merchant_name);
holder.expireDate = (TextView) convertView.findViewById(R.id.example_box_expire_date);
holder.description = (TextView) convertView.findViewById(R.id.example_box_description);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
if (tempDeal.isDivider()) {
holder.divider.setVisibility(View.VISIBLE);
} else {
holder.divider.setVisibility(View.GONE);
}
holder.merchantName.setText(tempDeal.getMerchantName());
holder.expireDate.setText(tempDeal.getExpiryDateString());
holder.description.setText(tempDeal.getPriceOption().getDescription());
return convertView;
}
As you can see, I call the isDivider() method on my custom object (this method looks at a boolean set on data load). This method is used to turn the visibility of part of the layout on or off.
Alternatively, you could load a completely new layout based on this same concept.

Binding listview row with sqlite database for custom rows

I have a listview which loads its data from sqlite database.
Each row in listview has image , textview and a checkbox.
The sqlitedatabase rows has image and text data + some other columns.
My question is can I bind my listview with the database so that all rows will be loaded with required data automatically. (image + textview) There are examples to bind a simple list of textviews. What about complex rows ? Also there are few spinners which can filter the data in list depending on its value. (Which act as a WHERE clause on my DB)
Currently I am managing this all by generating the view for my custom adapter for each row. So each time I query database and populate data. I hold the last listview results , make a newer results based on actions/conditions like spinner values, then notifydatachanged to adapter to load my new results.
To add features like DELETE , ADD , SEARCH -- I have to manage it all using collections.
Is there any simple way of doing this ? As if the db is large then the approach of holding such huge set of results in memory is not good. And is painful for managing it.
Thanks.
Here is my example for row, constructed from two records from db + image (at current - one image for any row, but it can be improved for specific image from db):
public class DomainAdapter extends SimpleCursorAdapter{
private Cursor dataCursor;
private LayoutInflater mInflater;
....
public DomainAdapter(Context context, int layout, Cursor dataCursor, String[] from,
int[] to) {
super(context, layout, dataCursor, from, to);
this.dataCursor = dataCursor;
mInflater = LayoutInflater.from(context);
}
public View getView(int position, View convertView, ViewGroup parent) {
// A ViewHolder keeps references to children views to avoid unneccessary calls
// to findViewById() on each row.
ViewHolder holder;
// When convertView is not null, we can reuse it directly, there is no need
// to reinflate it. We only inflate a new View when the convertView supplied
// by ListView is null.
if (convertView == null) {
convertView = mInflater.inflate(layout, null);
// Creates a ViewHolder and store references to the two children views
// we want to bind data to.
holder = new ViewHolder();
holder.text1 = (TextView) convertView.findViewById(R.id.test_track);
holder.text2 = (TextView) convertView.findViewById(R.id.test_band);
holder.icon = (ImageView) convertView.findViewById(R.id.test_artwork);
convertView.setTag(holder);
} else {
// Get the ViewHolder back to get fast access to the TextView
// and the ImageView.
holder = (ViewHolder) convertView.getTag();
}
// Bind the data efficiently with the holder.
// Cursor to current item
dataCursor.moveToPosition(position);
int title_index = dataCursor.getColumnIndex(fields[0]);
String title = dataCursor.getString(title_index);
int description_index = dataCursor.getColumnIndex(fields[1]);
String description = dataCursor.getString(description_index);
holder.text1.setText(title);
holder.text2.setText(description);
holder.icon.setImageResource(R.drawable.alert_dialog_icon);
return convertView;
}
static class ViewHolder {
TextView text1;
TextView text2;
ImageView icon;
}
}
and using this adapter:
databaseListAdapter = new DomainAdapter(this,
R.layout.test_layout,
databaseCursor,
new String[] {"title", "description"},
new int[] { R.id.test_track, R.id.test_track });
databaseListAdapter.notifyDataSetChanged();
DomainView.setAdapter(databaseListAdapter);
and layout:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="64dip"
android:padding="6dip">
<TextView
android:id="#+id/test_band"
android:layout_width="fill_parent"
android:layout_height="26dip"
android:layout_below="#+id/test_track"
android:layout_alignLeft="#id/test_track"
android:layout_alignParentBottom="true"
android:gravity="top" />
<TextView
android:id="#id/test_track"
android:layout_marginLeft="6dip"
android:layout_width="fill_parent"
android:layout_height="26dip"
android:layout_toRightOf="#+id/test_artwork"
android:textAppearance="?android:attr/textAppearanceMedium"
android:gravity="bottom" />
<ImageView
android:id="#id/test_artwork"
android:layout_width="56dip"
android:layout_height="56dip"
android:layout_gravity="center_vertical" />
</RelativeLayout>
My question is can I bind my listview
with the database so that all rows
will be loaded with required data
automatically. (image + textview)
There are examples to bind a simple
list of textviews. What about complex
rows ?
Yes, you can do a Cursor to complex view mapping by implementing your own CursorAdapter and overriding the bindView().

Categories

Resources