我有一个简单的 ContentProvider 按照vogella.com的步骤进行了一些更改,因为我正在使用android-support-v4.jar
我有一个简单的应用程序
在这里,我有三个按钮和一个 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>
数据
评论助手.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);
}
}
评论数据源.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;
}
}
评论提供者.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