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
Related
I have created an android app in which i have to fetch data from sqlite database and set it on custom listview. Problem is that data is not shown. my code is same as a required for showing output.
You need to create a class which extends CursorAdapter. Below is the demo code:
public class PassCursorAdapter extends CursorAdapter {
public PassCursorAdapter(Context context, Cursor c) {
super(context, c,0);
}
#Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
return LayoutInflater.from(context).inflate(R.layout.item_todo,parent,false);
}
#Override
public void bindView(View view, Context context, Cursor cursor) {
TextView textID = (TextView) view.findViewById(R.id.textView6);
TextView textName = (TextView) view.findViewById(R.id.textView3);
TextView textUser = (TextView) view.findViewById(R.id.textView4);
TextView textPass = (TextView) view.findViewById(R.id.textView5);
int idColumnIndex = cursor.getColumnIndex(PassDBHelper.COLUMN_ID);
int nameColumnIndex = cursor.getColumnIndex(PassDBHelper.PASS_COLUMN_NAME);
int userColumnIndex = cursor.getColumnIndex(PassDBHelper.PASS_COLUMN_USERNAME);
int passColumnIndex = cursor.getColumnIndex(PassDBHelper.PASS_COLUMN_PASSWORD);
String id = cursor.getString(idColumnIndex);
String name = cursor.getString(nameColumnIndex);
String user = cursor.getString(userColumnIndex);
String pass = cursor.getString(passColumnIndex);
textID.setText(id);
textName.setText(name);
textUser.setText(user);
textPass.setText(pass);
}
}
In the newView method you are returning the layout file. This is how your List View layout file will be with 4 Text Views. In the End there is the method bindView where you set the id's.
Now to display the database you need to get the data from the sq-lite database as follows:
private void displayDataBaseInfo() {
PassDBHelper passDBHelper = new PassDBHelper(this);
SQLiteDatabase db = passDBHelper.getReadableDatabase();
String [] columns = {
PassDBHelper.COLUMN_ID,
PassDBHelper.PASS_COLUMN_NAME,
PassDBHelper.PASS_COLUMN_USERNAME,
PassDBHelper.PASS_COLUMN_PASSWORD
} ;
Cursor cursor = db.query(PassDBHelper.TABLE_NAME,columns,null,null,null,null,null);
ListView listView = (ListView)findViewById(R.id.list);
PassCursorAdapter passCursorAdapter = new PassCursorAdapter(this,cursor);
listView.setAdapter(passCursorAdapter);
}//displayDatabaseInfo
I want to set image in my ListView, my intention is to take a string contain the address of the image (ex. "#drawable/image") from database and to set the images for the element of the LisView. I have already create a custom SimpleCursorAdapter to change the font.This is my custom SimpleCursorAdapter code:
public class CustomFontExampleAdapter extends SimpleCursorAdapter
{
private Typeface mCustomFont;
#SuppressWarnings("deprecation")
public CustomFontExampleAdapter(final Context context, final int layout, final Cursor c, final String[] from,
final int[] to) {
super(context, layout, c, from, to);
mCustomFont = Typeface.createFromAsset(context.getAssets(), "font/Pompiere-Regular.ttf");
}
#Override
public void bindView(final View view, final Context context, final Cursor cursor) {
super.bindView(view, context, cursor);
final TextView _TextViewTitle = (TextView) view.findViewById(R.id.record_nome);
_TextViewTitle.setTypeface(mCustomFont);
}
}
This is my code when i set the adapter:
d= new Database(getActivity());
final Cursor c = d.scelta();
CursorLoader(c);
String from[] = {Codice.DATI_ID,
Codice.DATI_NOME_DIETA};
int to[] = {R.id.record_id,
R.id.record_nome};
#SuppressWarnings("deprecation")
CustomFontExampleAdapter sca = new CustomFontExampleAdapter(rootView.getContext(),
R.layout.singolo_elemento,
c, from, to);
sceltadieta = (ListView) rootView.findViewById(R.id.scelta_dieta);
sceltadieta.setAdapter(sca);
after this line :
_TextViewTitle.setTypeface(mCustomFont);
Yous should go :
ImageView _ImageView = (ImageView) view.findViewById(R.id.your_image_id)
//Suppose you've already get your string(because it's not part of a question)
Drawable drawable = getResources().getDrawable(getResources()
.getIdentifier(yourStringName, "drawable", context.getPackageName()));
_ImageView.setImageDrawable(drawable)
Oh, and as far as i see you have no context in your adapter, putting context to adapter is common thing, you should past it throw constructor(as you did), and storing reference for it(create field and initialize it by context from constructor)
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've been able to successfully link two spinners to a database using a SimpleCursorAdapter. But, I need to make the second spinner selection dependant on the first spinner selection.
Here is how I linked the data:
public class epa_estimates_button extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.epa_estimates);
final Cursor cYear;
final Cursor cMake;
final Spinner mMakeSpinner;
final Spinner mModelSpinner;
cYear = (Cursor) DataBaseHelper.getEPADataYear();
this.startManagingCursor(cYear);
SimpleCursorAdapter scaYear = new SimpleCursorAdapter(this, R.layout.spinner_layout,cYear,new String[] {DataBaseHelper.EPA_COLUMN_ONE},new int[]{R.id.text1});
scaYear.setDropDownViewResource(R.layout.spinner_dropdown);
mYearSpinner = (Spinner) findViewById(R.id.yearSpinner);
mYearSpinner.setAdapter(scaYear);
cMake = (Cursor) DataBaseHelper.getEPADataMake();
this.startManagingCursor(cMake);
SimpleCursorAdapter scaMake = new SimpleCursorAdapter(this, R.layout.spinner_layout,cMake,new String[] {DataBaseHelper.EPA_COLUMN_TWO},new int[]{R.id.text1});
scaMake.setDropDownViewResource(R.layout.spinner_dropdown);
mMakeSpinner = (Spinner) findViewById(R.id.makeSpinner);
mMakeSpinner.setAdapter(scaMake);
}}
Here is my DataBaseHelper
public class DataBaseHelper extends SQLiteOpenHelper {
private static String DB_PATH = "/data/data/org.application.ocdmpg/databases/";
private static String DB_NAME = "ocd_mpg.mp3";
private final int DB_VERSION = 1;
private static SQLiteDatabase myDataBase;
private final Context myContext;
private static final String EPA_TABLE_NAME = "epa_data";
private static final String EPA_COLUMN_ID = "_id";
public DataBaseHelper(Context context) {
super(context, DB_NAME, null, 1);
this.myContext = context;
}
public static Cursor getEPADataYear()
{
return myDataBase.query(EPA_TABLE_NAME, //table name
new String[] {EPA_COLUMN_ID, EPA_COLUMN_ONE}, //list of columns to return
null, //filter declaring which rows to return; formatted as SQL WHERE clause
null,
EPA_COLUMN_ONE, //filter declaring how to group rows; formatted as SQL GROUP BY clause
null, //filter declaring which row groups to include in cursor; formatted as SQL HAVING clause
null); //how to order rows; formatted as SQL ORDER BY clause
}
public static Cursor getEPADataMake()
{
return myDataBase.query(EPA_TABLE_NAME, new String[] {
EPA_COLUMN_ID,
EPA_COLUMN_TWO,
},
null,
null,
EPA_COLUMN_TWO,
null,
null);
}}
I've found code for setOnItemSelectedListener and tried to add my code for linking the data to the spinner but the startManagingCursor method and SimpleCursorAdapter constructors give me an error as undefined. Should I use an ArrayAdapter to populate my spinners? Or is there a way to correct the code below?
mYearSpinner.setOnItemSelectedListener(new OnItemSelectedListener() {
#Override
public void onItemSelected(AdapterView<?> parentView, View selectedItemView, int position, long id) {
// your code here
cMake = (Cursor) DataBaseHelper.getEPADataMake();
this.startManagingCursor(cMake);
SimpleCursorAdapter scaMake = new SimpleCursorAdapter(this, R.layout.spinner_layout,cMake,new String[] {DataBaseHelper.EPA_COLUMN_TWO},new int[]{R.id.text1});
scaMake.setDropDownViewResource(R.layout.spinner_dropdown);
mMakeSpinner = (Spinner) findViewById(R.id.makeSpinner);
mMakeSpinner.setAdapter(scaMake);
}
#Override
public void onNothingSelected(AdapterView<?> parentView) {
// your code here
}
});
Updated based on your edit and comments
Your call to this.startManagingCursor(cMake) needs to be changed to either startManagingCursor(cMake) or epa_estimates_button.this.startManagingCursor(cMake), since it's being made from within an inner class (an OnItemSelectedListener). It works without 'this' (the former case) because, well, basically, Java figures out which this you meant. And it works with the classname because that makes explicit what Java would have figured out for itself. But the unqualified this implies that you're referring to the inner class this, and that wouldn't work.
Very similarly, in your onItemSelectedListener, your call to startManagingCursor needs to be rewritten as:
SimpleCursorAdapter scaMake = new SimpleCursorAdapter(epa_estimates_button.this,
R.layout.spinner_layout,cMake,new String[] {DataBaseHelper.EPA_COLUMN_TWO},
new int[]{R.id.text1});
(I think your database queries are going to need work -- you don't seem to use any sort of WHERE clause to restrict the 'make' results to the appropriate year. But if you do get stuck on that, please post it as another question.)
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.