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.
Related
As title says, it get this exception from the code I pasted below. I tried to make it work both with the uncommented code and also with the commented part insted of the IF block just before it.
The error I get is: java.lang.ClassCastException: java.lang.String cannot be cast to android.database.Cursor which I don't understand, since the item in the listview should exactly be a String! Any idea?
public class ListScoutActivity extends ListActivity {
private DBHelper database;
private ListView listav;
private Cursor cursor;
ArrayList<String> stringlist = new ArrayList<String>();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_list_scout);
database = new DBHelper(getApplicationContext());
SQLiteDatabase db = database.getWritableDatabase();
listav = this.getListView();
listav.setVisibility(View.VISIBLE);
int codpartita;
String team;
cursor = db.rawQuery("SELECT _codpartita as _id, team, FROM partita ORDER BY _codpartita DESC", null);
cursor.moveToFirst();
while ( !cursor.isAfterLast() ) {
team = cursor.getString(cursor.getColumnIndex("team"));
stringlist.add(team);
cursor.moveToNext();
}
cursor.moveToFirst();
if (cursor.getCount()>0) {
SimpleCursorAdapter adapter = new SimpleCursorAdapter(ListScoutActivity.this,
android.R.layout.simple_list_item_1, cursor, new String[]{"team"},
new int[]{android.R.id.text1}, 0);
listav.setAdapter(adapter);
adapter.notifyDataSetChanged();
}
// ArrayAdapter<String> adapter = new ArrayAdapter<String>(ListScoutActivity.this,
// android.R.layout.simple_list_item_1, android.R.id.text1, stringlist);
// listav.setAdapter(adapter);
db.close();
}
#Override
protected void onListItemClick(ListView l, View v, int position, long id) {
Cursor cursor = (Cursor)l.getItemAtPosition(position);
//.. other things..
}
MAIN QUESTION:
Wondering if there's any conflict with the two spinners when I try display the results with my LoadGrid. Like if one is overriding the other and ending up with an empty result because of it. If so how do I go about combining the two results from the spinners to get the desired view.
SOME DETAILS:
I want to use two spinners on my gridview to act as filters. One for TERMS and one for STATUS. Specifically what I want to happen is that the user can use those two spinners INDIVIDUALLY or TOGETHER to filter the view of accounts in the DB.
Taking it one step at a time I've gotten one spinner running and working properly. So I cloned that working spinner code to get my second one up and running. Nope, not working. Using either of the two spinners now result in nothing. No accounts show up anymore. It'll let me select from the spinners but my grid will still be empty.
If anything is missing or you need to see more of the code please feel free to ask. Cheers.
Here's the spinners snippets:
Utilities.ManageTermSpinner(this.getParent(), spinTerm);
try {
spinTerm.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
#Override
public void onItemSelected(AdapterView<?> arg0, View arg1,
int arg2, long arg3) {
LoadGrid();
}
#Override
public void onNothingSelected(AdapterView<?> arg0) {
}
});
} catch (Exception ex) {
txtTest.setText(ex.toString());
}
Utilities.ManageStatSpinner(this.getParent(), spinStat);
try {
spinStat.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
#Override
public void onItemSelected(AdapterView<?> arg0, View arg1,
int arg2, long arg3) {
LoadGrid();
}
#Override
public void onNothingSelected(AdapterView<?> arg0) {
}
});
} catch (Exception ex) {
txtTest2.setText(ex.toString());
}
}
Here's the LoadGrid that it references:
public void LoadGrid() {
dbHelper = new DatabaseHelper(this);
try {
View v = spinTerm.getSelectedView();
TextView txt = (TextView) v.findViewById(R.id.txtTermClass);
String Terms = String.valueOf(txt.getText());
Cursor c = dbHelper.getAccByTerms(Terms);
startManagingCursor(c);
View x = spinStat.getSelectedView();
TextView txt2 = (TextView) x.findViewById(R.id.txtStatID);
String Status = String.valueOf(txt2.getText());
Cursor b = dbHelper.getAccByStatus(Status);
startManagingCursor(b);
String[] from = new String[]{DatabaseHelper.colName, DatabaseHelper.colAmount, DatabaseHelper.colTermsClass, DatabaseHelper.colStatClass};
int[] to = new int[]{R.id.colName, R.id.colAmount, R.id.colTerms, R.id.colStat};
SimpleCursorAdapter sca = new SimpleCursorAdapter(this, R.layout.gridrow, c, from, to);
grid.setAdapter(sca);
SimpleCursorAdapter sba = new SimpleCursorAdapter(this, R.layout.gridrow, b, from, to);
grid.setAdapter(sba);
} catch (Exception ex) {
AlertDialog.Builder b = new AlertDialog.Builder(this);
b.setMessage(ex.toString());
b.show();
}
}
The dbHelper snippets for TERMS and STATUS:
public Cursor getAccByTerms(String Terms)
{
SQLiteDatabase db=this.getReadableDatabase();
String [] columns=new String[]{"_id",colName,colAmount,colPurpose,colTermsClass,colDate,colEditDate,colStatClass};
Cursor c=db.query(viewAccs, columns, colTermsClass+"=?", new String[]{Terms}, null, null, null);
return c;
}
public Cursor getAccByStatus(String Status)
{
SQLiteDatabase db=this.getReadableDatabase();
String [] columns=new String[]{"_id",colName,colAmount,colPurpose, colTermsClass,colDate,colEditDate,colStatClass};
Cursor d=db.query(viewAccs,columns, colStatClass +"=?",new String[]{Status},null,null,null);
return d;
}
And the Utilities snippet where I keep the ManageSpinner stuff:
public class Utilities {
static public void ManageTermSpinner(Context context, Spinner view) {
DatabaseHelper dbHelper = new DatabaseHelper(context);
Cursor c = dbHelper.getAllTerms();
SimpleCursorAdapter ca = new SimpleCursorAdapter(context, R.layout.termspinnerrow, c, new String[]{DatabaseHelper.colTermsClass, "_id"}, new int[]{R.id.txtTermClass});
view.setAdapter(ca);
}
static public void ManageStatSpinner(Context context, Spinner view) {
DatabaseHelper dbHelper = new DatabaseHelper(context);
Cursor d = dbHelper.getAllStatus();
SimpleCursorAdapter da = new SimpleCursorAdapter(context,R.layout.statspinnerrow, d, new String[]{DatabaseHelper.colStatClass,"_id"}, new int[]{R.id.txtStatClass});
view.setAdapter(da);
}
This is how you need to do it:
public Cursor getAccByTermsAndStatus(String Terms, String status)
{
SQLiteDatabase db=this.getReadableDatabase();
String [] columns=new String[]{"_id",colName,colAmount,colPurpose,colTermsClass,colDate,colEditDate,colStatClass};
Cursor c=db.query(viewAccs, columns, colTermsClass+"=? AND " + colStatClass + "=?", new String[]{Terms, status}, null, null, null);
return c;
}
I wish to store it in arraylist and then display it out in listView. Is there any solution to it ? how do I set the adapter? how can I link this two up and display it into a listview using arrayList?
DBhelper.java
public ArrayList<String> getDataarray(){
SQLiteQueryBuilder querybuilder=new SQLiteQueryBuilder();
querybuilder.setTables(DATABASE_TABLES);
String [] columns= new String[]{ KEY_ROWID,KEY_USERNAME,KEY_AGE,KEY_ClINIC,KEY_PHONE,KEY_EMAIL,KEY_DATESIGNUP
,KEY_CONDITIONID,KEY_DOCTORID,KEY_LOGINID,KEY_ACTIVITYNAME,KEY_NOTIFICATIONNAME,KEY_GROUPNAME,KEY_APPROVED
};
Cursor c= ourdatabase.query(DATABASE_TABLES, columns, null,null, null, null, null);
String result="";
ArrayList<String> resultarray = new ArrayList<String>();
int iRow=c.getColumnIndex(KEY_ROWID);
int iUserName=c.getColumnIndex(KEY_USERNAME);
int iAge=c.getColumnIndex(KEY_AGE);
int iClinic=c.getColumnIndex(KEY_ClINIC);
int iPhone=c.getColumnIndex(KEY_PHONE);
int iEmail=c.getColumnIndex(KEY_EMAIL);
int iDateSignup=c.getColumnIndex(KEY_DATESIGNUP);
int iConditionID=c.getColumnIndex(KEY_CONDITIONID);
int iDoctorID=c.getColumnIndex(KEY_DOCTORID);
int iLoginID=c.getColumnIndex(KEY_LOGINID);
int iActivityName=c.getColumnIndex(KEY_ACTIVITYNAME);
int iNotificationName=c.getColumnIndex(KEY_NOTIFICATIONNAME);
int iGroupName=c.getColumnIndex(KEY_GROUPNAME);
int iApproved=c.getColumnIndex(KEY_APPROVED);
SQLiteDatabase db = this.getReadableDatabase();
Cursor cursor = db.rawQuery("SELECT value FROM " + DATABASE_TABLES, null);
if(cursor.moveToFirst()) {
do {
resultarray.add(cursor.getString(cursor.getColumnIndex("value")));
}while(cursor.moveToNext());
}
cursor.close();
db.close();
return resultarray;
}
ProfileFragment.java this is the page where i want to retrieve out at the listView how can i retrieve it from the database instead of array
public View getView( int position ,View convertView,ViewGroup parent){
LayoutInflater inflater= (LayoutInflater) context.getSystemService(android.content.Context.LAYOUT_INFLATER_SERVICE);
View row =inflater.inflate(R.layout.profile_list,parent,false);
TextView myProfile=(TextView)row.findViewById(R.id.Profile);
TextView myCondition=(TextView)row.findViewById(R.id.condition);
myProfile.setText(ProfileArray[position]);
myCondition.setText(resultarray[position]);
return row;
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootview = inflater.inflate(R.layout.user,container,false);
Resources res=getResources();
Profile=res.getStringArray(R.array.Profile);
//how can i change the line below to let it get the data from the database array? or is there any other method?
condition=res.getStringArray(R.array.Profile_values);
list.setAdapter(adapter);
list=(ListView)rootview.findViewById(R.id.listView1);
return rootview;
}
Do you want to display all of data?
Think about using CursorLoader with SimpleCursorAdapter. It will load your data once activity is created in background. And in your activity class just implement interface LoaderManager.LoaderCallback, and in onCreate you simply initialize Loader with getSupportLoaderManager().initLoader(LOADER_ID, null, this)
Here is the link with good example http://www.androiddesignpatterns.com/2012/07/understanding-loadermanager.html
EDIT:
This code use in onCreate
// init DB
db = new DB(this);
db.open();
// forming columns from DB to views
String[] from = new String[] { KEY_ROWID, KEY_USERNAME, KEY_AGE...}; //array of columns from DB
int[] to = new int[] { R.id.textviewId, R.id.textviewUserName, R.id.textviewAge }; //Array of of view components
// create adapter
scAdapter = new SimpleCursorAdapter(this, R.layout.item, null, from, to, 0);
ListView lvData = (ListView) findViewById(R.id.lvData); // listview where you want to display data
lvData.setAdapter(scAdapter);
//init loader
getSupportLoaderManager().initLoader(0, null, this);
//implement these mothods with interface `LoaderManager.LoaderCallback<Cursor>`
#Override
public Loader<Cursor> onCreateLoader(int id, Bundle bndl) {
return new MyCursorLoader(this, db);
}
#Override
public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
scAdapter.swapCursor(cursor);
}
#Override
public void onLoaderReset(Loader<Cursor> loader) {
}
This code must works for you.
EDIT2
static class MyCursorLoader extends CursorLoader {
DB db;
public MyCursorLoader(Context context, DB db) {
super(context);
this.db = db;
}
#Override
public Cursor loadInBackground() {
return db.getAllData();
}
}
One detail added. This is a class where you download your data from db and return filled cursor.
My ListView currently is able to display only one column data. I want it to display two column data.
Here is the code for my ListView:
public class ProjectExplorer extends ListActivity {
private projectdatabase database;
protected Cursor cursor;
protected ListAdapter adapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
database = new projectdatabase(ProjectExplorer.this);
getinfo();
}
private void getinfo() {
database.open();
cursor = database.getDataforDisplay();
adapter = new SimpleCursorAdapter(this, android.R.layout.simple_list_item_1, cursor, new String[] {"project_name"}, new int[] { android.R.id.text1 }, 0);
setListAdapter(adapter);
}
#Override
public void onListItemClick(ListView parent, View view, int position, long id) {
super.onListItemClick(parent, view, position, id);
Cursor c = ((SimpleCursorAdapter)parent.getAdapter()).getCursor();
c.moveToPosition(position);
// get project name here
String str_projectname= c.getString(c.getColumnIndex("project_name"));
Toast.makeText(this, str_projectname, Toast.LENGTH_LONG).show();
}
Here is the method in database class which return the cursor:
public Cursor getDataforDisplay () {
String[] columns = new String[] {KEY_ROWID, PROJECT_NAME, PROJECT_FINISH_DATE, PROJECT_DIFFICULTY, PROJECT_STATUS};
Cursor c = projectDatabase.query(DATABASE_TABLE, columns, null, null, null, null, null);
projectDatabase.query(DATABASE_TABLE, columns, null, null, null, null, null);
c.moveToFirst();
return c;
}
I also want to display KEY_ROWID which is defined as _id
You can use android.R.layout.simple_list_item_2 specifying column no.2 from table from where data can be retrieved and specifies location with help of it can be displayed on Activity - android.R.id.text2
adapter = new SimpleCursorAdapter(this, android.R.layout.simple_list_item_2, cursor, new String[] {"project_name","column_no2"}, new int[] { android.R.id.text1, andriod.R.id.text2 }, 0);
You can also create your on custom Adapter specifying your own Listview and creating it from scratch and customized everything.
The best way to achieve this at least in my opinion is to create custom Adapter for your ListView in that case you can set your own design how single listview element should look like . Just populate some arrays using your Cursor and set them to your custom adapter.
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'