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.)
Related
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
I wanted to pass a selected menu name in listview to another intent class so that the new submenu is recognized by its parent-menu. So I used the getExtras to get Menu name as belows in KatagoriPengeluaran.java
public void displayListView() {
listView.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> listView, View view,
int position, long id) {
Cursor cursor = (Cursor) listView.getItemAtPosition(position);
String countryCode =
cursor.getString(cursor.getColumnIndexOrThrow("katagori_label"));
Intent ourIntent = new Intent(KatagoriPengeluaran.this, Pengeluaran.class);
ourIntent.putExtra("cek", countryCode);
startActivity(ourIntent);
}
});
And in the new class which is Pengeluaran.java
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.pengeluaran);
dbHelper = new Database(this);
dbHelper.open();
Bundle extras = this.getIntent().getExtras();
String sub = extras.getString("cek");
// dbHelper.deleteAllData();
//dbHelper.insertSomeData();
//Generate ListView from SQLite Database
displayListView(sub);
}
private void displayListView(final String su) {
cursor = dbHelper.fetchPengeluaran(su);
// The desired columns to be bound
allAdapter = new PengeluaranCursorAdapter(this, cursor);
ListView listView = (ListView) findViewById(android.R.id.list);
// Assign adapter to ListView
listView.setAdapter(allAdapter);
Here's my database and the fetch function
public class Database {
// Katagori Pengeluaran
public static final String RIK = "_id";
public static final String RLK = "katagori_label";
public static final String RJK = "katagori_jumlah";
//Pengeluaran
public static final String KEY_RPI = "_id";
public static final String KEY_RLP = "pengeluaran_label";
public static final String KEY_RSK = "pengeluaran_sub";
public static final String KEY_RNP = "nominal";
public static final String KEY_RTP = "tanggal";
public Cursor fetchPengeluaran(String su) {
Cursor mCursor = mDb.query(PENGELUARAN_TABLE, new String[] {KEY_RPI,
KEY_RLP, KEY_RSK, KEY_RNP, KEY_RTP}, "KEY_RLP like " + su
,null, null, null, null);
if (mCursor != null) {
mCursor.moveToFirst();
}
return mCursor;
}
But while executing it says NullPointerException, Unable to Inisiate Activity Component in the log cat. Please help.
Use this method to getExtra
sub = (String) getIntent().getSerializableExtra("cek");
EDIT
Just you Log.i("Activity", countryCode );
To make your your countrycode is not null
Why do you get a cursor back from your listView? That doesn't look like a good idea to me. You should separate presentation and data.
You can try using the following in the first class instead. Use putString() instead of putExtra()
ourIntent.putString("cek", countryCode);
ListView & Adapter
Other than that I can't find anything I would do different. But like I said in the first place, review having a cursor object in your presentation (listView). Instead have String objects in an ArrayAdapter for example so you can get the String countryCode directly.
More information on listViews here: http://www.vogella.com/articles/AndroidListView/article.html
Debug
Anyway I would double check in debug mode that the object returned from your Cursor is what you expect and most of all not null.
I am using SimpleCursorAdapter and database table to populate a List. The list gets populated and I am able to click on list items to open the desired item(This starts a new activity). The problem is when I press the back key, I got Following error.
IllegalStateException: database already closed.
My code is as follows:
public class populatingLectures extends ListActivity{
private static String[] FROM = {SUBJECT, TOPIC, LECTURENUMBER, DATE };
private static int[] TO = {R.id.subject, R.id.topic,
R.id.lecturenumber, R.id.date };
private static String[] data = { SUBJECT, TOPIC, LECTURENUMBER, _DATA };
private static String ORDER_BY = DATE + " DESC";
private SoftCopyDatabase lectures;
String gotId;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
SoftCopyDatabase lectures = new SoftCopyDatabase(this);
try {
Cursor cursor = getLectures();
showLectures(cursor);
} finally {
lectures.close();
}
}
public void onStart() {
super.onStart();
lectures = new SoftCopyDatabase(this);
try {
Cursor cursor = getLectures();
showLectures(cursor);
} finally {
lectures.close();
}
}
private Cursor getLectures() {
SQLiteDatabase db = lectures.getReadableDatabase();
Cursor cursor = db.query(TABLE_NAME,null, "subject=?", new String[] {OpenClick.subjectName}, null, null,
ORDER_BY);
startManagingCursor(cursor);
return cursor;
}
private void showLectures(Cursor cursor) {
SimpleCursorAdapter adapter = new SimpleCursorAdapter(this,
R.layout.item_lectures, cursor, FROM, TO);
setListAdapter(adapter);
}
private Cursor getFileName(String ID) {
SQLiteDatabase db = lectures.getReadableDatabase();
Cursor cursor = db.query(TABLE_NAME, data, "_ID=?",
new String[] { ID }, null, null, null);
startManagingCursor(cursor);
return cursor;
}
#Override
protected void onListItemClick(ListView listView, View view, int position,
long id) {
super.onListItemClick(listView, view, position, id);
//...CODE TO START NEW ACTIVITY
}
}
}
Kindly tell me what mistake am I doing. Because I am not closing the database explicitly any where.
Regards,
Waneya Iqbal.
finally
{
lectures.close();
}
I think this line gives the exception, so put it in onDestroy().
You're closing the database as soon as you populate the list. You should move the
lectures.close()
line from onStart() to onDestroy(), which will make sure your database gets closed when the activity is complete, rather than as soon as the list is populated.
i can add to a db and list as a listview.
When I click a list item using onListItemClick, what statement do I
need to get the value?
Thanks in advance.
public class Main extends ListActivity {
private static String[] FROM = { _ID, DESCRIPTION, UN };
private static String ORDER_BY = DESCRIPTION + " ASC";
private static int[] TO = {R.id.itemrowid, R.id.itemdescription, R.id.itemun };
private EventsData events;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
events = new EventsData(this);
try {
Cursor cursor = getEvents();
showEvents(cursor);
} finally {
events.close();
}
**public void onListItemClick(ListView parent, View v, int position, long id) {
// What statement to put here to get the value of _ID,DESCRIPTION, UN
// selected**?
}
private Cursor getEvents() {
// Perform a managed query. The Activity will handle closing
// and re-querying the cursor when needed.
SQLiteDatabase db = events.getReadableDatabase();
Cursor cursor = db.query(TABLE_NAME, FROM, null, null, null,
null, ORDER_BY);
startManagingCursor(cursor);
return cursor;
}
private void showEvents(Cursor cursor) {
// Set up data binding
SimpleCursorAdapter adapter = new SimpleCursorAdapter(this,
R.layout.item, cursor, FROM, TO);
setListAdapter(adapter);
}
First, you need to obtain item at clicked position:
Cursor cursor = getListAdapter().getItem(position);
Then you can get data from this cursor (I don't know what types do you use, so just for example it will be int and String):
int id = cursor.getInt(cursor.getColumnIndex(_ID));
String description = cursor.getString(cursor.getColumnIndex(DESCRIPTION));
See documentation for Cursor's available methods.
Adding to sergey answer you can also directly see what View was clicked and use findViewById() to find the components, therefore, the values you want.
This is just an alternative being the method Sergey much less 'patchy'
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.