This question already has an answer here:
attempt to re-open an already-closed object: SQLiteDatabase
(1 answer)
Closed 8 years ago.
I know there are several questions like this one, but all of them seem to have a different approach to solve the problem and none have solved mine.
I have my main activity working just fine, loading the db and populating the listview. Then I call a second activity and the problem shows up when I try to load the listview.
I have tried using start/stop managingcursor(cursor) even though it is deprecated, but it didn't fix the problem. Also I tried cloasing the cursor and db in my main activity before firing the next one but that didn't help either.
Both classes extend from ListActivity and follow the same sequence:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//Open db in writing mode
MySQLiteHelper.init(this);
MySQLiteHelper tpdbh =
new MySQLiteHelper(this, "DB", null, 1);
SQLiteDatabase db = tpdbh.getWritableDatabase();
checkLocationAndDownloadData(); //this fires a Asynctask that calls method parseNearbyBranches shown bellow
//I load the data to the ListView in the postExecute method of the asynctask by calling:
/*
Cursor cursor = MysSQLiteHelper.getBranchesNames();
adapter = new SimpleCursorAdapter(this,
R.layout.row, cursor, fields, new int[] { R.id.item_text },0);
setListAdapter(adapter);
*/
ListView lv = getListView();
lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> listView, View view,
int position, long id) {
// Get the cursor, positioned to the corresponding row in the result set
Cursor cursor = (Cursor) listView.getItemAtPosition(position);
// Get the state's capital from this row in the database.
String branch_id = cursor.getString(cursor.getColumnIndexOrThrow("branch_id"));
cursor.close();
openNextActivity(Integer.parseInt(branch_id));
}
});
}
//In another file:
private void parseNearbyBranches(JSONObject jo) throws JSONException
{
if ( jo.has(jsonTitle) &&
jo.has("company_id") &&
jo.has("id")
) {
String branch = jo.getString(jsonTitle);
MySQLiteHelper tpdbh = MySQLiteHelper.instance;
SQLiteDatabase db = tpdbh.getWritableDatabase();
db.execSQL("INSERT INTO Branches (branch_id, name, company_id) " +
"VALUES ('" +jo.getInt("id")+"', '" + branch +"', '" +jo.getInt("company_id")+"' )");
db.close(); //no difference is I comment or uncomment this line
}
}
In MySQLiteHelper.java:
public static Cursor getBranchesNames() {
// TODO Auto-generated method stub
String[] columns = new String[] { "_id", "branch_id", "name", "company_id" };
Cursor c = getReadDb().query(branchesTable, columns, null, null, null, null,
null);
return c;
}
My other activity does basically the same:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_branch_surveys);
//Read branch data from DB
int companyID = -1;
MySQLiteHelper.init(this);
String [] columns = new String [] {"company_id"};
String [] args = {Integer.toString(branchID)};
Cursor c = MySQLiteHelper.getReadDb().query(MySQLiteHelper.branchesTable, columns, "branch_id=?", args, null, null, null); //THIS QUERY WORKS JUST FINE
if (c.moveToFirst())
companyID = Integer.parseInt(c.getString(0));
c.close();
if( companyID != -1)
{
new DownloadTask().execute(Integer.toString(companyID) );
//where the Async task calls something just like NearByBranches shown above(but with different objects of course)
//And the postExecute sets the listView:
/* cursor = MySQLiteHelper.getAll();
SimpleCursorAdapter adapter = new SimpleCursorAdapter(this,
R.layout.row, cursor, fields, new int[] { R.id.item_text },0);
setListAdapter(adapter);
*/
}
}
}
In MySQLiteHelper.java:
public static Cursor getAll() {
// TODO Auto-generated method stub
String[] columns = new String[] { "_id","title", "points" };
//********IT IS IN THIS LINE WHERE I GET THE ERROR:********************
Cursor c = getReadDb().query(theTable, columns, null, null, null, null,
null);
return c;
}
public static SQLiteDatabase getReadDb() {
if (null == db) {
db = instance.getReadableDatabase();
}
return db;
}
I hope you can help me out. Thanks!
I just tried commenting the db.close in the similar method of parseNeabyBranches and the problem was solved. Yet I dont get the same error having db.close() in parseNearbyBranches(), can you explain me why?
In parseNearbyBranches() you create a separate SQLiteDatabase object with:
SQLiteDatabase db = tpdbh.getWritableDatabase();
Since this is a different object than the one returned by getReadDb(), you can (and should) close it. The basic rule is each time you call getWritableDatabase() and getReadableDatable() you must have a matching close() statement.
Related
I have build an app that take data with different attribute, adds them in the database and then shows it through a ListView.
I have done the part where data are added, but I Can't figure out how to fetch it(for now I just want the name) from the database and populate it in the ListView.
Here is the part in the database class.
public Cursor getCursor() {
Cursor c = null;
sqLiteDatabase = this.getReadableDatabase();
String query = "SELECT * FROM tbl_customer";
String where = null;
c = sqLiteDatabase.query("tbl_customer", new String[]{"Name"}, where, null, null, null, null);
if (c != null) {
c.moveToFirst();
}
return c;
}
here is the part of code in activity which I want to show the ListView in.
private void populateListView(){
Cursor cursor = db.getCursor();
String []From = new String[]{"Name"};
int [] to = new int[R.id.textView];
SimpleCursorAdapter adapter;
adapter = new SimpleCursorAdapter(this,R.layout.listview_items,cursor,From,to,0);
ListView listView = (ListView)findViewById(R.id.ShowDataListView);
listView.setAdapter(adapter);
}
Please guide me, where I have gone wrong, and correct me.
you are using R.id.textView as a size of array
int [] to = new int[R.id.textView];
it should be like this
int [] to = new int[]{R.id.textView};
You've to specify the From and To params of the SimpleCursorAdapter.
adapter = new SimpleCursorAdapter(this,R.layout.listview_items,cursor,
new String[] { "Name" },to,0);
As for to, you need to put the id of your textview from R.layout.listview_items. Let's assume the id of your TextView is R.id.text1 then the adapter will look like following,
adapter = new SimpleCursorAdapter(this,R.layout.listview_items,cursor,
new String[] { "Name" },
new int[] { android.R.id.text1 },
0);
Here, have a look at the documentation to grasp it more clearly.
I have a listview with a problem. I want to implement the classic search with the edittext, i am using the addTextChangedListener with TextWatcher(). The Listview gets the elements from a database so I use cursor and simplecursoradapter so i have to use the setFilterQueryProvider. The problem appears when I write something in the edittext, if I write the name of a product it changes all the names of the elements in the list.So i dont know what to do. Appreciate the help.
here is my java code with the listview:
public class Lista_general extends ListActivity {
SimpleCursorAdapter adapter;
ListView list;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.lista_general);
list = getListView();
EditText edit =(EditText)findViewById(R.id.edit);
// open database
AdminSQLiteOpenHelper dbhelper = new AdminSQLiteOpenHelper(
getBaseContext());
SQLiteDatabase db = dbhelper.getReadableDatabase();
// array for SimpleCursorAdapter
String columns[] = new String[] { "PRODUCTO._id",
"nombre","category","CATEGORIAS._id","categoryid" };
String orderBy = "category";
// query database
Cursor c = db.query("PRODUCTO, CATEGORIAS WHERE CATEGORIAS._id = categoryid ",
columns,null,null, null, null, orderBy);
c.moveToFirst();
// array for SimpleCursorAdapter
String from[] = new String[] { "nombre", "category", };
//String from[] = new String[] { "nombre", "categoria", };
int to[] = new int[] { R.id.name, R.id.cate, };
// Adapter
adapter = new SimpleCursorAdapter(getBaseContext(),
R.layout.productos, c, from, to,
SimpleCursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER);
setListAdapter(adapter);
list.setTextFilterEnabled(true);
//Listener edit text
edit.addTextChangedListener(new TextWatcher() {
#Override
public void onTextChanged(CharSequence s, int start, int before,
int count) {
}
#Override
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
}
#Override
public void afterTextChanged(Editable s) {
adapter.getFilter().filter(s.toString());
}
});
adapter.setFilterQueryProvider(new FilterQueryProvider() {
#Override
public Cursor runQuery(CharSequence constraint) {
// TODO Auto-generated method stub
AdminSQLiteOpenHelper dbhelper = new AdminSQLiteOpenHelper(
getBaseContext());
SQLiteDatabase db = dbhelper.getReadableDatabase();
Cursor mCursor = null;
if (constraint == null || constraint.length () == 0) {
mCursor = db.query("PRODUCTO, CATEGORIAS", new String[] {
"PRODUCTO._id", "nombre","CATEGORIAS._id","category"},
null, null, null, null, null);
}
else {
mCursor = db.query(true,"PRODUCTO, CATEGORIAS", new String[]
{"PRODUCTO._id", "nombre", "category","CATEGORIAS._id"},
"nombre" + " like '%" + constraint + "%'", null,
null, null, null, null);
}
if (mCursor != null) {
mCursor.moveToFirst();
}
return mCursor;
}
});
}
Here is a visual of my error:
first my normal list:
http://i40.tinypic.com/2111k0p.png
after I wrote:
http://i44.tinypic.com/23j04kg.png
It looks like the queries generated in the FilterQueryProvider are not joining the tables properly, so that you end up with every possible combination of PRODUCTO and CATEGORIAS (which are then filtered by PRODUCTO.nombre to give the impression that all the names have changed).
There's also a potential security risk with inserting constraint directly into the query, this opens the door to SQL injection attacks. I'm not sure how serious this is in the context of Android apps, but in for example a PHP web application this would allow anyone to execute any SQL they wished by entering a carefully crafted constraint.
From the answers to this question it looks like a rawQuery() call is needed in order to use SQL JOIN so I would change your queries as follows...
For querying with no filter (i.e. in onCreate(); and in runQuery() where there is no constraint):
cursor = db.rawQuery("SELECT PRODUCTO._id, nombre, category, CATEGORIAS._id FROM PRODUCTO INNER JOIN CATEGORIAS ON PRODUCTO.categoryid = CATEGORIAS._id", null);
For querying with a filter:
String[] params = { constraint.toString() };
cursor = db.rawQuery("SELECT PRODUCTO._id, nombre, category, CATEGORIAS._id FROM PRODUCTO INNER JOIN CATEGORIAS ON PRODUCTO.categoryid = CATEGORIAS._id WHERE nombre LIKE ('%' || ? || '%')", params);
How to retrieve rows from external database and display them in text view??
i have tried some codes but the application stopped.
In my database helper i added that code :
public String[] getData(String l) {
// TODO Auto-generated method stub
String[] columns = new String[] { DB_ID, DB_name, DB_desc };
// FILTERS DEPENDING ON THE CATEGORY TYPE PASSED IN THE PARAMETER
Cursor c = mDataBase.rawQuery("SELECT _id,name,description FROM facilities WHERE name='" + l + "'", null);
String[] result = new String[] { null, null, null, null, null };
int iId = c.getColumnIndex(DB_ID);
int iName = c.getColumnIndex(DB_name);
int iDesc = c.getColumnIndex(DB_desc);
c.moveToFirst();
result[0] = c.getString(iId);
result[1] = c.getString(iName);
result[2] = c.getString(iDesc);
return result;
}
And this code in my activity which i wish to display the string in textview:
for(int i=0;i<4;i++){
// dbhelper.open();
String[] data =dbhelper.getData(namee);
// dbhelper.close();
txt.append("\n"+data[3]+"\n");}
}
This is another code i tried it, from this url :
Return all data from a SQLite DB into two columns in Android
Can you post the LogCat entries?
What does this line do?
String[] result=new String[]{null,null,null,null,null};
Try
String[] result = new String[5];
instead;
I used this in one of my app.... This may help.
I declared the following in the main activity itself
DatabaseHelper myDbHelper = new DatabaseHelper(this);
.
.
try {
myDbHelper.createDataBase();
}
.
.
.
db = myDbHelper.getWritableDatabase();// or db = myDbHelper.getReadableDatabase();
.
.
.
//In another function
Cursor c = db.rawQuery("Whatever you want to query");
String[] s=new String[]{"The fields(columns) you want queried and used in textbox"};
I am trying to populate the ListFragment from one of the columns in my Database.
For that i am trying to use
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
db.open();
db = new NotesDatabase(getActivity());
c = db.getAllRows();
getActivity().startManagingCursor(c);
String[] fromField = new String[] { NotesDatabase.KEY_TITLE };
int[] toView = new int[] { R.id.item_title };
SimpleCursorAdapter myCAdapter = new SimpleCursorAdapter(getActivity(),
R.layout.list_item, c, fromField, toView, 0);
setListAdapter(myCAdapter);
}
but i dont know why i am getting a NullPointerException on db.open(); and c = db.getAllRows();
db.open()
public NotesDatabase open() {
db = myDBHelper.getWritableDatabase();
return this;
}
db.getAllRows();
public Cursor getAllRows() {
String where = null;
Cursor c = db.query(true, DATABASE_TABLE, ALL_KEYS, where, null, null,
null, null, null);
if (c != null) {
c.moveToFirst();
}
return c;
}
DBHelper
private static class DatabaseHelper extends SQLiteOpenHelper {
DatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
or if there is a better a better way to populate the list view of fragment from a database?
Thanks in Advance :)
db.open();
db = new NotesDatabase(getActivity());
c = db.getAllRows();
Open the database
Create the database
Get all the rows.
Logically speaking. create it first. then open. then get all the rows. So swithc line 1 and lone 2.
Another thing is that , I assume your getting NPE at myDBHelper, because you never created that helper.
aren't you doing it reverse?
db.open();
db = new NotesDatabase(getActivity());
Just initialise your databasehelper before opening it:
db = new DatabaseHelper(this);
You are doing the db.open before the new so it doesn't exist yet, you are trying to open a null db.
I am trying to fetch rows from the database and make a list view from it.
This is by Query method inside the DbAdapter
public Cursor readInbox(long toId) throws SQLException {
return db.query(TABLE_MAILS, new String[] { ID, KEY_FROM, KEY_TO,
KEY_SUB, KEY_BODY, KEY_DATETIME, KEY_READ }, KEY_TO + "="
+ toId, null, null, null, null, null);
}
This is the code i am trying to write. but its giving error
public class InboxActivity extends ListActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.inbox);
DBAdapter db = new DBAdapter(InboxActivity.this);
db.open();
long userID = Long.parseLong(MessagingApplication.getUserID());
Cursor inbox = db.readInbox(userID);
startManagingCursor(inbox);
String[] Id = new String[] { DBAdapter.ID };
SimpleCursorAdapter inboxmail = new SimpleCursorAdapter(this, R.layout.list_view, db, Id, null);
setListAdapter(inboxmail);
db.close();
}
}
the Error:
The constructor SimpleCursorAdapter(InboxActivity, int, DBAdapter, String[], null) is undefined
This is a simple compilation error.
Have a look at the public constructors at http://developer.android.com/reference/android/widget/SimpleCursorAdapter.html :
SimpleCursorAdapter(Context context, int layout, Cursor c, String[] from, int[] to)
You're providing DBAdapter where you should be providing a Cursor. Most likely you should be passing the inbox variable instead of DBAdapter