简体   繁体   中英

Android ContentProvider SQLite : SQLiteMisuseException

I have a simple ContentProvider following the step from vogella.com with some changes because I'm using android-support-v4.jar I have a simple App

在此处输入图片说明

Here i have three buttons and one ListFragment all use custom ContentProvider the i'm looking for problems but when i try to pulse faster the buttons sometimes i get a SQLiteMisuseException the docs tell

This error can occur if the application creates a SQLiteStatement object and allows multiple threads in the application use it at the same time

but i dont have many threads (At least I think).

Update : sometimes the app stop working the UI work but does not respond

Update 2 : Can be a problem with the speed response of the device i'm testing in a Galaxy ACE (with the error) and a Galaxy SIII works fine


MainActivity.java

package com.example.providertest;

import java.util.Random;

import android.database.Cursor;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.ListFragment;
import android.support.v4.app.LoaderManager.LoaderCallbacks;
import android.support.v4.content.CursorLoader;
import android.support.v4.content.Loader;
import android.support.v4.widget.SimpleCursorAdapter;
import android.view.Menu;
import android.view.View;

public class MainActivity extends FragmentActivity {

    private List mLista;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mLista = (List) getSupportFragmentManager().findFragmentById(R.id.la_lista);

        getSupportLoaderManager().initLoader(0, null, mLista);
    }

    public static class List extends ListFragment implements LoaderCallbacks<Cursor>
    {
        private SimpleCursorAdapter mAdapter;

        @Override
        public void onCreate(Bundle savedInstanceState) {
            // TODO Auto-generated method stub
            super.onCreate(savedInstanceState);

            final String[] from = new String[] { CommentHelper.COLUMN_COMMENT };
            final int[] to = new int[] {android.R.id.text1 };

            mAdapter = new SimpleCursorAdapter(
                    getActivity().getApplicationContext(), R.layout.lista_item, null, from, to, 0);
            setListAdapter(mAdapter);

        }

        @Override
        public Loader<Cursor> onCreateLoader(int arg0, Bundle arg1) {
            final CursorLoader loader = new CursorLoader(
                    getActivity().getApplicationContext(),
                    CommentProvider.CONTENT_URI,
                    CommentDataSource.sAllColumns, null, null, null);

            return loader;
        }

        @Override
        public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
            mAdapter.swapCursor(cursor);
        }

        @Override
        public void onLoaderReset(Loader<Cursor> loader) {
            mAdapter.swapCursor(null);
        }

    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

    public void buttonPressed(View view)
    {
        final String[] comments = {"Excelente", "Bueno", "Que mas da", "Malo"};
        Comment comment = null;

        switch (view.getId()) {
        case R.id.add:
            comment = new Comment();
            final int nextInt = new Random().nextInt(comments.length);
            comment.setComment(comments[nextInt]);
            getContentResolver().insert(CommentProvider.CONTENT_URI, CommentDataSource.toValues(comment));
            break;
        case R.id.delete_first:
            deleteOne("ASC");
            break;
        case R.id.delete_last:
            deleteOne("DESC");
            break;
        }

    }

    private void deleteOne(String order) {
        final Cursor c = getContentResolver().query(CommentProvider.CONTENT_URI, null, null, null, "_ID " + order + " LIMIT 1");
        c.moveToFirst();
        if (!c.isAfterLast()) {
            final String _id = c.getString(c.getColumnIndexOrThrow(CommentHelper.COLUMN_ID));
            getContentResolver().delete(CommentProvider.CONTENT_URI, "_ID = ?", new String[] { _id });
        }
        c.close();
    }
}

activity_main.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:orientation="vertical"
    tools:context=".MainActivity" >

    <LinearLayout
        android:id="@+id/group"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content">

        <Button
            android:id="@+id/add"
            android:layout_width="0dp"
            android:layout_weight="1"
            android:layout_height="wrap_content"
            android:text="@string/add_new"
            android:onClick="buttonPressed" />

        <Button
            android:id="@+id/delete_first"
            android:layout_width="0dp"
            android:layout_weight="1"
            android:layout_height="wrap_content"
            android:text="@string/delete_first"
            android:onClick="buttonPressed" />

        <Button
            android:id="@+id/delete_last"
            android:layout_width="0dp"
            android:layout_weight="1"
            android:layout_height="wrap_content"
            android:onClick="buttonPressed"
            android:text="@string/delete_last" />
    </LinearLayout>

    <fragment
        android:id="@+id/la_lista"
        class="com.example.providertest.MainActivity$List"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
</LinearLayout>

Data

CommentHelper.java

package com.example.providertest;

import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.provider.BaseColumns;

public class CommentHelper extends SQLiteOpenHelper {

    private static final String DATABASE_NAME = "comments.db";
    private static final int DATABASE_VERSION = 1;
    public static final String TABLE_NAME = "comments";

    public static final String COLUMN_ID = BaseColumns._ID;
    public static final String COLUMN_COMMENT = "comment";

    private static final String DATABASE_CREATE = "CREATE TABLE " +
            TABLE_NAME + "(" +
                    COLUMN_ID + " INTEGER PRIMARY KEY, " +
                    COLUMN_COMMENT + " TEXT NOT NULL" +
                    ");";
    private static final String DATABASE_DROP = "DROP TABLE IF EXISTS " + TABLE_NAME;


    public CommentHelper(Context context) {
        super(context, DATABASE_NAME, null, DATABASE_VERSION);
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        db.execSQL(DATABASE_CREATE);
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        db.execSQL(DATABASE_DROP);
        onCreate(db);
    }
}

CommentDataSource.java

package com.example.providertest;

import java.util.ArrayList;
import java.util.List;

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;

public class CommentDataSource {

    private final CommentHelper mHelper;
    public static String[] sAllColumns = {CommentHelper.COLUMN_ID, CommentHelper.COLUMN_COMMENT};

    public CommentDataSource(Context context) {
        mHelper = new CommentHelper(context);
    }

    public SQLiteDatabase getDatabase()
    {
        return getDatabase(false);
    }

    public SQLiteDatabase getDatabase(boolean writable)
    {
        return writable ? mHelper.getWritableDatabase() : mHelper.getReadableDatabase();
    }

    public Comment Save(Comment comment)
    {
        final ContentValues values = toValues(comment);
        final long insertId = insert(values);
        comment.setId(insertId);
        return comment;
    }

    public long insert(ContentValues values)
    {
        final SQLiteDatabase db = mHelper.getWritableDatabase();
        try {
            final long insertId = db.insert(CommentHelper.TABLE_NAME, null, values);
            return insertId;
        } finally {
            db.close();
        }
    }

    public int update(ContentValues values, String selection, String[] selectionArgs)
    {
        final SQLiteDatabase db = mHelper.getWritableDatabase();

        try {
            final int rowsUpdated = db.update(CommentHelper.TABLE_NAME, values, selection, selectionArgs);
            return rowsUpdated;
        } finally {
            db.close();
        }
    }

    public int update(long id, ContentValues values)
    {
        final String whereClause = String.format("%s = %s", CommentHelper.COLUMN_ID, id);
        return update(values, whereClause, null);
    }

    public int delete(String selection, String[] selectionArgs)
    {
        final SQLiteDatabase db = mHelper.getWritableDatabase();

        try {
            final int rowsDeleted = db.delete(CommentHelper.TABLE_NAME, selection, selectionArgs);
            return rowsDeleted;
        } finally {
            db.close();
        }
    }

    public int delete(long id)
    {
        final SQLiteDatabase db = mHelper.getWritableDatabase();
        final String whereClause = String.format("%s = %s", CommentHelper.COLUMN_ID, id);

        try {
            final int rowsDeleted = db.delete(CommentHelper.TABLE_NAME, whereClause, null);
            return rowsDeleted;
        } finally {
            db.close();
        }
    }

    public int delete(Comment comment)
    {
        return delete(comment.getId());
    }

    public List<Comment> findAll()
    {
        final List<Comment> comments = new ArrayList<Comment>();
        final SQLiteDatabase db = mHelper.getReadableDatabase();
        final Cursor cursor = db.query(CommentHelper.TABLE_NAME, sAllColumns, null, null, null, null, null);

        try {
            cursor.moveToFirst();
            while(!cursor.isAfterLast()) {
                comments.add(fromCursor(cursor));
                cursor.moveToNext();
            }

            return comments;
        } finally {
            cursor.close();
            db.close();
        }
    }

    public Comment fromCursor(Cursor cursor)
    {
        final Comment comment = new Comment();
        comment.setId(cursor.getLong(0));
        comment.setComment(cursor.getString(1));

        return comment;
    }


    public static ContentValues toValues(Comment comment)
    {
        final ContentValues values = new ContentValues();

        // Si el valor ho se ha definido es mejor no incluirlo
        // Evita problemas con el AUTOINCREMENT de SQLite
        if(comment.getId() > 0) {
            values.put(CommentHelper.COLUMN_ID, comment.getId());
        }

        values.put(CommentHelper.COLUMN_COMMENT, comment.getComment());

        return values;
    }
}

CommentProvider.java

package com.example.providertest;

import java.util.Arrays;
import java.util.HashSet;

import android.content.ContentProvider;
import android.content.ContentValues;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteQueryBuilder;
import android.net.Uri;
import android.text.TextUtils;

public class CommentProvider extends ContentProvider {

    private CommentDataSource mDataSource;

    private static final String AUTHORITY = "com.example.comments";
    private static final int COMMENT = 10;
    private static final int COMMENT_ID = 20;

    public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/comments");

    private static final UriMatcher sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
    static {
        sUriMatcher.addURI(AUTHORITY, "comments", COMMENT);
        sUriMatcher.addURI(AUTHORITY, "comments/#", COMMENT_ID);
    }

    @Override
    public int delete(Uri uri, String selection, String[] selectionArgs) {
        int rowsDeleted = 0;

        switch (sUriMatcher.match(uri)) {
        case COMMENT:
            rowsDeleted = mDataSource.delete(selection, selectionArgs);
            break;
        case COMMENT_ID:
            final long id = Long.parseLong(uri.getLastPathSegment());
            if(TextUtils.isEmpty(uri.getLastPathSegment())) {
                rowsDeleted = mDataSource.delete(id);
            } else {
                selection = CommentHelper.COLUMN_ID + " = " + id + " and " + selection;
                rowsDeleted = mDataSource.delete(selection, selectionArgs);
            }
            break;
        default:
            throw new IllegalArgumentException("Unknow URI: " + uri);
        }

        getContext().getContentResolver().notifyChange(uri, null);
        return rowsDeleted;
    }

    @Override
    public String getType(Uri uri) {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public Uri insert(Uri uri, ContentValues values) {
        long insertId = 0;

        switch (sUriMatcher.match(uri)) {
        case COMMENT:
            insertId = mDataSource.insert(values);
            break;
        }
        getContext().getContentResolver().notifyChange(uri, null);

        return Uri.parse("comments/" + insertId);
    }

    @Override
    public boolean onCreate() {
        mDataSource = new CommentDataSource(getContext());
        return false;
    }

    @Override
    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
            String sortOrder) {

        final SQLiteQueryBuilder builder = new SQLiteQueryBuilder();

        checkColumns(projection);

        builder.setTables(CommentHelper.TABLE_NAME);

        switch (sUriMatcher.match(uri)) {
        case COMMENT_ID:
            builder.appendWhere(String.format("%s = %s", CommentHelper.COLUMN_ID, uri.getLastPathSegment()));
            break;
        case COMMENT:
            break;
        default:
            throw new IllegalArgumentException("Unknow URI: " + uri);
        }

        final SQLiteDatabase db = mDataSource.getDatabase();
        final Cursor cursor = builder.query(db, projection, selection, selectionArgs, null, null, sortOrder);
        cursor.setNotificationUri(getContext().getContentResolver(), uri);

        return cursor;
    }

    private void checkColumns(String[] projection) {
        if (projection != null) {
            final HashSet<String> requestedColumns = new HashSet<String>(Arrays.asList(projection));
            final HashSet<String> availableColumns = new HashSet<String>(Arrays.asList(CommentDataSource.sAllColumns));
            if (!availableColumns.containsAll(requestedColumns)) {
                throw new IllegalArgumentException("Unknow columns in projection");
            }
        }
    }

    @Override
    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
        int rowsUpdated = 0;

        switch (sUriMatcher.match(uri)) {
        case COMMENT_ID:
            final long id = Long.parseLong(uri.getLastPathSegment());
            if(TextUtils.isEmpty(uri.getLastPathSegment())) {
                rowsUpdated = mDataSource.update(id, values);
                break;
            } else {
                selection = CommentHelper.COLUMN_ID + " = " + id + " and " + selection;
            }
        case COMMENT:
            rowsUpdated = mDataSource.update(values, selection, selectionArgs);
            break;
        default:
            throw new IllegalArgumentException("Unknow URI: " + uri);
        }

        getContext().getContentResolver().notifyChange(uri, null);

        return rowsUpdated;
    }

}

Error

05-04 09:45:48.031: D/dalvikvm(19873): GC_CONCURRENT freed 327K, 48% free 3114K/5895K, external 1073K/1585K, paused 4ms+7ms
05-04 09:45:54.421: W/dalvikvm(19873): threadid=11: thread exiting with uncaught exception (group=0x40018578)
05-04 09:45:54.554: E/AndroidRuntime(19873): FATAL EXCEPTION: ModernAsyncTask #3
05-04 09:45:54.554: E/AndroidRuntime(19873): java.lang.RuntimeException: An error occured while executing doInBackground()
05-04 09:45:54.554: E/AndroidRuntime(19873):    at android.support.v4.content.ModernAsyncTask$3.done(ModernAsyncTask.java:137)
05-04 09:45:54.554: E/AndroidRuntime(19873):    at java.util.concurrent.FutureTask$Sync.innerSetException(FutureTask.java:274)
05-04 09:45:54.554: E/AndroidRuntime(19873):    at java.util.concurrent.FutureTask.setException(FutureTask.java:125)
05-04 09:45:54.554: E/AndroidRuntime(19873):    at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:308)
05-04 09:45:54.554: E/AndroidRuntime(19873):    at java.util.concurrent.FutureTask.run(FutureTask.java:138)
05-04 09:45:54.554: E/AndroidRuntime(19873):    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1088)
05-04 09:45:54.554: E/AndroidRuntime(19873):    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:581)
05-04 09:45:54.554: E/AndroidRuntime(19873):    at java.lang.Thread.run(Thread.java:1019)
05-04 09:45:54.554: E/AndroidRuntime(19873): Caused by: android.database.sqlite.SQLiteMisuseException: library routine called out of sequence: , while compiling: SELECT _id, comment FROM comments
05-04 09:45:54.554: E/AndroidRuntime(19873):    at android.database.sqlite.SQLiteCompiledSql.native_compile(Native Method)
05-04 09:45:54.554: E/AndroidRuntime(19873):    at android.database.sqlite.SQLiteCompiledSql.compile(SQLiteCompiledSql.java:92)
05-04 09:45:54.554: E/AndroidRuntime(19873):    at android.database.sqlite.SQLiteCompiledSql.<init>(SQLiteCompiledSql.java:65)
05-04 09:45:54.554: E/AndroidRuntime(19873):    at android.database.sqlite.SQLiteProgram.<init>(SQLiteProgram.java:83)
05-04 09:45:54.554: E/AndroidRuntime(19873):    at android.database.sqlite.SQLiteQuery.<init>(SQLiteQuery.java:49)
05-04 09:45:54.554: E/AndroidRuntime(19873):    at android.database.sqlite.SQLiteDirectCursorDriver.query(SQLiteDirectCursorDriver.java:42)
05-04 09:45:54.554: E/AndroidRuntime(19873):    at android.database.sqlite.SQLiteDatabase.rawQueryWithFactory(SQLiteDatabase.java:1356)
05-04 09:45:54.554: E/AndroidRuntime(19873):    at android.database.sqlite.SQLiteQueryBuilder.query(SQLiteQueryBuilder.java:330)
05-04 09:45:54.554: E/AndroidRuntime(19873):    at android.database.sqlite.SQLiteQueryBuilder.query(SQLiteQueryBuilder.java:280)
05-04 09:45:54.554: E/AndroidRuntime(19873):    at com.example.providertest.CommentProvider.query(CommentProvider.java:103)
05-04 09:45:54.554: E/AndroidRuntime(19873):    at android.content.ContentProvider$Transport.query(ContentProvider.java:187)
05-04 09:45:54.554: E/AndroidRuntime(19873):    at android.content.ContentResolver.query(ContentResolver.java:262)
05-04 09:45:54.554: E/AndroidRuntime(19873):    at android.support.v4.content.CursorLoader.loadInBackground(CursorLoader.java:49)
05-04 09:45:54.554: E/AndroidRuntime(19873):    at android.support.v4.content.CursorLoader.loadInBackground(CursorLoader.java:35)
05-04 09:45:54.554: E/AndroidRuntime(19873):    at android.support.v4.content.AsyncTaskLoader.onLoadInBackground(AsyncTaskLoader.java:240)
05-04 09:45:54.554: E/AndroidRuntime(19873):    at android.support.v4.content.AsyncTaskLoader$LoadTask.doInBackground(AsyncTaskLoader.java:51)
05-04 09:45:54.554: E/AndroidRuntime(19873):    at android.support.v4.content.AsyncTaskLoader$LoadTask.doInBackground(AsyncTaskLoader.java:40)
05-04 09:45:54.554: E/AndroidRuntime(19873):    at android.support.v4.content.ModernAsyncTask$2.call(ModernAsyncTask.java:123)
05-04 09:45:54.554: E/AndroidRuntime(19873):    at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:306)
05-04 09:45:54.554: E/AndroidRuntime(19873):    ... 4 more
05-04 09:45:54.578: D/dalvikvm(19873): GC_CONCURRENT freed 451K, 48% free 3109K/5959K, external 876K/1388K, paused 5ms+6ms

The relevant code is in your your CommentProvider class. It looks like you don't open the database before trying to query it. Hard to say without seeing the Comment Provider code.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM