1

シンプルなアプリを使用しているため、 vogella.comの手順に従っていくつかの変更を加えたシンプルな ContentProvider があります。android-support-v4.jar

ここに画像の説明を入力

ここでは、3 つのボタンと 1 つの ListFragment がすべてカスタム ContentProvider を使用しており、問題を探していますが、ボタンを高速にパルスしようとすると、ドキュメントに記載されているSQLiteMisuseExceptionが発生することがあります

このエラーは、アプリケーションが SQLiteStatement オブジェクトを作成し、アプリケーション内の複数のスレッドが同時にそれを使用できるようにした場合に発生する可能性があります

しかし、私は多くのスレッドを持っていません(少なくとも私は思います)。

更新:アプリがUIの動作を停止することがありますが、応答しません

更新 2 : Galaxy ACE (エラーあり) でテストしているデバイスの速度応答に問題がある可能性があり、Galaxy SIII は正常に動作します


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>

データ

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;
    }

}

エラー

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
4

1 に答える 1