I have one problem with my application.
I create a one AsyncTask for downloading list of files from server . When all the files are download after that i update the database. But when i called the update query its give me the below error.
Failure 21 (out of memory) on 0x0 when
preparing update
Can any one tell me why this error occurs ?
Sample Code
public void setStatus(int index)
{
try
{
db.OpenDatabase();
db.updateStatus(id.get(index), 1);
db.closeDatabase();
}
catch(Exception e)
{
e.printStackTrace();
}
}
Above function called from the AsyncTask ....
public void updateStatus(int id,int status)
{
try
{
db.execSQL("update sample set status =" + status + " where id = " + id);
}
catch(Exception e){e.printStackTrace();}
}
This may not be related to the database pe se, but rather to the fact that the memory (heap) is almost full and opening the database completely fills it up.
Remember that most handsets have 48MB of heap or even less.
Sometime while working I also got the same error.
I used this link
"Failure 21 (out of memory)" when performing some SQLite operations
It said that this error occurs when you try to work on a closed DB.
I looked back into my code and found that I was also doing the same. Got it working afterwards
I think you are also trying to work on a closed DB.
Have you tried to use the update() method instead of execSQL()?
public void updateStatus(int id,int status)
{
try
{
ContentValues values = new ContentValues();
values.put("status", status);
db.update ("sample", values, "id = ?", new String[]{Integer.toString(id)});
}
catch(Exception e){e.printStackTrace();}
}
I has "out of memory" error (21) when I try to call sqlite3_prepare() with a NULL pointer to database handle.
Check if your handle is valid and the database is opened.
Related
I have spent the day reading through various articles, but I can't seem to find an answer to my problem. Months ago, I created an app in android studio that uses SQLite. Now, I have gotten to the point that I need to add a column to the table. I am able to add the column in the adapter class with no problem, but I am having a problem in the 'MainActivity.class'. The code is as follows...
private void setData() {
new Thread(new Runnable() {
#Override
public void run() {
for (int i = 0; i <= 0; i++) {
dbAdapter.insertSpace(String.valueOf(i+1),"Confined Space " + (i+1),"description "+(i+1),"","","","","","","","","","",
"","","","","","","","","","","","","","","","",
"","","","");
}
try {
// Execute insert function
} catch (SQLiteConstraintException e) {
Toast.makeText(context, "Error inserting record", Toast.LENGTH_SHORT).show();
}
}
}).start();
}
}
and the error message I am getting is...
error: method insertSpace in class DBAdapter cannot be applied to given types;
required: String,String,String,String,String,String,String,String,String,String,String,String,String,String,String,String,String,String,String,String,String,String,String,String,String,String,String,String,String,String,String,String,String,String
found: String,String,String,String,String,String,String,String,String,String,String,String,String,String,String,String,String,String,String,String,String,String,String,String,String,String,String,String,String,String,String,String,String
reason: actual and formal argument lists differ in length
My required content shows 34 columns, and found is 33. What do I need to do to make these equal, and where do I need to make the adjustments? I added a column once before, but just can't remember how I did it :(
I am sorry all. This was entirely my own mess-up. I had only changed the structure of the add query... I had neglected to make the same changes to my update, and my listview. Every call to the database in the app needed to be edited, not jus.t the add record
Im making a login and register system and if need to check if the user already exits so I wrote this function in my database handler to check it.
public boolean checkIfUserExits(String username){
SQLiteDatabase db = this.getWritableDatabase();
String query = "SELECT * FROM " + TABLE_NAME + " WHERE username=" + "\"" + username + "\"";
Cursor cursor = db.rawQuery(query, null);
if(cursor.getCount() <= 0){
cursor.close();
return false;
}
cursor.close();
return true;
}
But the problem if that i always getting a true.
Thanks for help.
Well, it does exist:
From the other function you posted (it can be accessed in the revision history, so double check before posting stuff, as it will stay around even if you edit it away).
user = new User(username, password, email);
dbHandler.createUser(user);
if(dbHandler.checkIfUserExits(username) == true){
You can just remove the == true, that's redundant. Anyway, you create the user, then you check whether it exists. Of course it does, you just created it.
The easy but wrong fix would be to check first, then create the user. Unfortunately, if for some reason two programs do this at the same time, it is very possible they both see the user doesn't exist, and both proceed.
What you probably want to do here would be to try creating the user no matter what, then check whether it worked or not. I dont't know this environment, but for sure you should be able to detect integrity constraint violations.
It's posible that your cursor is null and can't count members... My app uses a similar method but it's more complet and can control errors more good.
Why I pass the complet query? It's simple it's a general method, for a general class. With this you can use this method for all calls and don't need to create a new methods for differents calls... If you need this one for one query, then includes inside how your question.
You can see the code below:
public boolean exists_the_ColumnParameter(String query){
//Declaration of variables
Cursor a3 = null;
try{
a3 = database.rawQuery(query,null);
a3.moveToFirst();
if(a3.getString(0).equals("")){
a3.close();
return false;
}
else{
a3.close();
return true;
}
}
catch (CursorIndexOutOfBoundsException ex){
return false;
} catch (Exception ex){
Log.e("-- BDD.exists_the_ColumnParameter --","Exception",ex);
return false;
}
}
Tell me if I helped you and good programming!
This is my first Application with database, I hope that someone can help me to understand this problem. I have this insert method:
public long insertData(String name, int password){
....
contentValues.put(KEY_NAME, name);
contentValues.put(KEY_PASSWORD, password);
return db.insert(DBHelper.TABle_NAME, null, contentValues);
}
I can insert few data with this method, but what about if I have thousands of rows? how can I insert all these data into database? where can I write all these data, in extra class or what?
As others have said, you'll need to do some sort of iteration.
Efficiency can be gained by performing a bulk transaction. Here's an example:
public int bulkInsert(#NonNull ContentValues[] values) {
int insertCount = 0;
SQLiteDatabase db = mSqlHelper.getWritableDatabase();
try {
db.beginTransaction();
for (ContentValues value : values) {
if (db.insertOrThrow(tableName, null, value) == -1) {
throw new Exception("Unknown error while inserting entry in database.");
}
insertCount++;
}
db.setTransactionSuccessful();
} catch (Exception e) {
Log.e(LOG_TAG, "An error occurred while bulk-inserting database entries.\n" + e.getMessage(), e);
} finally {
db.endTransaction();
}
return insertCount;
}
There is no 'bulk load' facility that I'm aware of.
You'd just have to spin through the list, and insert the items.
You might want to think about why you're potentially trying to insert thousands of items into a database on a hardware-limited device like a phone or a tablet.
Might it be better to put the data on a server, and create an API that you can use to load data (for display) by pages?
you can do it the same way, that you do with few data, you only need to catch the thousands rows to insert into your database using your method, you can use asyntask, or a service to do that
You can use the same method to insert any amount of records, whether it's 1 or 1,000. Use a loop to call your insert method and add your records to your database. Consider putting your database executions in an AsyncTask to prevent your UI thread from hanging.
Your data can come from anywhere, as long as it's formatted to fit your function parameters String, int
I am working on an Android App and have a class where user can update his "choices". This is from a Dialog Box which appears when a user installs the app, BUT he can also access it later on via overflow. At the startup, according to the choices by user, I upload a class, NCUP.class on Parse.com. But when user clicks on overflow icon to change preferences, I want to "refresh" the table by deleting ALL the previous records and adding new ones. I was previously using SQLite database and I just used
database.delete(MySQLiteHelper.TABLE_NCUP, null, null);
Now, I can think 3 ways:
(Currently doing) As soon as the user clicks "Done" after selecting his pref, I delete all the objects in the table by below code, but this is taking upto 5 seconds for a class with 13 entries.:
DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
Date date = new Date();
String current = dateFormat.format(date);
ParseQuery<NCUP> query = ParseQuery.getQuery(NCUP.class);
query.equals("objectId");
// query.whereLessThan("createdAt", date);
query.findInBackground(new FindCallback<NCUP>() {
#Override
public void done(List<NCUP> ncupList, ParseException e) {
if (e == null) {
Log.d("QUERY", "Retrieved " + ncupList.size() + " data");
Log.d("QUERY", ncupList.get(1).getCreatedAt().toString());
for (NCUP ncup : ncupList) {
try {
ncup.delete();
} catch (ParseException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
} else {
Log.d("QUERY", "Error: " + e.getMessage());
}
}
});
Get the query by using the line that I have commented above i.e by using current date and adding to query whereLessThan to get and delete older items. But this doesnt work, returns ncupList.size() as 0. Tried different formatting but none helped.
Drop the whole NCUP class and make a new one. I tried to search for this method for it seems to me fastest, but I think I can not do it programatically.
Any suggestions?
The problem might be that you are using ncup.delete(), which is executing an http request on the main thread.
Replace with ncup.deleteInBackground() and your UI won't block.
Also look into ParseObject.deleteAllInBackground(List<ParseObject> objects, DeleteCallback callback) which would seem to do what you need (deleting a list of ParseObjects)
I have a routine that runs different queries against an SQLite database many times per second. After a while I would get the error
"android.database.CursorWindowAllocationException: - Cursor window allocation of 2048 kb failed. # Open Cursors = " appear in LogCat.
I had the app log memory usage, and indeed when usage reaches a certain limit the I get this error, implying it runs out. My intuition tells me that the database engine is creating a NEW buffer (CursorWindow) every time I run a query, and even though .close() the cursors, neither the garbage collector nor SQLiteDatabase.releaseMemory() are quick enough at freeing memory. I think the solution may lie in "forcing" the database to always write into the same buffer, and not create new ones, but I have been unable to find a way to do this. I have tried instantiating my own CursorWindow, and tried setting SQLiteCursor to it, but to no avail.
¿Any ideas?
EDIT: re example code request from #GrahamBorland:
public static CursorWindow cursorWindow = new CursorWindow("cursorWindow");
public static SQLiteCursor sqlCursor;
public static void getItemsVisibleArea(GeoPoint mapCenter, int latSpan, int lonSpan) {
query = "SELECT * FROM Items"; //would be more complex in real code
sqlCursor = (SQLiteCursor)db.rawQuery(query, null);
sqlCursor.setWindow(cursorWindow);
}
Ideally I would like to be able to .setWindow() before giving a new query, and have the data put into the same CursorWindow everytime I get new data.
Most often the cause for this error are non closed cursors. Make sure you close all cursors after using them (even in the case of an error).
Cursor cursor = null;
try {
cursor = db.query(...
// do some work with the cursor here.
} finally {
// this gets called even if there is an exception somewhere above
if(cursor != null)
cursor.close();
}
To make your App crash when you are not closing a cursor you can enable Strict Mode with detectLeakedSqlLiteObjects in your Applications onCreate:
StrictMode.VmPolicy policy = new StrictMode.VmPolicy.Builder()
.detectLeakedClosableObjects()
.detectLeakedSqlLiteObjects()
.penaltyDeath()
.penaltyLog()
.build();
StrictMode.setVmPolicy(policy);
Obviously you would only enable this for debug builds.
If you're having to dig through a significant amount of SQL code you may be able to speed up your debugging by putting the following code snippet in your MainActivity to enable StrictMode. If leaked database objects are detected then your app will now crash with log info highlighting exactly where your leak is. This helped me locate a rogue cursor in a matter of minutes.
#Override
protected void onCreate(Bundle savedInstanceState) {
if (BuildConfig.DEBUG) {
StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
.detectLeakedSqlLiteObjects()
.detectLeakedClosableObjects()
.penaltyLog()
.penaltyDeath()
.build());
}
super.onCreate(savedInstanceState);
...
...
I have just experienced this issue - and the the suggested answer of not closing the cursor while valid, was not how I fixed it. My issue was closing the database when SQLite was trying to repopulate it's cursor. I would open the database, query the database to get a cursor to a data set, close the database and iterate over the cursor. I noticed whenever I hit a certain record in that cursor, my app would crash with this same error in OP.
I assume that for the cursor to access certain records, it needs to re-query the database and if it is closed, it will throw this error. I fixed it by not closing the database until I had completed all the work I needed.
There is indeed a maximum size Android SQLite cursor windows can take and that is 2MB, anything more than this size would result into the above error. Mostly, this error is either caused by a large image byte array stored as blob in sql database or too long strings. Here is how i fixed it.
Create a java class eg. FixCursorWindow and put below code in it.
public static void fix() {
try {
Field field = CursorWindow.class.getDeclaredField("sCursorWindowSize");
field.setAccessible(true);
field.set(null, 102400 * 1024); //the 102400 is the new size added
} catch (Exception e) {
e.printStackTrace();
}
}
Now go to your application class (create one if you don't have already) and make a call to the FixCursorWindow like this
public class App extends Application {
public void onCreate()
{
super.onCreate();
CursorWindowFixer.fix();
}
}
Finally, ensure you include your application class in your manifest on the application tag like this
android:name=".App">
That's all, it should work perfectly now.
If you're running Android P, you can create your own cursor window like this:
if(cursor instanceof SQLiteCursor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
((SQLiteCursor) cursor).setWindow(new CursorWindow(null, 1024*1024*10));
}
This allows you to modify the cursor window size for a specific cursor without resorting to reflections.
Here is #whlk answer with Java 7 automatic resource management of try-finally block:
try (Cursor cursor = db.query(...)) {
// do some work with the cursor here.
}
This is a Normal Exception while we are using External SQLite especially. You can resolve it by closing the Cursor Object just like as follow:
if(myCursor != null)
myCursor.close();
What it means is, IF the cursor has memory and it's opened then close it so the Application will be faster, all the Methods will take less space, and the functionalities related to the Database will also be improved.
public class CursorWindowFixer {
public static void fix() {
try {
Field field = CursorWindow.class.getDeclaredField("sCursorWindowSize");
field.setAccessible(true);
field.set(null, 102400 * 1024);
} catch (Exception e) {
e.printStackTrace();
}
}
}