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
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();
}
}
<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>
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);
}
}
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;
}
}
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
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.