开发者

Android SQLite query crashing when it takes too long?

I have an SQLite query in my android app that seems to crash when it takes too long to execute. It crashes with NullPointerException and tells me the line number...

When I put breakpoints around that line and see that it always gets filled with a variable, the app does not crash and does what it is supposed to.

So aside from having a phantom null pointer, it appears the problem is that the breakpoints actually slow things down giving the query time to complete. Without breakpoints it always crashes without fail.

Others here seem to have a similar problem, and I've read some things about SQLite taking an erratic amount of time to complete tasks, but this table should only ever ha开发者_JAVA技巧ve a few entries in it (the one I'm testing should only have three entries, 4 columns)

Suggestions on how to make it not crash? Perhaps put a thread wait inside the method that makes the query?

 public void fetchItemsToRemove() throws SQLException{
    Cursor mCursor =
            mapDb.query(myMain_TABLE, new String[] {myOtherId, myCustomID, myDATE}, null, null, null, null, null);

    if(mCursor.moveToFirst())
    {
            do
            {
                /*taking "dates" that were stored as plain text strings, and converting them to 
                *Date objects in a particular format for comparison*/

                String DateCompareOld = mCursor.getString(mCursor.getColumnIndex(myDATE));
                String DateCompareCurrent = "";
                Date newDate = new Date();
                DateCompareCurrent = newDate.toString();

                try {
                    DateCompareOld = (String)DateCompareOld.subSequence(0, 10);
                    DateCompareCurrent = (String)DateCompareCurrent.subSequence(0, 10);
                    SimpleDateFormat dateType =  new SimpleDateFormat("EEE MMM dd");
                    Date convertDate = dateType.parse(DateCompareOld);

                    newDate = dateType.parse(DateCompareCurrent);

                    if(convertDate.compareTo(newDate) < 0)
                    {
                        //remove unlim id
                        mapDb.delete(myMain_TABLE, myDATE + "=" + mCursor.getString(mCursor.getColumnIndex(myDATE)), null);

                    }

                } catch (ParseException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }while(mCursor.moveToNext());
            mCursor.close();
    }
    else
    {
        mCursor.close();    
    }


}

Now "line 342" where it crashes with NullPointerException is DateCompareOld = (String)DateCompareOld.subSequence(0, 10); where it gets a subsequence of the string. If it gets here and is null, this means the string was never filled at String DateCompareOld = mCursor.getString(mCursor.getColumnIndex(myDATE));

as if the query just got skipped because it took too long. Do note this is in a while loop, and I have done tests to make sure that the mCursor never goes out of bounds.


You're deleting things from a DB table whilst iterating over the results of a query from that table. Sounds a bit dangerous.

Try building a list, inside the loop, of things to be deleted, and then delete them in a single go after the loop finishes.

Also, wrap the entire thing in a DB transaction. When you're modifying the DB in a loop, that can make a huge difference to performance.

EDIT: a quick explanation of transactions:

A transaction allows you to combine a bunch of DB queries/modifications into a single atomic operation which either succeeds or fails. It's primarily a safety mechanism so your DB isn't stuck in an inconsistent state if something goes wrong half way through, but it also means that any modifications are committed to the DB's file storage in a single shot rather than one at a time, which is much faster.

You start the transaction at the start of your function:

public void fetchItemsToRemove() throws SQLException{
    db.beginTransaction();
    Cursor mCursor = ....

You set it as successful if the whole function completes without errors. This probably means you want to remove the inner try/catch and have an outer try/catch enclosing the loop. Then at the end of the try{ }, you can assume nothing's gone wrong, so you call:

db.setTransactionSuccessful(); 

Then, in a finally clause, to make sure you always close the transaction whether it's successful or otherwise:

db.endTransaction();
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜