so im a little confused here....
i have code that takes info from my sqlite database and populates a list, then shows the list using the standard array adapter. what i want to do is have it so that in this list, the row color is green if the "completed" table row value is "yes"
heres my db structure for the table being used:
String CREATE_ACHIEVEMENTS_TABLE = "CREATE TABLE achievements ("
+ "id INTEGER PRIMARY KEY,"
+ "name VARCHAR,"
+ "type VARCHAR,"
+ "value VARCHAR,"
+ "completed VARCHAR"
+ ")";
heres my code that gets the list from the db:
public ArrayList<String> getAchievements(Context context) {
ArrayList<String> achievementList = new ArrayList<String>();
String selectQuery = "SELECT * FROM achievements ORDER BY id asc";
SQLiteDatabase db = this.getWritableDatabase();
Cursor cursor = db.rawQuery(selectQuery, null);
if (cursor != null) {
if (cursor.moveToFirst()) {
do {
if (cursor.getString(4).equals("yes")) {
achievementList.add(cursor.getString(1)+" (completed)");
}
else {
achievementList.add(cursor.getString(1));
}
} while (cursor.moveToNext());
}
}
else {
achievementList.add(context.getResources().getString(R.string.na));
}
cursor.close();
db.close();
return achievementList;
}
heres my custom arrayadapter:
public class AchievementAdapter extends ArrayAdapter<String> {
private final Context context;
private final String[] values;
public AchievementAdapter(Context context, String[] values) {
super(context, R.layout.achievements, values);
this.context = context;
this.values = values;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View row = convertView;
if (row == null) {
LayoutInflater inflater = (LayoutInflater)this.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
row = inflater.inflate(R.layout.achievement_item, parent, false);
}
return row;
}
}
i really have no clue where to go from here. this is my first android app and i have learned a LOT, but i cant seem to figure out how to achieve this simple thing in regards to custom arrayadapters....all the tutorials i find contain a bunch of features that i dont want. all im trying to do is make the text color of the list item green if its "completed" table value is "yes"...
First of all, I recommend using a cursorAdapter instead of an arrayAdapter. With a cursor adapter you will have a pointer to the DB so you can get all of the information from there.
If you do that... your code for the adapter should look something like this.
private class MyCursorAdapter extends CursorAdapter {
public MyCursorAdapter(Context context, Cursor c) {
super(context, c);
}
#Override
public void bindView(View v, Context context, Cursor cursor) {
if(cursor.getString(cursor.getColumnIndex("completed").equals("yes")){
TextView tv = (TextView) v.findViewById(R.id.NAMEOFTEXTVIEW);
tv.setTextColor(Color.GREEN);
}
}
#Override
public View newView(Context arg0, Cursor arg1, ViewGroup arg2) {
LayoutInflater inflater = (LayoutInflater)this.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
row = inflater.inflate(R.layout.achievement_item, parent, false);
return row;
}
}
and you create the adapter with:
Cursor cursor = db.rawQuery(selectQuery, null);
mAdapter = new MyCursorAdapter(this, cursor);
Having said all that... if you want to use the arrayAdapter and just change the textview,
in getView:
String item = (String) getItem(position);
if(item.contains("(completed)"){
TextView tv = (TextView) row.findViewById(R.id.NAMEOFTEXTVIEW);
tv.setTextColor(Color.GREEN);
}
I should note that with a cursorAdapter you should keep the cursor open, and close it in onStop (reopen it in onRestart)
Related
I trying to populate a listview with data from an SQL database using the following code
final DBAdapter db = new DBAdapter(this);
db.open();
Cursor c = db.getAsset6("MARK BARR");
int mx=1;
String[] lvdata = new String[mx];
while (c.moveToNext()) {
lvdata[mx]=c.getString(1) + "-" + c.getString(2) + "-" + c.getString(6);
mx++;
}
setListAdapter(new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_1, lvdata));
getListView().setTextFilterEnabled(true);
db.close();
When I run the app crashes I'm am sure it something to do with the way i'm adding the data into a string in the while loop and then setting the adapter but I cant work out where I'm going wrong
Any help is appreciated
Mark
EDIT
OK the following works OK now But he app crashed when I reach the last listview entry
final DBAdapter db = new DBAdapter(this);
db.open();
Cursor c = db.getAsset6("MARK BARR");
int mx=0;
String[] lvdata = new String[c.getCount()];
while (c.moveToNext()) {
lvdata[mx]=c.getString(1) + "-" + c.getString(2) + "-" + c.getString(6);
mx++;
}
// use your custom layout
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
R.layout.rowlayout, R.id.label, lvdata);
setListAdapter(adapter);
}
Well I am probably not worthy of even tying Vogella's shoes but this how I do it. I like using CursorAdapter because it allows you do all kinds of things with images and I think it's easier. If if you don't use this please check it out as you may need this in the future. Put this where you want to view the data whether in onCreate or from some button being pushed.
SQLiteDatabase sqLiteDatabase = controller.getReadableDatabase();
String query = "SELECT DISTINCT * FROM YOURTABLENAME";
Cursor cursor = sqLiteDatabase.rawQuery(query, null);
((ListView) YOURLISTVIEWNAME).setAdapter(new ANYNAMEADAPTER(context,
cursor, 0));
Then we create ANYNAMEADAPTER to get all the data into one organized place
private static final class ANYNAMEADAPTER extends CursorAdapter {
ANYNAMEADAPTER(Context context, Cursor cursor, int flags) {
super(context, cursor, flags);
mInflater = LayoutInflater.from(context);
}
#Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
View v = mInflater.inflate(android.R.layout.simple_list_item_1, parent, false);
return v;
}
#Override
public void bindView(View view, Context context, Cursor cursor) {
TextView theline = (TextView) view.findViewById(android.R.id.text1);
String thedata =cursor.getString(1) + "-" + cursor.getString(2) + "-" + cursor.getString(6);
theline.setText(thedata);
}
LayoutInflater mInflater;
}
I am using a CursorAdapter with a ListView and a cursor getting data from an sqlite database. I have this function called RenderList() which I call every time I update the database with a new item for the list or if I set the checked value of a row to one (this will add the new item or strikethough the item name).
private void renderList(){
String showWhere = show_checked ? null : DbHelper.C_CHECKED + "= '0' ";
try {
db = dbHelper.getReadableDatabase();
cursor = db.query(DbHelper.TABLE, null, showWhere, null, null, null, dbHelper.C_ID + " DESC");
groceriesList = (ListView)findViewById(R.id.listView1);
adapter = new GroceryAdapter(this, cursor);
adapter.newView(getApplicationContext(), cursor, groceriesList);
groceriesList.setAdapter(adapter);
groceriesList.setOnItemClickListener(itemListener);
} catch (Exception e) {
Log.d(TAG, "RenderList Error: ",e);
}
}
This will reset the list, so if I click an item that is way down the listview it will reset the listview to the top position. Obviously I'm missing something with how to update the listview, and the database in an efficient, and usable way?
public class GroceryAdapter extends CursorAdapter {
private final LayoutInflater mInflater;
public GroceryAdapter(Context context, Cursor cursor) {
super(context, cursor, true);
mInflater = LayoutInflater.from(context);
// mContext = context;
}
#Override
public void bindView(View view, Context context, Cursor cursor) {
TwoLineListItem listItem = (TwoLineListItem)view;
TextView t1 = listItem.getText1();
TextView t2 = listItem.getText2();
t1.setText(cursor.getString(cursor.getColumnIndex(DbHelper.C_GROCERY)));
t2.setText("Added by: Wes");
t1.setTag(cursor.getInt(cursor.getColumnIndex(DbHelper.C_ID)));
t2.setTag(cursor.getInt(cursor.getColumnIndex(DbHelper.C_CHECKED)));
if (cursor.getInt(cursor.getColumnIndex(DbHelper.C_CHECKED)) == 1 ) {
t1.setPaintFlags(t1.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG);
listItem.setBackgroundColor(0xEECCCCCC);
} else {
t1.setPaintFlags(t1.getPaintFlags() & (~Paint.STRIKE_THRU_TEXT_FLAG) );
listItem.setBackgroundColor(0x00000000);
}
}
#Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
final View view = mInflater.inflate(R.layout.grocery_list_item, parent, false);
return view;
}
}
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
I'm trying to populate listview from my SQLite database... this is how I get my data from database:
Cursor c = database.rawQuery("SELECT * FROM " + TableName, null);
int Column1 = c.getColumnIndex("uri");
int Column2 = c.getColumnIndex("file");
int Column3 = c.getColumnIndex("id");
c.moveToFirst();
if (c != null) {
do {
String uri = c.getString(Column1);
String file = c.getString(Column2);
int id = c.getInt(Column3);
} while (c.moveToNext());
}
I would normally add an array to listview like that:
ListView my_listview2 = (ListView) findViewById(R.id.listView1);
String my_array[] = {"Android", "iPhone"};
my_listview2.setAdapter(new ArrayAdapter<String>(this, R.layout.row, R.id.my_custom_row, my_array));
How can I make an array to setadapter from my sql query?
The best way to do this is to use a CursorAdapter or a SimpleCursorAdapter. This will give you the best performance and once you figure it out you'll find it's the simplest approach when using a SQLite db.
http://developer.android.com/reference/android/widget/SimpleCursorAdapter.html
Below is a simple CustomCursorAdapter that I use frequently. Just add the CustomCursorAdapter class as an inner class.
protected class CustomCursorAdapter extends SimpleCursorAdapter {
private int layout;
private LayoutInflater inflater;
private Context context;
public CustomCursorAdapter (Context context, int layout, Cursor c, String[] from, int[] to) {
super(context, layout, c, from, to);
this.layout = layout;
this.context = context;
inflater = LayoutInflater.from(context);
}
#Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
Log.i("NewView", newViewCount.toString());
View v = inflater.inflate(R.layout.list_cell, parent, false);
return v;
}
#Override
public void bindView(View v, Context context, Cursor c) {
//1 is the column where you're getting your data from
String name = c.getString(1);
/**
* Next set the name of the entry.
*/
TextView name_text = (TextView) v.findViewById(R.id.textView);
if (name_text != null) {
name_text.setText(name);
}
}
Create an instance of the CustomCursorAdapter like so...
You'll need to create your cursor just like you're already doing.
protected String[] from;
protected int[] to;
//From is the column name in your cursor where you're getting the data
//to is the id of the view it will map to
from = new String[]{"name"};
to = new int[]{R.id.textView};
CustomCursorAdapter adapter = new CustomCursorAdapter(this, R.layout.list, cursor, from, to);
listView.setAdapter(adapter);
I found working with the notepad tutorial very useful for learning about this.
It shows you how to implement the listview using the sqlite database in very easy steps.
http://developer.android.com/resources/tutorials/notepad/index.html
i have been having this issue for some time now, and have not gotten an answer for it yet. i have this custom Cursor adapter which i use to populate a list view from an sqlite database. Now my issue is that i want to populate the listview based on certain conditions.An example is if the condition is important, the listview should display only data that fits into that criteria and so on. I already have working methods that query the database accordingly.
now my problem is that, i can't seem to populate the listviews based on those methods and conditions without:
1) creating a copy of the exact same custom cursor adapter and just changing the names variables.
2) creating a copy of the exact xml layout and changing the id's.
As i say, its working this way, but i feel am having unnecessary classes and xml layout since its exactly the same thing. I know am doing something wrong, i just don't know what. Please any help and explanation would be appreciated. here is the necessary part of the code Code for the CustomCursorAdapter:
public class ViewItems extends ListActivity implements OnItemClickListener{
DBAdapter adapter;
Cursor cursor;
ListView list;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.view_list);
adapter = new DBAdapter(this);
adapter.open();
fillData();
list = (ListView)findViewById(android.R.id.list); // default android listView id
list.setOnItemClickListener(this);
}
// Different method calls
protected void fillImportantData() {
Cursor cursor = adapter.retrieveImportant();
startManagingCursor(cursor);
String[] from = new String[]{DBAdapter.NAME, DBAdapter.DATE, DBAdapter.TIME, DBAdapter.PRIORITY};
int[] to = new int[]{R.id.viewNameId, R.id.viewDateId, R.id.viewTimeId};
customCursorAdapter items = new customCursorAdapter(this, R.layout.view_items, cursor, from, to);
setListAdapter(items);
}
public class customCursorAdapter extends SimpleCursorAdapter {
private int layout;
Context context;
public customCursorAdapter(Context context, int layout, Cursor cursor, String[]from, int[] to) {
super(context, layout, cursor, from, to);
this.layout = layout;
this.context = context;
}
#Override
public void bindView(View view, Context context, Cursor cursor) {
ViewHolder holder;
if(view != null){
holder = new ViewHolder();
holder.viewName = (TextView)view.findViewById(R.id.viewNameId);
holder.viewStartDate = (TextView)view.findViewById(R.id.viewDateId);
holder.viewStartTime = (TextView)view.findViewById(R.id.viewTimeId);
view.setTag(holder);
}else{
holder = (ViewHolder)view.getTag();
}
int namecol = cursor.getColumnIndex(DBAdapter.NAME);
String name = cursor.getString(namecol);
if(holder.viewName != null){
holder.viewName.setText(name);
holder.viewName.setTextColor(Color.RED);
}
String startDate = cursor.getString(cursor.getColumnIndex(DBAdapter.DATE));
holder.viewStartDate.setText(startDate);
String startTime = cursor.getString(cursor.getColumnIndex(DBAdapter.TIME));
holder.viewStartTime.setText(startTime);
}
#Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
LayoutInflater inflater = LayoutInflater.from(context);
final View view = inflater.inflate(layout, parent, false);
return view;
}
#Override
public long getItemId(int id){
return id;
}
#Override
public Object getItem(int position){
return position;
}
}
static class ViewHolder{
TextView viewName;
TextView viewStartDate;
TextView viewStartTime;
}
}
// methods in database
public Cursor retrieveAll(){
String[] resultColumns = new String[] {KEY_ID, NAME DATE, TIME, PRIORITY};
Cursor cursor = db.query(DATABASE_TABLE, resultColumns, null, , null, null, null);
return cursor;
}
public Cursor retrieveImportant(){
String[] resultColumns = new String[] {KEY_ID, NAME DATE, TIME, PRIORITY};
String[] condition = {"important"};
Cursor cursor = db.query(DATABASE_TABLE, resultColumns, PRIORITY + "=" + "?", condition, null, null, null);
return cursor;
}
If you change the data you wish to display, you will need to run a fresh query on the database and get a Cursor back that reflects that changed data. Depending on the nature of the changes, this may require a fresh CursorAdapter or merely a call to changeCursor(). If the new query returns the same columns and you want them displayed the same way, changeCursor() is probably sufficient. Otherwise, you will need to create a new CursorAdapter and call setAdapter() on your ListView to switch over to it.
You only need a different row layout if you are truly changing the row layout. You do not need to change IDs just for grins. Since you are not doing this in the code you have shown above, I am unclear what specifically you are worried about.