populating a listView with images on the device - android

Ok so Ive spent the last two days looking for a good simple example of how to use the images on a device to populate a list view and Ive come to the conclusion that there is no easy way to do this. I know that everytime I put together bits and pieces from some one elses examples that I usually end up with lots of extra code i dont need. Can some one please show me how to simply load images from the device to a list view. There is no book, tutorial, or post on here that just simply shows how to do this and its kind of funny and crazy at the same time.

Here's the rest of the code, using the SDImageLoader linked to above from here: http://www.samcoles.co.uk/mobile/android-asynchronously-load-image-from-sd-card
The ListAdapter class:
public class PBListAdapter extends SimpleCursorAdapter {
//MEMBERS:
private int mLayoutId;
private SpecimenHunterDatabaseAdapter mDbHelper;
private final SDImageLoader mImageLoader = new SDImageLoader();
//METHODS:
public PBListAdapter(Context context, int layout, Cursor c) {
super(context, layout, c, new String[] {}, new int[] {});
mLayoutId = layout;
mDbHelper = new SpecimenHunterDatabaseAdapter(context);
mDbHelper.open();
}
#Override
public View newView(Context context, Cursor c, ViewGroup parent) {
final LayoutInflater inflater = LayoutInflater.from(context);
View v = inflater.inflate(mLayoutId, parent, false);
return v;
}
#Override
public void bindView(View v, Context context, Cursor c) {
String title = c.getString(c.getColumnIndexOrThrow(SpecimenHunterDatabaseAdapter.KEY_CAPTURES_TITLE));
String species = mDbHelper.fetchSpeciesName(c.getInt(c.getColumnIndexOrThrow(SpecimenHunterDatabaseAdapter.KEY_CAPTURES_SPECIES)));
int pounds = c.getInt((c.getColumnIndexOrThrow(SpecimenHunterDatabaseAdapter.KEY_CAPTURES_POUNDS)));
int ounces = c.getInt((c.getColumnIndexOrThrow(SpecimenHunterDatabaseAdapter.KEY_CAPTURES_OUNCES)));
int drams = c.getInt((c.getColumnIndexOrThrow(SpecimenHunterDatabaseAdapter.KEY_CAPTURES_DRAMS)));
String weight = pounds + context.getString(R.string.addcapture_pounds) + " " +
ounces + context.getString(R.string.addcapture_ounces) + " " +
drams + context.getString(R.string.addcapture_drams);
String photoFilePath = c.getString(c.getColumnIndexOrThrow(SpecimenHunterDatabaseAdapter.KEY_CAPTURES_PHOTO));
String comment = c.getString(c.getColumnIndexOrThrow(SpecimenHunterDatabaseAdapter.KEY_CAPTURES_COMMENT));
TextView nameView = (TextView)v.findViewById(R.id.pb_row_species_name);
TextView weightView = (TextView)v.findViewById(R.id.pb_row_capture_weight);
TextView titleView = (TextView)v.findViewById(R.id.pb_row_capture_title);
TextView commentView = (TextView)v.findViewById(R.id.pb_row_capture_comment);
ImageView photoView = (ImageView)v.findViewById(R.id.pb_row_capture_photo);
mImageLoader.load(context, photoFilePath, photoView);
nameView.setText(species);
titleView.setText(title);
weightView.setText(weight);
commentView.setText(comment);
}
}
In the actual ListActivity, in your onCreate() set the list adapter:
private void bindData() {
Cursor c = mDbHelper.fetchAllPBs();
startManagingCursor(c);
setListAdapter(new PBListAdapter(this, R.layout.pb_list_item, c));
}
In my example the absolute filepaths for the images are stored in the database when added via the app.

Related

ListViewAnimations only works when the Listview has only 1 view/element

I am using ListViewAnimations I am having this weird problem,
the animation is skipped and all of the views are populated if the list contains more than 1 element, but animation works if there is only one element to populate.
class AdapterOutcome extends CursorAdapter {
public AdapterOutcome(Context context, Cursor c, int flags) {
super(context, c, 0);
}
#Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
return LayoutInflater.from(context).inflate(R.layout.outcome_custom_row, parent, false);
}
#Override
public void bindView(View view, Context context, Cursor cursor) {
//finding the Views
TextView amonut = (TextView) view.findViewById(R.id.amount);
ImageView transactionType = (ImageView) view.findViewById(R.id.custom_row_icon);
TextView time = (TextView) view.findViewById(R.id.timeid);
TextView location = (TextView) view.findViewById(R.id.location);
TextView date = (TextView) view.findViewById(R.id.date);
TextView type_icon = (TextView) view.findViewById(R.id.type_icon);
//Creating Cursors for each View
String cursorTranscationType = cursor.getString(cursor.getColumnIndexOrThrow("_transactionType"));
String cursorAmount = cursor.getString(cursor.getColumnIndexOrThrow("_amount"));
String cursorTime = cursor.getString(cursor.getColumnIndexOrThrow("_time"));
String cursorLocation = cursor.getString(cursor.getColumnIndexOrThrow("_location"));
String cursorDay = cursor.getString(cursor.getColumnIndexOrThrow("_day"));
String cursorMonth = cursor.getString(cursor.getColumnIndexOrThrow("_month"));
String cursorYear = cursor.getString(cursor.getColumnIndexOrThrow("_year"));
DateFormat dateformat = DateFormat.getDateInstance(DateFormat.MEDIUM);
// Date myDate = new Date(Integer.parseInt(cursorYear)-1900, Integer.parseInt(cursorMonth)-1, Integer.parseInt(cursorDay));
//set the data from the Cursor to the Views
amonut.setText(String.valueOf("- " + cursorAmount));
time.setText(String.valueOf(cursorTime));
location.setText(String.valueOf(cursorLocation));
// date.setText( dateformat.format(myDate));
if (cursorTranscationType.equals("Purchase")) {
type_icon.setText("P");
}
else{
type_icon.setText("C");
}
}
}
Did you use a custom adapter for your list view? if yes, save the last position of your getView in a global int variable and when next a view need to be populated, use the last position.
if this is not clear enough, post a sample of your code.

Populate ListView with SQLite, Images and Text from local resources

I have a ListView that will be able to show two TextViews and an ImageView per ListViewItem. I also have a SQLite Database that has the following fields, _id, name, description, image.
An example record would be as follows:
1,R.string.name1,R.string.description1,R.drawable.image1
The strings for name and description are in the strings.xml file, and the images needed are in the res/drawable folders, which would usually be referenced by R.drawable.image_name
I am using the SQLiteAssetHelper Library to manage the database.
I am able to get a cursor containing all the information needed, and I am able to populate the listview with the text, but when I run the app, the textviews show as R.string.name1, R.string.description1, etc. I have not yet been able to get the image to work at all.
How would I get the text to show properly (so I can have different languages in the future) and how would I get the images to show?
Here is my code so far:
Database Helper
public class Database extends SQLiteAssetHelper {
private static final String DATABASE_NAME = "database.sqlite";
private static final int DATABASE_VERSION = 1;
public Database(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
setForcedUpgrade();
}
public Cursor getList() {
SQLiteDatabase db = getReadableDatabase();
SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
String [] sqlSelect = {"_id","name","description","image"};
String sqlTables = "tbl_list";
qb.setTables(sqlTables);
Cursor c = qb.query(db, sqlSelect, null, null,
null, null, null);
c.moveToFirst();
return c;
}
}
Main Activity
public class SQLite_List extends ActionBarActivity {
private ListView listView1;
private Cursor list;
private Database db;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.listview);
getSupportActionBar().setTitle("List");
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
db = new Database(this);
list = db.getList(); //Move this to its own thread later on
ListAdapter adapter = new SimpleCursorAdapter(this,
android.R.layout.simple_list_item_2,
mods,
new String[] {"name","description"}, //table values
new int[] {android.R.id.text1,android.R.id.text2});
listView1 = (ListView) findViewById(R.id.listview);
listView1.setAdapter(adapter);
}
...
}
Thanks
EDIT: I have written a new adapter, but the images are still not working:
public class SQLite_Adapter extends ResourceCursorAdapter {
public SQLite_Mods_Adapter(Context context, int layout, Cursor c, int flags) {
super(context, layout, c, flags);
}
#Override
public void bindView(View view, Context context, Cursor cursor) {
TextView name = (TextView) view.findViewById(R.id.txtTitle);
name.setText(cursor.getString(cursor.getColumnIndex("name")));
TextView description = (TextView) view.findViewById(R.id.txtDescription);
description.setText(cursor.getString(cursor.getColumnIndex("description")));
ImageView image = (ImageView) view.findViewById(R.id.imgIcon);
image.setImageResource(context.getResources().getIdentifier("image","drawable","com.package"));
}
}
EDIT 2: I found a solution. The answer is posted below.
Ok, I got this to work, Instead of using the SimpleCursorAdapter, use a custom adapter. Code can be found below.
Then you use the getIdentifier method to turn the name of the image or string, into an integer that can be used to setText on a TextView or setImageResource on an ImageView:
public class SQLite_ListView_Adapter extends ResourceCursorAdapter {
public SQLite_ListView_Adapter(Context context, int layout, Cursor c, int flags) {
super(context, layout, c, flags);
}
#Override
public void bindView(View view, Context context, Cursor cursor) {
TextView name = (TextView) view.findViewById(R.id.txtTitle);
String name_string=cursor.getString(cursor.getColumnIndex("name"));
int resIdName = context.getResources().getIdentifier(name_string, "string", context.getPackageName());
name.setText(resIdName);
TextView description = (TextView) view.findViewById(R.id.txtDescription);
String description_string = cursor.getString(cursor.getColumnIndex("description"));
int resIdDescription = context.getResources().getIdentifier(description_string, "string", context.getPackageName());
description.setText(resIdDescription);
ImageView image = (ImageView) view.findViewById(R.id.imgIcon);
String image_string = cursor.getString(cursor.getColumnIndex("image"));
int resId=context.getResources().getIdentifier(image_string, "drawable", context.getPackageName());
image.setImageResource(resId);
}
}
So if you had the string, R.string.name1 and you wanted that to show in the TextView, then in the name field of a record in your database, you only need name1
Similar idea with drawables and whatever else you might need

CursorAdapter + CheckBox, if check some item, some other is checked too

I try create my own Adapter for ListView with checkboxes on each row. All works fine, but problem is, when I check some checkbox and then scroll down, other one is checked too.
(When I check first, 11th, 21th, ..., is checked too) Can me anyone explain wher is the problem?
Thank you.
My adapter:
public class WordAdapter extends CursorAdapter {
public WordAdapter(Context context, Cursor cursor, int flags){
super(context, cursor, flags);
}
#Override
public void bindView(View oldView, Context ctx, Cursor c) {
int wordQuestionIndex = c.getColumnIndex( WordDBAdapter.QUESTION );
int wordAnswerIndex = c.getColumnIndex( WordDBAdapter.ANSWER );
int activeIndex = c.getInt(c.getColumnIndex( WordDBAdapter.ACTIVE ));
String question = c.getString(wordQuestionIndex);
String answer = c.getString(wordAnswerIndex);
int active = c.getInt(activeIndex);
Log.d("WordAdapter", "isActive: "+ active + " - " + question + ", " + answer);
((TextView) oldView.findViewById(R.id.adapter_question)).setText(question);
((TextView) oldView.findViewById(R.id.adapter_answer)).setText(answer);
CheckBox checkBox =(CheckBox) oldView.findViewById(R.id.myCheckBox);
//checkBox.setChecked(vh.isChecked);
}
#Override
public View newView(Context ctx, Cursor c, ViewGroup root) {
LayoutInflater inflater = LayoutInflater.from(ctx);
View view = inflater.inflate(R.layout.word, root, false);
return view;
}
}
This is because of the reuse of the old view...
I would suggest, you maintain a list of check boxes items which are ticked and reset the check box item in bindview every time you initialize with new values..
Similar Question and solution is found here

couple questions about custom arrayadapter

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)

Android ViewHolder in CursorAdapter causing listView to get screwed

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

Categories

Resources