I am trying to retrieve rows of locations from my SQLiteTable but I ran into a compilation error, the constructor CursorLoader is undefined.
#Override
public Loader<Cursor> onCreateLoader(int arg0,
Bundle arg1) {
// Uri to the content provider LocationsContentProvider
Uri uri = LocationsContentProvider.CONTENT_URI;
// Fetches all the rows from locations table
//return new CursorLoader(null);
//(Context context, Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)
/ERROR HERE
return new CursorLoader(this, null, null, null, null);
}
In LocationsContentProvider.java
/** A callback method which is invoked by default content uri */
#Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
if(uriMatcher.match(uri)==LOCATIONS){
return mLocationsDB.getAllLocations();
}
return null;
}
CursorLoader does not have a five-parameter constructor. More importantly, you need to provide the Uri pointing to the collection on the ContentProvider that you are trying to query. You are welcome to say that the final four parameters are null, but add the Uri as the second parameter to the constructor.
You may wish to read the documentation for the six-parameter CursorLoader constructor that you will be using.
Also note that the code in your first code snippet will not compile, as you are missing a comma between two of the null values.
Cursor Loader constructor get following property :
public CursorLoader(Context context, Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
super(context);
mObserver = new ForceLoadContentObserver();
mUri = uri;
mProjection = projection;
mSelection = selection;
mSelectionArgs = selectionArgs;
mSortOrder = sortOrder;
}
you miss one property. you can add one null or define your order and pass to the constructor.
and as CommonsWar said, you must pass your URI as a second argument,
Related
I am trying to use loaders without content provider.
To achieve this, while inserting/updating/deleting data from SQLite i use following code to notify.
getContext().getContentResolver().notifyChange(CONTENT_URI, null);
On the other hand, i have created one custom loader class to load data directly from SQLite and to get notify automatically when content changes.
public class SQLiteCursorLoader extends CursorLoader
{
private String tableName;
private String rawQuery = null;
private final ForceLoadContentObserver mObserver = new ForceLoadContentObserver();
private String[] projection;
private String selection;
private String[] selectionArgs;
private String sortOrder;
Loader<Cursor> ld = null;
public SQLiteCursorLoader(Context context, String tableName, String[] projection, String selection, String[] selectionArgs, String sortOrder)
{
super(context);
this.tableName = tableName;
this.projection = projection;
this.selection = selection;
this.selectionArgs = selectionArgs;
this.sortOrder = sortOrder;
}
public SQLiteCursorLoader(Context context, String rawQuery)
{
super(context);
this.rawQuery = rawQuery;
}
#Override
public Cursor loadInBackground()
{
//super.loadInBackground();
Cursor cursor = null;
SQLiteDatabase db = AndroidSQLite.getInstatnce().getDatabase();
try
{
if(rawQuery == null)
{
cursor = db.query(tableName, projection, selection, selectionArgs, null, null, sortOrder);
}
else
{
cursor = db.rawQuery(rawQuery, null);
}
// Ensure the cursor window is filled.
//cursor.setNotificationUri(getContext().getContentResolver(), UserGroupCP.CONTENT_URI);
cursor.getCount();
//cursor.registerContentObserver(mObserver);
getContext().getContentResolver().registerContentObserver(UserGroupCP.CONTENT_URI, true, mObserver);
}
catch(Exception e)
{
ErrorReportProvider.sendErrorMail(Helper.getStackTrace(e), TenoPhotoConstant.defaultDisplay);
}
return cursor;
}
}
But whenever i try to replace
getContext().getContentResolver().registerContentObserver(UserGroupCP.CONTENT_URI, true, mObserver);
with
cursor.setNotificationUri(getContext().getContentResolver(), UserGroupCP.CONTENT_URI);
cursor.registerContentObserver(mObserver);
in my custom loader class (as in android.content.CursorLoader's loadInBackground() method), it does not get notify automatically at all.
i am not getting any clue about this. In android.content.CursorLoader class, this works fine but not in custom class extending CursorLoader class. Kindly explain this.
Also explain about significance and difference between these two lines of code.
cursor.setNotificationUri(getContext().getContentResolver(), UserGroupCP.CONTENT_URI);
cursor.registerContentObserver(mObserver);
vs
getContext().getContentResolver().registerContentObserver(UserGroupCP.CONTENT_URI, true, mObserver);
I am inserting a ContentProvider layer in between the ORM of SugarORM and the underlying SQLite database in order to be able to use a SyncAdapter with it.
The ORM has a method like this:
public static <T extends SugarRecord<?>> List<T> find(Class<T> type,String whereClause,String[] whereArgs,String groupBy, String orderBy, String limit)
which matches nicely a query method of the SQLiteDatabase:
public Cursor query (String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy, String limit)
the problem is that the ContentProvider only has one query method which doesn't match the necessary parameters:
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)
So I was thinking of turning the parameters from the ORM into a SQL query, and then just passing that to my method, which can then run the raw query and return a cursor, like this:
#Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)
{
switch (uriMatcher.match(uri))
{
case RAW_QUERY:
cursor = db.rawQuery(selection, selectionArgs);//query, arguments
...
the first issue is that this method of SQLiteQueryBuilder is deprecated:
buildQuery (String[] projectionIn, String selection, String[] selectionArgs, String groupBy, String having, String sortOrder, String limit)
so then I tried this:
Object args[] = whereArgs;
String where_query = String.format(whereClause, args);
SQLiteQueryBuilder builder = new SQLiteQueryBuilder();
builder.setTables(getTableName(type));
String query = builder.buildQuery(null, whereClause, whereArgs, groupBy, null, orderBy, limit);
but the resulting query string is null.
Any suggestions?
public Cursor query(Uri iUri, String[] iProjection, String iSelection,
String[] iSelectionArgs, String iSortOrder) {
SQLiteQueryBuilder mBuilder = new SQLiteQueryBuilder();
mBuilder.setTables(Database.KEY_TABLE);
switch (uriMatcher.match(iUri)) {
case RAW_QUERY:
mBuilder.appendWhere(Database.KEY_ROWID);
break;
default:
throw new IllegalArgumentException("Unsupported URI: " + iUri);
}
Cursor cursor = mBuilder.query(db, iProjection, iSelection,
iSelectionArgs, null, null, iSortOrder);
return cursor;
}
Try this in your code i think this will solve your problem.
I used Content Provider to query some information(Android). After I called the startQuery(), I can output the result of my query in Log. But after all the result finished, the function onQueryComplete() was not called. I cannot find the reason.
The code below is my startQuery and onQueryComplete implementations.
public void queryAsync(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder, IContinue<Cursor> callback) {
this.startQuery(0, callback, uri, projection, selection, selectionArgs, sortOrder);
}
#Override
public void onQueryComplete(int token, Object cookie, Cursor c) {
Log.e("debug","query complete!");
if (cookie != null) {
#SuppressWarnings("unchecked")
IContinue<Cursor> callback = (IContinue<Cursor>) cookie;
callback.kontinue(c);
}
}
The code below is part of my query code in content provider:
#Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
switch (uriMatcher.match(uri)){
...
case SINGLE_MESSAGE:
String selection3 = SEQNUM + "=?";
String[] selectArgs2 = { "0" };
Cursor cm = db.query(MESSAGE_TABLE, null, selection3, selectArgs2, null, null, null);
Log.i("debug",Integer.toString(cm.getCount()));
return cm;
}
}
How can I fix this problem?
I'm using Loader and Content Provider to fill a listview with data from my database.
My problem is that, if I use the line below in my Content Provider to get data from database, the query and onLoadFinished is executed very fast (no problem to fill the listview):
Cursor c = this.mDb.rawQuery("SELECT * FROM " + DATABASE_TABLE , null);
However, If I change the line to :
Cursor c = this.mDb.rawQuery("SELECT DISTINCT D._id, D.Name, D.Icon FROM Plain A, Test B, Exercise C, Group D WHERE A.ID=1 AND B.PlainID=A._id AND B.TestID=C._id AND C.ExerciseID=D._id", null);
The query continues to run fast, but the application takes approximately 2s to call onLoadFinished and fill the listview.
why this delay if the cursor already executed query?
My Loader:
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
Log.d(TAG, "onCreateLoader");
Uri uri = ContentProviderGroup.CONTENT_URI;
String[] projection = { Group.KEY_ROW_ID, Group.KEY_NAME, Group.KEY_ICON };
CursorLoader cursorLoader = new CursorLoader(this, // Parent activity context
uri, // Table to query
projection, // Projection to return
null, // No selection clause
null, // No selection arguments
null); // Default sort order
Log.d(TAG, "END onCreateLoader");
return cursorLoader;
}
My Content Provider (query function):
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
Cursor cursor;
if(uriMatcher.match(uri) == CODE){
Log.d(TAG, "CALL SELECT");
cursor = mCustomerDB.getGroup(selection, selectionArgs);
Log.d(TAG, "END SELECT");
return cursor;
}else{
return null;
}
}
My DBAdapter (getGroup function):
public Cursor getGroup(String selection, String[] selectionArgs){
Log.d(TAG, "SELECT INIT");
/////// HERE I USE the rawQuery /////////
Log.d(TAG, "SELECT END");
return c;
}
Thank You
I am trying to limit the database result by defining a SQL WHERE clause in the selection string of the query of the ContentResolver.
Cursor cursor = getContentResolver().query(uri, null, getSelectionString(), null, null);
...
public String getSelectionString() {
// TODO Replace latitude and longitude with database reference.
StringBuilder string = new StringBuilder();
string.append("latitude >= ").append(northEast.getLatitudeE6() / 1e6);
string.append(" AND ");
string.append("latitude <= ").append(southWest.getLatitudeE6() / 1e6);
string.append(" AND ");
string.append("longitude >= ").append(southWest.getLongitudeE6() / 1e6);
string.append(" AND ");
string.append("longitude <= ").append(northEast.getLongitudeE6() / 1e6);
return string.toString();
}
The database columns are defined as follows ...
public class CustomDatabase {
public static final class Contract {
public static final String COLUMN_NAME = "name";
public static final String COLUMN_LATITUDE = "latitude";
public static final String COLUMN_LONGITUDE = "longitude";
}
}
...
I am not particularly sure that I can inspect the query sent in cursor. If so, it does not contain the WHERE clause I sent:
SQLiteQuery: SELECT * FROM custom_db ORDER BY number ASC
Here is an example of the selection string:
latitude >= 48.203927 AND latitude <= 48.213851 AND longitude >= 16.36735 AND longitude <= 16.377648
Questions:
Is the WHERE clause syntactically correct?
Do I need apostrophs?
Am I forced to use both parameters (selection, selectionArgs) at a time in a query?
Where can I debug the whole query?
EDIT:
Here is the query() method of the ContentProvider ...
public class CustomProvider extends ContentProvider {
#Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
switch (URI_MATCHER.match(uri)) {
case URI_CODE_LOCATIONS:
return mCustomDatabase.getLocations();
}
return null;
}
... obviously, as biegleux guessed, I forgot to pass the parameters. Doh!
Here is the current implementation of the database method ...
public class CustomSQLiteOpenHelper extends SQLiteOpenHelper {
public Cursor getLocation() {
return mDatabaseHelper.getReadableDatabase().query(
CustomSQLiteOpenHelper.TABLE_NAME,
null, null, null, null, null, null);
}
Do you suggest that I change the method signature to the following to pass all parameters? Am I not exposing to much of the database interface this way?
public Cursor getLocations(String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy) {
return mDatabaseHelper.getReadableDatabase().query(
CustomSQLiteOpenHelper.TABLE_NAME,
columns, selection, selectionArgs, groupBy, having, orderBy);
}
Ok, so it seems query() method of your provider is causing problems.
Make sure it looks like following.
#Override
public abstract Cursor query (Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
...
// run the query
db.query(db, projection, selection, selectionArgs, groupBy, having, sortOrder, limit);
You are not forced to use selectionArgs parameter, but with it code is more readable.
To debug a query you can use
SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
Log.e(TAG, qb.buildQuery(projection, selection, selectionArgs, groupBy, having, sortOrder, limit);
EDIT:
If you have a ContentProvider implemented you don't need to expose getLocations() method as you/users can use ContentProvider's query() method.
You should pass at least those arguments whose can be passed in query() method and those are projection, selection, selectionArgs and sortOrder.
Shouldn't that line be:
Cursor cursor = getContentResolver().query(uri, null, getSelectionString(), null, null);
Note the added parens after getSelectionString to indicate it's a method call, not a string (although I do wonder why that wouldn't throw an error as getSelectionString wouldn't exist as a string if my theory is correct...).