Related
I have the problem, that my ListView shows the data only one time. If am closing the application and open it again, it doesn't show anything.
I have a Content Provider for retrieving the data from a SQLite database. I have a SyncAdapter which is getting the data from a Server and puts it into the SQLite database. Then I use a SimpleCursorAdapter for showing the data into a ListView. The query is an 'inner join'.
MainActivity Code:
public class MainActivity extends AppCompatActivity implements LoaderManager.LoaderCallbacks<Cursor> {
private static final int URL_LOADER = 1;
private ListView employeeList;
public static SimpleCursorAdapter adapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
employeeList = (ListView) findViewById(R.id.listView);
/**
* Creating a dummyAccount for the content provider
*/
Account account = new Account("dummyAccount", TrackingContentProvider.AUTHORITY);
AccountManager accountManager = (AccountManager) this.getSystemService(ACCOUNT_SERVICE);
accountManager.addAccountExplicitly(account, null, null);
/**
* Set the sync adapter to an automatic state
*/
ContentResolver.setSyncAutomatically(account, TrackingContentProvider.AUTHORITY, true);
/**
* The projection for the SimpleCursorLoader
*/
String[] from = new String[] {EmployeesTable.COLUMN_FIRST_NAME, EmployeesTable.COLUMN_LAST_NAME, StatesTable.COLUMN_STATE, EmployeesTable.COLUMN_ID};
/**
* The ids of the views where the content is going to be put in
*/
int[] to = new int[] {R.id.tV_emplFirstNameInsert, R.id.tV_emplLastNameInsert, R.id.tV_stateInsert};
/**
* Make a new cursor adapter for the list view
*/
adapter = new SimpleCursorAdapter(this, R.layout.employee_list_item, null, from, to, 0);
/**
* Calls the loader manager and query another time
*/
getSupportLoaderManager().restartLoader(URL_LOADER, null, MainActivity.this);
/**
* Sets the list view to the SimpleCursorAdapter
*/
employeeList.setAdapter(adapter);
registerClickCallback();
}
/**
* Registers the clicks on the elements
*/
private void registerClickCallback() {
employeeList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
startActivity(new Intent(MainActivity.this, LocationActivity.class));
}
});
}
/**
* Is called by the loader manager
* #param id The unique id of the loader
* #param args Bundle of arguments
* #return The cursor of the query
*/
#Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
String[] projection = new String[] {"E." + EmployeesTable.COLUMN_ID, "E." + EmployeesTable.COLUMN_FIRST_NAME,
"E." + EmployeesTable.COLUMN_LAST_NAME, "S." + StatesTable.COLUMN_STATE};
String clause = "S." + StatesTable.COLUMN_ID + " = " + "E." + EmployeesTable.COLUMN_STATE_ID;
return new CursorLoader(this,
TrackingContentProvider.EMPLOYEE_LIST_CONTENT_URI, projection, clause, null, null);
}
#Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
adapter.swapCursor(data);
}
#Override
public void onLoaderReset(Loader<Cursor> loader) {
adapter.swapCursor(null);
}
#Override
protected void onRestart() {
super.onRestart();
getSupportLoaderManager().restartLoader(URL_LOADER, null, MainActivity.this);
}
}
The Content Provider queries the data with a SQLiteQueryBuilder. The table I used for the query looks like this:
private static final String EMPLOYEE_LIST_INNER_JOIN = "" +
EmployeesTable.TABLE_NAME + " AS E " +
"INNER JOIN " +
StatesTable.TABLE_NAME + " AS S";
The onPerformSync looks like this:
#Override
public void onPerformSync(Account account, Bundle extras, String authority, ContentProviderClient provider, SyncResult syncResult) {
try {
deleteDatabase(provider);
insertEmployeesTable(provider);
insertStatesTable(provider);
insertLocationsTable(provider);
} catch (RemoteException | IOException e) {
Log.e("Sync: Error:", e.toString());
}
}
So every sync, it deletes all entries of the database and inserts the data new. It works, I checked the database after sync.
After the application is started for the first time, it doesn't shows anything, since the sync adapter is syncing. Then I close the app and opens it again and it shows the data. Then the sync adapter syncs another time (same data) but it doesn't shows the data anymore. Any suggestions? I am now trying to find the error for 3 days...
EDIT 1: ContentProvider Code:
public class TrackingContentProvider extends ContentProvider {
private static final int TRACKING_CONTENT = 100;
private static final int TRACKING_CONTENT_ID = 200;
private static final int EMPLOYEE_LIST_CONTENT = 300;
private static final int EMPLOYEE_LIST_CONTENT_ID = 400;
/**
* Table declaration
*/
private static final int EMPLOYEES_TABLE_CONTENT = 500;
private static final int EMPLOYEES_TABLE_CONTENT_ID = 600;
private static final int STATES_TABLE_CONTENT = 700;
private static final int STATES_TABLE_CONTENT_ID = 800;
private static final int LOCATIONS_TABLE_CONTENT = 900;
private static final int LOCATIONS_TABLE_CONTENT_ID = 1000;
public static final String AUTHORITY = "***";
private static final String TRACKING_BASE_PATH = "tracking";
private static final String EMPLOYEE_LIST_BASE_PATH = "employees";
/**
* Table base paths
*/
private static final String EMPLOYEES_TABLE_BASE_PATH = "employeesTable";
private static final String STATES_TABLE_BASE_PATH = "statesTable";
private static final String LOCATIONS_TABLE_BASE_PATH = "locationsTable";
/**
* Table INNER JOIN declarations
*/
private static final String EMPLOYEE_LIST_INNER_JOIN = "" +
EmployeesTable.TABLE_NAME + " AS E " +
"INNER JOIN " +
StatesTable.TABLE_NAME + " AS S";
public static final Uri TRACKING_CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/" + TRACKING_BASE_PATH);
public static final Uri EMPLOYEE_LIST_CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/" + EMPLOYEE_LIST_BASE_PATH);
/**
* Tables Uris
*/
public static final Uri EMPLOYEES_TABLE_URI = Uri.parse("content://" + AUTHORITY + "/" + EMPLOYEES_TABLE_BASE_PATH);
public static final Uri STATES_TABLE_URI = Uri.parse("content://" + AUTHORITY + "/" + STATES_TABLE_BASE_PATH);
public static final Uri LOCATIONS_TABLE_URI = Uri.parse("content://" + AUTHORITY + "/" + LOCATIONS_TABLE_BASE_PATH);
private static final UriMatcher sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
static {
sUriMatcher.addURI(AUTHORITY, TRACKING_BASE_PATH, TRACKING_CONTENT);
sUriMatcher.addURI(AUTHORITY, TRACKING_BASE_PATH + "/#", TRACKING_CONTENT_ID);
sUriMatcher.addURI(AUTHORITY, EMPLOYEE_LIST_BASE_PATH, EMPLOYEE_LIST_CONTENT);
sUriMatcher.addURI(AUTHORITY, EMPLOYEE_LIST_BASE_PATH + "/#", EMPLOYEE_LIST_CONTENT_ID);
/**
* Table matcher
*/
sUriMatcher.addURI(AUTHORITY, EMPLOYEES_TABLE_BASE_PATH, EMPLOYEES_TABLE_CONTENT);
sUriMatcher.addURI(AUTHORITY, EMPLOYEES_TABLE_BASE_PATH + "/#", EMPLOYEES_TABLE_CONTENT_ID);
sUriMatcher.addURI(AUTHORITY, STATES_TABLE_BASE_PATH, STATES_TABLE_CONTENT);
sUriMatcher.addURI(AUTHORITY, STATES_TABLE_BASE_PATH + "/#", STATES_TABLE_CONTENT_ID);
sUriMatcher.addURI(AUTHORITY, LOCATIONS_TABLE_BASE_PATH, LOCATIONS_TABLE_CONTENT);
sUriMatcher.addURI(AUTHORITY, LOCATIONS_TABLE_BASE_PATH + "/#", LOCATIONS_TABLE_CONTENT_ID);
}
private SQLiteHelper database;
#Override
public boolean onCreate() {
database = new SQLiteHelper(getContext());
return false;
}
#Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder();
int uriType = sUriMatcher.match(uri);
checkColumns(projection);
switch (uriType) {
case TRACKING_CONTENT:
break;
case TRACKING_CONTENT_ID:
break;
case EMPLOYEE_LIST_CONTENT:
queryBuilder.setTables(EMPLOYEE_LIST_INNER_JOIN);
break;
case EMPLOYEE_LIST_CONTENT_ID:
queryBuilder.setTables(EMPLOYEE_LIST_INNER_JOIN);
queryBuilder.appendWhere("E." + EmployeesTable.COLUMN_ID + " = " + uri.getLastPathSegment());
break;
case STATES_TABLE_CONTENT:
queryBuilder.setTables(StatesTable.TABLE_NAME);
break;
case STATES_TABLE_CONTENT_ID:
queryBuilder.setTables(StatesTable.TABLE_NAME);
queryBuilder.appendWhere(StatesTable.COLUMN_ID + " = " + uri.getLastPathSegment());
break;
case EMPLOYEES_TABLE_CONTENT:
queryBuilder.setTables(EmployeesTable.TABLE_NAME);
break;
case EMPLOYEES_TABLE_CONTENT_ID:
queryBuilder.setTables(EmployeesTable.TABLE_NAME);
queryBuilder.appendWhere(EmployeesTable.COLUMN_ID + " = " + uri.getLastPathSegment());
break;
case LOCATIONS_TABLE_CONTENT:
queryBuilder.setTables(LocationsTable.TABLE_NAME);
break;
case LOCATIONS_TABLE_CONTENT_ID:
queryBuilder.setTables(LocationsTable.TABLE_NAME);
queryBuilder.appendWhere(LocationsTable.COLUMN_ID + " = " + uri.getLastPathSegment());
default:
throw new IllegalArgumentException("Unknown URI: " + uri);
}
SQLiteDatabase db = database.getReadableDatabase();
Cursor cursor = queryBuilder.query(
db,
projection,
selection,
selectionArgs,
null,
null,
sortOrder
);
cursor.setNotificationUri(getContext().getContentResolver(), uri);
return cursor;
}
#Override
public String getType(Uri uri) {
return null;
}
#Override
public Uri insert(Uri uri, ContentValues values) {
int uriType = sUriMatcher.match(uri);
SQLiteDatabase db = database.getWritableDatabase();
long id;
String path;
switch (uriType) {
case STATES_TABLE_CONTENT:
id = db.insert(StatesTable.TABLE_NAME, null, values);
path = STATES_TABLE_BASE_PATH;
break;
case LOCATIONS_TABLE_CONTENT:
id = db.insert(LocationsTable.TABLE_NAME, null, values);
path = LOCATIONS_TABLE_BASE_PATH;
break;
case EMPLOYEES_TABLE_CONTENT:
id = db.insert(EmployeesTable.TABLE_NAME, null, values);
path = EMPLOYEES_TABLE_BASE_PATH;
break;
default:
throw new IllegalArgumentException("Unknown URI: " + uri);
}
getContext().getContentResolver().notifyChange(uri, null);
return Uri.parse(path + "/" + id);
}
#Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
int uriType = sUriMatcher.match(uri);
SQLiteDatabase db = database.getWritableDatabase();
int rowsDeleted = 0;
switch (uriType) {
case EMPLOYEES_TABLE_CONTENT:
rowsDeleted = db.delete(EmployeesTable.TABLE_NAME,
selection,
selectionArgs);
break;
case EMPLOYEES_TABLE_CONTENT_ID:
String employeeID = uri.getLastPathSegment();
if (TextUtils.isEmpty(selection)) {
rowsDeleted = db.delete(EmployeesTable.TABLE_NAME,
EmployeesTable.COLUMN_ID + " = " + employeeID, null);
}
break;
case STATES_TABLE_CONTENT:
rowsDeleted = db.delete(StatesTable.TABLE_NAME,
selection,
selectionArgs);
break;
case STATES_TABLE_CONTENT_ID:
String stateID = uri.getLastPathSegment();
if (TextUtils.isEmpty(selection)) {
rowsDeleted = db.delete(StatesTable.TABLE_NAME,
StatesTable.COLUMN_ID + " = " + stateID, null);
}
break;
case LOCATIONS_TABLE_CONTENT:
rowsDeleted = db.delete(StatesTable.TABLE_NAME,
selection,
selectionArgs);
break;
case LOCATIONS_TABLE_CONTENT_ID:
String locationID = uri.getLastPathSegment();
if (TextUtils.isEmpty(selection)) {
rowsDeleted = db.delete(LocationsTable.TABLE_NAME,
LocationsTable.COLUMN_ID + " = " + locationID, null);
}
break;
default:
throw new IllegalArgumentException("Unknown URI: " + uri);
}
getContext().getContentResolver().notifyChange(uri, null);
return rowsDeleted;
}
#Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
int uriType = sUriMatcher.match(uri);
SQLiteDatabase sqlDb = database.getWritableDatabase();
int rowsUpdated;
switch (uriType) {
case EMPLOYEES_TABLE_CONTENT:
rowsUpdated = sqlDb.update(EmployeesTable.TABLE_NAME,
values,
selection,
selectionArgs);
break;
case EMPLOYEE_LIST_CONTENT_ID:
String employeeID = uri.getLastPathSegment();
if (TextUtils.isEmpty(selection)) {
rowsUpdated = sqlDb.update(EmployeesTable.TABLE_NAME,
values,
EmployeesTable.COLUMN_ID + "=" + employeeID
+ " AND "
+ selection,
selectionArgs);
} else {
rowsUpdated = sqlDb.update(EmployeesTable.TABLE_NAME,
values,
EmployeesTable.COLUMN_ID + "=" + employeeID
+ " AND "
+ selection,
selectionArgs);
}
break;
case STATES_TABLE_CONTENT:
rowsUpdated = sqlDb.update(StatesTable.TABLE_NAME,
values,
selection,
selectionArgs);
break;
case STATES_TABLE_CONTENT_ID:
String stateID = uri.getLastPathSegment();
if (TextUtils.isEmpty(selection)) {
rowsUpdated = sqlDb.update(StatesTable.TABLE_NAME,
values,
StatesTable.COLUMN_ID + "=" + stateID
+ " AND "
+ selection,
selectionArgs);
} else {
rowsUpdated = sqlDb.update(StatesTable.TABLE_NAME,
values,
StatesTable.COLUMN_ID + "=" + stateID
+ " AND "
+ selection,
selectionArgs);
}
break;
case LOCATIONS_TABLE_CONTENT:
rowsUpdated = sqlDb.update(LocationsTable.TABLE_NAME,
values,
selection,
selectionArgs);
break;
case LOCATIONS_TABLE_CONTENT_ID:
String locationID = uri.getLastPathSegment();
if (TextUtils.isEmpty(selection)) {
rowsUpdated = sqlDb.update(LocationsTable.TABLE_NAME,
values,
LocationsTable.COLUMN_ID + "=" + locationID
+ " AND "
+ selection,
selectionArgs);
} else {
rowsUpdated = sqlDb.update(LocationsTable.TABLE_NAME,
values,
LocationsTable.COLUMN_ID + "=" + locationID
+ " AND "
+ selection,
selectionArgs);
}
break;
default:
throw new IllegalArgumentException("Unknown URI: " + uri);
}
getContext().getContentResolver().notifyChange(uri, null);
return rowsUpdated;
}
/**
* Checks if the column exists
* #param projection The array of the existing columns
*/
private void checkColumns(String[] projection) {
String[] available = {
"E." + EmployeesTable.COLUMN_ID,
"E." + EmployeesTable.COLUMN_LAST_NAME,
"E." + EmployeesTable.COLUMN_FIRST_NAME,
"E." + EmployeesTable.COLUMN_STATE_ID,
"E." + EmployeesTable.COLUMN_ENTRY_DATE,
"S." + StatesTable.COLUMN_ID,
"S." + StatesTable.COLUMN_STATE,
"L." + LocationsTable.COLUMN_ID,
"L." + LocationsTable.COLUMN_DATE,
"L." + LocationsTable.COLUMN_EMPLOYEE_ID,
"L." + LocationsTable.COLUMN_LONGITUDE,
"L." + LocationsTable.COLUMN_LATITUDE,
EmployeesTable.COLUMN_ID,
EmployeesTable.COLUMN_LAST_NAME,
EmployeesTable.COLUMN_FIRST_NAME,
EmployeesTable.COLUMN_STATE_ID,
EmployeesTable.COLUMN_ENTRY_DATE,
StatesTable.COLUMN_ID,
StatesTable.COLUMN_STATE,
LocationsTable.COLUMN_ID,
LocationsTable.COLUMN_DATE,
LocationsTable.COLUMN_EMPLOYEE_ID,
LocationsTable.COLUMN_LONGITUDE,
LocationsTable.COLUMN_LATITUDE,
};
if (projection != null) {
HashSet<String> requestedColumns = new HashSet<>(Arrays.asList(projection));
HashSet<String> availableColumns = new HashSet<>(Arrays.asList(available));
if (!availableColumns.containsAll(requestedColumns)) {
throw new IllegalArgumentException("Unknown columns in projection");
}
}
}
}
UPDATE:
I finally found the mistake. During the synchronization, there is a mistake with the auto increment. So, he won't find a entry with this Inner Join statement. finished.
I have the content provider below. It's the inteface to my database which has several tables, message, phone, transaction etc.
I can retrieve data ok using the query method and a cursor loader. I do this when displaying data in a listview.
I understand that if i want to insert data, i must use a contentResolver. Something like the following.
getContentResolver().insert(URI, values);
.
How can i insert into the message table for example?
I can see there is a uriMatching mechanism within the content provider, but how do i specify a specific table when using the content provider to perform an insert. How can i specify this in the contentResolver?
would i have to perform a switch like i do in the query method?
Thanks in advance
Matt.
public class RR3ContentProvider extends ContentProvider {
private static final String TAG = RR3ContentProvider.class.getSimpleName();
NfcScannerApplication nfcAppObj;
static final String PROVIDER_NAME = "com.carefreegroup.rr3.ContentProvider";
static final String URLPHONENUMBERS = "content://" + PROVIDER_NAME + "/phonenumbers";
static final Uri CONTENT_URI_PHONE_NUMBERS = Uri.parse(URLPHONENUMBERS);
static final String _ID_PHONENUMBERS = "_id";
static final String PHONE_NAME = "phonename";
static final String PHONE_NUMBER = "phonenumber";
static final String TABLEPHONE = "phone";
private static HashMap<String, String> PHONE_PROJECTION_MAP;
static final int PHONES = 1;
static final int PHONE_ID = 2;
static final String URLMESSAGES = "content://" + PROVIDER_NAME + "/messages";
static final Uri CONTENT_URI_MESSAGES = Uri.parse(URLMESSAGES);
static final String _ID_MESSAGES = "_id";
static final String MESSAGE_CREATED_AT = "messagecreatedat";
static final String MESSAGE_TEXT = "messagetext";
static final String MESSAGE_SENDER = "messagesender";
static final String TABLEMESSAGE = "message";
private static HashMap<String, String> MESSAGE_PROJECTION_MAP;
static final int MESSAGES = 3;
static final int MESSAGE_ID = 4;
public static final String C_ID = BaseColumns._ID; // special for id
// internally in system
static final String URLTRANSACTIONS = "content://" + PROVIDER_NAME + "/transactions";
static final Uri CONTENT_URI_TRANSACTIONS = Uri.parse(URLTRANSACTIONS);
static final String _ID_TRANSACTIONS = "_id";
static final String TRANSACTIONS_TYPE = "type";
static final String TRANSACTIONS_COMPANY_ID = "companyid";
static final String TRANSACTIONS_PERSON_ID = "person";
static final String TRANSACTIONS_NAME = "name";
static final String TRANSACTIONS_TAG_ID = "tagid";
static final String TRANSACTIONS_STATUS = "status";
static final String TRANSACTIONS_TAG_SCAN_TIME = "tagscantime";
static final String TRANSACTIONS_TAG_SENTSERVER_TIME = "tagsentservertime";
static final String TRANSACTIONS_TRANSACTIONS_LATITUDE = "transactionslatitude";
static final String TRANSACTIONS_TRANSACTIONS_LONGITUDE = "transactionslongitude";
static final String TRANSACTIONS_DRIVER = "driver";
static final String TABLETRANSACTIONS = "transactions";
private static HashMap<String, String> TRANSACTIONS_PROJECTION_MAP;
static final int TRANSACTIONS = 5;
static final int TRANSACTION_ID = 6;
static final String URLLOG = "content://" + PROVIDER_NAME + "/log";
static final Uri CONTENT_URI_LOG = Uri.parse(URLLOG);
static final String _ID_Log = "_id";
static final String LOG_CALLID = "logcallid";
static final String LOG_MESSAGE = "logmessage";
static final String LOG_CREATED_TIME = "logcreatedtime";
static final String LOG_CLIENTID = "logclientid";
static final String LOG_CARERID = "logcarerid";
static final String LOG_SERVER_TIME = "logservertime";
static final String TABLELOG = "log";
private static HashMap<String, String> LOG_PROJECTION_MAP;
static final int LOG = 7;
static final int LOG_ID = 8;
static final UriMatcher uriMatcher;
static{
uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
uriMatcher.addURI(PROVIDER_NAME, "phonenumbers", PHONES);
uriMatcher.addURI(PROVIDER_NAME, "phonenumbers/#", PHONE_ID);
uriMatcher.addURI(PROVIDER_NAME, "messages", MESSAGES);
uriMatcher.addURI(PROVIDER_NAME, "messages/#", MESSAGE_ID);
uriMatcher.addURI(PROVIDER_NAME, "transactions", TRANSACTIONS);
uriMatcher.addURI(PROVIDER_NAME, "transactions/#", TRANSACTION_ID);
uriMatcher.addURI(PROVIDER_NAME, "log", LOG);
uriMatcher.addURI(PROVIDER_NAME, "log/#", LOG_ID);
}
/**
* Database specific constant declarations
*/
private SQLiteDatabase db;
#Override
public boolean onCreate() {
Context context = getContext();
nfcAppObj = (NfcScannerApplication) getContext();
Log.e(TAG, "inside RR3ContentProvider onCreate");
return (nfcAppObj == null)? false:true;
}
#Override
public Uri insert(Uri uri, ContentValues values) {
db = nfcAppObj.getDb();
long rowID = db.insert( TABLEPHONE, "", values);
/**
* If record is added successfully
*/
if (rowID > 0)
{
Uri _uri = ContentUris.withAppendedId(CONTENT_URI_PHONE_NUMBERS, rowID);
getContext().getContentResolver().notifyChange(_uri, null);
return _uri;
}
throw new SQLException("Failed to add a record into " + uri);
}
#Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
Log.e(TAG, "inside RR3ContentProvider query method");
db = nfcAppObj.getDb();
SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
switch (uriMatcher.match(uri)) {
case PHONES:
Log.e(TAG, "CASE PHONES");
qb.setTables(TABLEPHONE);
qb.setProjectionMap(PHONE_PROJECTION_MAP);
if (sortOrder == null || sortOrder == ""){
sortOrder = PHONE_NAME;
}
break;
case PHONE_ID:
Log.e(TAG, "CASE PHONE_ID");
qb.setTables(TABLEPHONE);
qb.appendWhere( _ID_PHONENUMBERS + "=" + uri.getPathSegments().get(1));
if (sortOrder == null || sortOrder == ""){
sortOrder = PHONE_NAME;
}
break;
case MESSAGES:
Log.e(TAG, "CASE MESSAGES");
qb.setTables(TABLEMESSAGE);
qb.setProjectionMap(MESSAGE_PROJECTION_MAP);
if (sortOrder == null || sortOrder == ""){
sortOrder = MESSAGE_CREATED_AT + " DESC";
}
break;
case MESSAGE_ID:
Log.e(TAG, "CASE MESAAGE_ID");
qb.setTables(TABLEMESSAGE);
qb.appendWhere( _ID_MESSAGES + "=" + uri.getPathSegments().get(1));
if (sortOrder == null || sortOrder == ""){
sortOrder = MESSAGE_CREATED_AT + " DESC";
}
break;
case TRANSACTIONS:
Log.e(TAG, "CASE TRANSACTIONS");
qb.setTables(TABLETRANSACTIONS);
qb.setProjectionMap(TRANSACTIONS_PROJECTION_MAP);
if (sortOrder == null || sortOrder == ""){
sortOrder = TRANSACTIONS_TAG_SCAN_TIME + " DESC";
}
break;
case TRANSACTION_ID:
Log.e(TAG, "CASE TRANSACTION_ID");
qb.setTables(TABLETRANSACTIONS);
qb.appendWhere( _ID_TRANSACTIONS + "=" + uri.getPathSegments().get(1));
if (sortOrder == null || sortOrder == ""){
sortOrder = TRANSACTIONS_TAG_SCAN_TIME + " DESC";
}
break;
default:
throw new IllegalArgumentException("Unknown URI " + uri);
}
// switch (uriMatcher.match(uri)) {
// case PHONES:
//
// if (sortOrder == null || sortOrder == ""){
//
// sortOrder = PHONE_NAME;
// }
//
// break;
//
// case PHONE_ID:
//
// if (sortOrder == null || sortOrder == ""){
//
// sortOrder = PHONE_NAME;
// }
//
// break;
//
//
// case MESSAGES:
//
// if (sortOrder == null || sortOrder == ""){
//
// sortOrder = MESSAGE_CREATED_AT + " DESC";
// }
//
// break;
//
// case MESSAGE_ID:
//
// if (sortOrder == null || sortOrder == ""){
//
// sortOrder = MESSAGE_CREATED_AT + " DESC";
// }
//
// break;
//
// default:
//
// throw new IllegalArgumentException("Unknown URI " + uri);
// }
//
Log.e(TAG, "About to do the query method in content provider");
Cursor c = qb.query(db, projection, selection, selectionArgs,
null, null, sortOrder);
/**
* register to watch a content URI for changes
*/
c.setNotificationUri(getContext().getContentResolver(), uri);
return c;
}//end of query
#Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
db = nfcAppObj.getDb();
int count = 0;
switch (uriMatcher.match(uri)){
case PHONES:
count = db.delete(TABLEPHONE, selection, selectionArgs);
break;
case PHONE_ID:
String id = uri.getPathSegments().get(1);
count = db.delete( TABLEPHONE, _ID_PHONENUMBERS + " = " + id +
(!TextUtils.isEmpty(selection) ? " AND (" +
selection + ')' : ""), selectionArgs);
break;
case MESSAGES:
count = db.delete(TABLEMESSAGE, selection, selectionArgs);
break;
case MESSAGE_ID:
String id2 = uri.getPathSegments().get(1);
count = db.delete( TABLEMESSAGE, _ID_MESSAGES + " = " + id2 +
(!TextUtils.isEmpty(selection) ? " AND (" +
selection + ')' : ""), selectionArgs);
break;
default:
throw new IllegalArgumentException("Unknown URI " + uri);
}
getContext().getContentResolver().notifyChange(uri, null);
return count;
}
#Override
public int update(Uri uri, ContentValues values, String selection,
String[] selectionArgs) {
db = nfcAppObj.getDb();
int count = 0;
switch (uriMatcher.match(uri)){
case PHONES:
count = db.update(TABLEPHONE, values,
selection, selectionArgs);
break;
case PHONE_ID:
count = db.update(TABLEPHONE, values, _ID_PHONENUMBERS +
" = " + uri.getPathSegments().get(1) +
(!TextUtils.isEmpty(selection) ? " AND (" +
selection + ')' : ""), selectionArgs);
break;
case MESSAGES:
count = db.update(TABLEMESSAGE, values,
selection, selectionArgs);
break;
case MESSAGE_ID:
count = db.update(TABLEMESSAGE, values, _ID_MESSAGES +
" = " + uri.getPathSegments().get(1) +
(!TextUtils.isEmpty(selection) ? " AND (" +
selection + ')' : ""), selectionArgs);
break;
default:
throw new IllegalArgumentException("Unknown URI " + uri );
}
getContext().getContentResolver().notifyChange(uri, null);
return count;
}//end of delete
#Override
public String getType(Uri uri) {
switch (uriMatcher.match(uri)){
/**
* Get all records
*/
case PHONES:
return "vnd.android.cursor.dir/vnd.example.phonenumbers";
/**
* Get a particular record
*/
case PHONE_ID:
return "vnd.android.cursor.item/vnd.example.phonenumbers";
/**
* Get all records
*/
case MESSAGES:
return "vnd.android.cursor.dir/vnd.example.messages";
/**
* Get a particular record
*/
case MESSAGE_ID:
return "vnd.android.cursor.item/vnd.example.messages";
default:
throw new IllegalArgumentException("Unsupported URI: " + uri);
}
}
}
.
[Edit1]
I have got it working and inserting into the Log table with the following code.
Do i have to do a switch statement in the insert method if i want to specify different tables to insert into?
ContentValues cv = new ContentValues();
cv.putNull(LoginValidate.C_ID_LOG);
cv.putNull(LoginValidate.C_LOG_CALLID);
cv.put(LoginValidate.C_LOG_MESSAGE, logString);
cv.put(LoginValidate.C_LOG_CREATED_TIME, formattedNowTime);
cv.put(LoginValidate.C_LOG_CLIENTID, clientID);
cv.put(LoginValidate.C_LOG_CARERID, carerID);
cv.putNull(LoginValidate.C_LOG_SERVER_TIME);
getContentResolver().insert(RR3ContentProvider.CONTENT_URI_LOG, cv);
ContentValues cv = new ContentValues();
cv.putNull(LoginValidate.C_ID_LOG);
cv.putNull(LoginValidate.C_LOG_CALLID);
cv.put(LoginValidate.C_LOG_MESSAGE, logString);
cv.put(LoginValidate.C_LOG_CREATED_TIME, formattedNowTime);
cv.put(LoginValidate.C_LOG_CLIENTID, clientID);
cv.put(LoginValidate.C_LOG_CARERID, carerID);
cv.putNull(LoginValidate.C_LOG_SERVER_TIME);
getContentResolver().insert(RR3ContentProvider.CONTENT_URI_LOG, cv);
I have followed the below tutorial http://www.vogella.de/articles/AndroidSQLite/article.htm
But getting this exception after clicking on "confirm" button
01-20 10:18:14.585: E/AndroidRuntime(2006): Caused by: java.lang.IllegalArgumentException: Unknown URL content://com.example.todos.contentprovider/todos
01-20 10:18:14.585: E/AndroidRuntime(2006): at android.content.ContentResolver.insert(ContentResolver.java:910)
01-20 10:18:14.585: E/AndroidRuntime(2006): at com.example.todos.TodoDetailActivity.saveState(TodoDetailActivity.java:122)
01-20 10:18:14.585: E/AndroidRuntime(2006): at com.example.todos.TodoDetailActivity.onPause(TodoDetailActivity.java:100)
TodoDetailActivity
public class TodoDetailActivity extends Activity {
private Spinner mCategory;
private EditText mTitleText;
private EditText mBodyText;
private Uri todoUri;
#Override
protected void onCreate(Bundle bundle) {
super.onCreate(bundle);
setContentView(R.layout.todo_edit);
mCategory = (Spinner) findViewById(R.id.category);
mTitleText = (EditText) findViewById(R.id.todo_edit_summary);
mBodyText = (EditText) findViewById(R.id.todo_edit_description);
Button confirmButton = (Button) findViewById(R.id.todo_edit_button);
Bundle extras = getIntent().getExtras();
// check from the saved Instance
todoUri = (bundle == null) ? null : (Uri) bundle
.getParcelable(MyTodoContentProvider.CONTENT_ITEM_TYPE);
// Or passed from the other activity
if (extras != null) {
todoUri = extras
.getParcelable(MyTodoContentProvider.CONTENT_ITEM_TYPE);
fillData(todoUri);
}
confirmButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
if (TextUtils.isEmpty(mTitleText.getText().toString())) {
makeToast();
} else {
setResult(RESULT_OK);
finish();
}
}
});
}
private void fillData(Uri uri) {
String[] projection = { TodoTable.COLUMN_SUMMARY,
TodoTable.COLUMN_DESCRIPTION, TodoTable.COLUMN_CATEGORY };
Cursor cursor = getContentResolver().query(uri, projection, null, null,
null);
if (cursor != null) {
cursor.moveToFirst();
String category = cursor.getString(cursor
.getColumnIndexOrThrow(TodoTable.COLUMN_CATEGORY));
for (int i = 0; i < mCategory.getCount(); i++) {
String s = (String) mCategory.getItemAtPosition(i);
if (s.equalsIgnoreCase(category)) {
mCategory.setSelection(i);
}
}
mTitleText.setText(cursor.getString(cursor
.getColumnIndexOrThrow(TodoTable.COLUMN_SUMMARY)));
mBodyText.setText(cursor.getString(cursor
.getColumnIndexOrThrow(TodoTable.COLUMN_DESCRIPTION)));
// always close the cursor
cursor.close();
}
}
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
saveState();
outState.putParcelable(MyTodoContentProvider.CONTENT_ITEM_TYPE, todoUri);
}
#Override
protected void onPause() {
super.onPause();
saveState();
}
private void saveState() {
String category = (String) mCategory.getSelectedItem();
String summary = mTitleText.getText().toString();
String description = mBodyText.getText().toString();
// only save if either summary or description
// is available
if (description.length() == 0 && summary.length() == 0) {
return;
}
ContentValues values = new ContentValues();
values.put(TodoTable.COLUMN_CATEGORY, category);
values.put(TodoTable.COLUMN_SUMMARY, summary);
values.put(TodoTable.COLUMN_DESCRIPTION, description);
if (todoUri == null) {
// New todo
todoUri = getContentResolver().insert(
MyTodoContentProvider.CONTENT_URI, values);
} else {
// Update todo
getContentResolver().update(todoUri, values, null, null);
}
}
private void makeToast() {
Toast.makeText(TodoDetailActivity.this, "Please maintain a summary",
Toast.LENGTH_LONG).show();
}
}
MyTodoContentProvider
public class MyTodoContentProvider extends ContentProvider{
//database
private TodoDatabaseHelper database;
//Used for the uriMatcher
private static final int TODOS = 10;
private static final int TODO_ID = 20;
private static final String AUTHORITY = "com.example.todos.contentprovider";
private static final String BASE_PATH = "todos";
public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY+ "/" + BASE_PATH);
public static final String CONTENT_TYPE = ContentResolver.CURSOR_DIR_BASE_TYPE +"/todos";
public static final String CONTENT_ITEM_TYPE = ContentResolver.CURSOR_ITEM_BASE_TYPE + "/todo";
private static final UriMatcher sURIMatcher = new UriMatcher(UriMatcher.NO_MATCH);
static {
sURIMatcher.addURI(AUTHORITY, BASE_PATH, TODOS);
sURIMatcher.addURI(AUTHORITY, BASE_PATH + "/#", TODO_ID);
}
#Override
public boolean onCreate()
{
database = new TodoDatabaseHelper(getContext());
return false;
}
#Override
public Cursor query(Uri uri,String[] projection, String selection,
String[] selectionArgs, String sortOrder)
{
// Uisng SQLiteQueryBuilder instead of query() method
SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder();
// check if the caller has requested a column which does not exists
checkColumns(projection);
//set the table
queryBuilder.setTables(TodoTable.TABLE_TODO);
int uriType = sURIMatcher.match(uri);
switch (uriType) {
case TODOS:
break;
case TODO_ID:
// adding the ID to the original query
queryBuilder.appendWhere(TodoTable.COLUMN_ID + "="
+ uri.getLastPathSegment());
break;
default:
throw new IllegalArgumentException("Unknown URI: " + uri);
}
SQLiteDatabase db = database.getWritableDatabase();
Cursor cursor = queryBuilder.query(db, projection, selection,
selectionArgs, null, null, sortOrder);
// make sure that potential listeners are getting notified
cursor.setNotificationUri(getContext().getContentResolver(), uri);
return cursor;
}
#Override
public String getType(Uri uri) {
return null;
}
#Override
public Uri insert(Uri uri, ContentValues values)
{
int uriType = sURIMatcher.match(uri);
SQLiteDatabase sqlDB = database.getWritableDatabase();
long id = 0;
switch (uriType) {
case TODOS:
id = sqlDB.insert(TodoTable.TABLE_TODO, null, values);
break;
default:
throw new IllegalArgumentException("Unknown URI: " + uri);
}
getContext().getContentResolver().notifyChange(uri, null);
return Uri.parse(BASE_PATH + "/" + id);
}
#Override
public int delete(Uri uri, String selection,String[] selectionArgs)
{
int uriType = sURIMatcher.match(uri);
SQLiteDatabase sqlDB = database.getWritableDatabase();
int rowsDeleted = 0;
switch (uriType) {
case TODOS:
rowsDeleted = sqlDB.delete(TodoTable.TABLE_TODO,selection, selectionArgs);
break;
case TODO_ID:
String id = uri.getLastPathSegment();
if(TextUtils.isEmpty(selection))
{
rowsDeleted = sqlDB.delete(TodoTable.TABLE_TODO,TodoTable.COLUMN_ID + "=" + id,null);
}
else
{
rowsDeleted = sqlDB.delete(TodoTable.TABLE_TODO,TodoTable.COLUMN_ID + "=" + id + "and" + selection ,selectionArgs);
}
default:
throw new IllegalArgumentException("Unknown URI: " + uri);
}
getContext().getContentResolver().notifyChange(uri, null);
return rowsDeleted;
}
#Override
public int update(Uri uri,ContentValues values,String selection,String[] selectionArgs)
{
int uriType = sURIMatcher.match(uri);
SQLiteDatabase sqlDb = database.getWritableDatabase();
int rowsUpdated = 0;
switch (uriType) {
case TODOS:
rowsUpdated = sqlDb.update(TodoTable.TABLE_TODO, values, selection, selectionArgs);
break;
case TODO_ID:
String id = uri.getLastPathSegment();
if(TextUtils.isEmpty(selection))
{
rowsUpdated = sqlDb.update(TodoTable.TABLE_TODO, values, TodoTable.COLUMN_ID + "=" + id, null);
}
else
{
rowsUpdated = sqlDb.update(TodoTable.TABLE_TODO, values, TodoTable.COLUMN_ID + "=" + id + "and" + selection, selectionArgs);
}
break;
default:
throw new IllegalArgumentException("Unknown URI: " + uri);
}
getContext().getContentResolver().notifyChange(uri, null);
return rowsUpdated;
}
private void checkColumns(String[] projection)
{
String[] available = {TodoTable.COLUMN_CATEGORY,TodoTable.COLUMN_SUMMARY,TodoTable.COLUMN_DESCRIPTION,TodoTable.COLUMN_ID};
HashSet<String> requestedColumns = new HashSet<String>(Arrays.asList(projection));
HashSet<String> availableColumns = new HashSet<String>(Arrays.asList(available));
if(projection != null)
{
if (!availableColumns.containsAll(requestedColumns)) {
throw new IllegalArgumentException("Unknown columns in projection");
}
}
}
}
TodoDatabaseHelper
public class TodoDatabaseHelper extends SQLiteOpenHelper{
private static final String DATABASE_NAME = "todotable.db";
private static final int DATABASE_VERSION = 1;
public TodoDatabaseHelper(Context context)
{
super(context,DATABASE_NAME,null,DATABASE_VERSION);
}
//Method is called during creation of database
#Override
public void onCreate(SQLiteDatabase database)
{
TodoTable.onCreate(database);
}
// Method is called during an upgrade of the database,
// e.g. if you increase the database version
#Override
public void onUpgrade(SQLiteDatabase database, int oldVersion,
int newVersion) {
TodoTable.onUpgrade(database, oldVersion, newVersion);
}
}
You are using
private static final String AUTHORITY = "com.example.todos.contentprovider";
// It should same as you defined in manifest
So this
Caused by: java.lang.IllegalArgumentException: Unknown URL content://com.example.todos.contentprovider/todos
So make sure you define your ContentProvider with same authority in manifest.xml
<provider
android:authorities="com.example.todos.contentprovider"
android:name=".YOUR_ContentProvider" >
</provider>
Hope this will work for you.
Also ensure that you give android:exported="true" in manifest.xml, also ensure they are placed inside </application> not inside </activity>.
<provider
android:name="com.example.todos.contentprovider"
android:authorities="com.example.todos.contentprovider.MyTodoContentProvider"
android:exported="true">
</provider>
I have a ContentProvider that abstracts the info I'm using for a CursorAdapter to populate a list.
I'm building a SearchView in the action bar and want to attach a search ContentProvider to it. Can I use the same provider for this? Is it good design?
The SearchView content would be the same as in #1, it's just used to search a massive listview of items.
The ContentProvider code is below:
public class WebSitesContentProvider extends ContentProvider {
// database
private UserDatabaseHelper database;
// Used for the UriMacher
private static final int TOTAL_ELEMENTS = 10;
private static final int ELEMENT_ID = 20;
private static final String BASE_PATH = "websites";
public static final Uri CONTENT_URI = Uri.parse("content://" + Consts.AUTHORITY + "/" + BASE_PATH);
public static final String CONTENT_TYPE = ContentResolver.CURSOR_DIR_BASE_TYPE + "/website";
public static final String CONTENT_ITEM_TYPE = ContentResolver.CURSOR_ITEM_BASE_TYPE + Consts.TABLE_WEBSITES_INFO;
private static final UriMatcher sURIMatcher = new UriMatcher(UriMatcher.NO_MATCH);
static {
sURIMatcher.addURI(Consts.AUTHORITY, BASE_PATH, TOTAL_ELEMENTS);
sURIMatcher.addURI(Consts.AUTHORITY, BASE_PATH + "/#", ELEMENT_ID);
}
#Override
public boolean onCreate() {
database = new UserDatabaseHelper(getContext());
return false;
}
#Override
public String getType(Uri uri) {
return null;
}
#Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
// UsIng SQLiteQueryBuilder instead of query() method
SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder();
// Check if the caller has requested a column which does not exists
checkColumns(projection);
// Set the table
queryBuilder.setTables(Consts.TABLE_WEBSITES_INFO);
int uriType = sURIMatcher.match(uri);
switch (uriType) {
case TOTAL_ELEMENTS:
break;
case ELEMENT_ID:
// Adding the ID to the original query
queryBuilder.appendWhere(Consts.COLUMN_ID + "=" + uri.getLastPathSegment());
break;
default:
throw new IllegalArgumentException("Unknown URI: " + uri);
}
SQLiteDatabase db = database.getWritableDatabase();
Cursor cursor = queryBuilder.query(db, projection, selection, selectionArgs, null, null, sortOrder);
// Make sure that potential listeners are getting notified
cursor.setNotificationUri(getContext().getContentResolver(), uri);
return cursor;
}
#Override
public Uri insert(Uri uri, ContentValues values) {
int uriType = sURIMatcher.match(uri);
SQLiteDatabase sqlDB = database.getWritableDatabase();
int rowsDeleted = 0;
long id = 0;
switch (uriType) {
case TOTAL_ELEMENTS:
id = sqlDB.insert(Consts.TABLE_WEBSITES_INFO, null, values);
break;
default:
throw new IllegalArgumentException("Unknown URI: " + uri);
}
getContext().getContentResolver().notifyChange(uri, null);
return Uri.parse(BASE_PATH + "/" + id);
}
#Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
int uriType = sURIMatcher.match(uri);
SQLiteDatabase sqlDB = database.getWritableDatabase();
int rowsDeleted = 0;
switch (uriType) {
case TOTAL_ELEMENTS:
rowsDeleted = sqlDB.delete(Consts.TABLE_WEBSITES_INFO,
selection,
selectionArgs);
break;
case ELEMENT_ID:
String id = uri.getLastPathSegment();
if (TextUtils.isEmpty(selection)) {
rowsDeleted = sqlDB.delete(Consts.TABLE_WEBSITES_INFO,
Consts.COLUMN_ID + "=" + id,
null);
} else {
rowsDeleted = sqlDB.delete(Consts.TABLE_WEBSITES_INFO,
Consts.COLUMN_ID + "=" + id + " and " + selection,
selectionArgs);
}
break;
default:
throw new IllegalArgumentException("Unknown URI: " + uri);
}
/*
* Let's not notify content observers on deletes of less then 1 as each delete would cause a network call.
* user could delete multiple entries at once. if the deletes are greater then 1 then it's probably a
* request to remove the entire list, this we will allow
*/
//if(rowsDeleted>1)
getContext().getContentResolver().notifyChange(uri, null);
return rowsDeleted;
}
#Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
int uriType = sURIMatcher.match(uri);
SQLiteDatabase sqlDB = database.getWritableDatabase();
int rowsUpdated = 0;
switch (uriType) {
case TOTAL_ELEMENTS:
rowsUpdated = sqlDB.update(Consts.TABLE_WEBSITES_INFO,
values,
selection,
selectionArgs);
break;
case ELEMENT_ID:
String id = uri.getLastPathSegment();
if (TextUtils.isEmpty(selection)) {
rowsUpdated = sqlDB.update(Consts.TABLE_WEBSITES_INFO,
values,
Consts.COLUMN_ID + "=" + id,
null);
} else {
rowsUpdated = sqlDB.update(Consts.TABLE_WEBSITES_INFO,
values,
Consts.COLUMN_ID + "=" + id + " and " + selection,
selectionArgs);
}
break;
default:
throw new IllegalArgumentException("Unknown URI: " + uri);
}
getContext().getContentResolver().notifyChange(uri, null);
return rowsUpdated;
}
private void checkColumns(String[] projection) {
String[] available = {
Consts.COLUMN_USER,
Consts.COLUMN_ID
};
if (projection != null) {
HashSet<String> requestedColumns = new HashSet<String>(Arrays.asList(projection));
HashSet<String> availableColumns = new HashSet<String>(Arrays.asList(available));
// Check if all columns which are requested are available
if (!availableColumns.containsAll(requestedColumns)) {
throw new IllegalArgumentException("Unknown columns in projection");
}
}
}
}
UPDATE
ContentProviders are generic and I agree on this.
They can be adapted.
So I adapted mine to handle SearchView data content.
Below is the entire ContentProvider acting as both a SearchView content provider and a ListView cursor adapter for anyone interested:
package org.jefferyemanuel.database;
import java.util.Arrays;
import java.util.HashSet;
import org.jefferyemanuel.bulkwebsites.Consts;
import org.jefferyemanuel.bulkwebsites.Utils;
import android.app.SearchManager;
import android.content.ContentProvider;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.MatrixCursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteQueryBuilder;
import android.net.Uri;
import android.provider.BaseColumns;
import android.text.TextUtils;
import android.util.Log;
public class WebSitesContentProvider extends ContentProvider {
/* define out search provider structures */
// UriMatcher constant for search suggestions
private static final int SEARCH_SUGGEST = 1;
private static final String[] SEARCH_SUGGEST_COLUMNS = {
BaseColumns._ID,
SearchManager.SUGGEST_COLUMN_TEXT_1,
SearchManager.SUGGEST_COLUMN_INTENT_DATA,
SearchManager.SUGGEST_COLUMN_INTENT_EXTRA_DATA,
SearchManager.SUGGEST_COLUMN_SHORTCUT_ID
};
// database
private UserDatabaseHelper database;
// Used for the UriMacher
private static final int TOTAL_ELEMENTS = 10;
private static final int ELEMENT_ID = 20;
private static final String BASE_PATH = "websites";
public static final Uri CONTENT_URI = Uri.parse("content://" + Consts.AUTHORITY + "/" + BASE_PATH);
public static final String CONTENT_TYPE = ContentResolver.CURSOR_DIR_BASE_TYPE + "/website";
public static final String CONTENT_ITEM_TYPE = ContentResolver.CURSOR_ITEM_BASE_TYPE + Consts.TABLE_WEBSITES_INFO;
private static final UriMatcher sURIMatcher = new UriMatcher(UriMatcher.NO_MATCH);
static {
sURIMatcher.addURI(Consts.AUTHORITY, BASE_PATH, TOTAL_ELEMENTS);
sURIMatcher.addURI(Consts.AUTHORITY, BASE_PATH + "/#", ELEMENT_ID);
sURIMatcher.addURI(Consts.AUTHORITY, SearchManager.SUGGEST_URI_PATH_QUERY, SEARCH_SUGGEST);
sURIMatcher.addURI(Consts.AUTHORITY, SearchManager.SUGGEST_URI_PATH_QUERY + "/*", SEARCH_SUGGEST);
}
#Override
public boolean onCreate() {
database = new UserDatabaseHelper(getContext());
return false;
}
#Override
public String getType(Uri uri) {
return null;
}
#Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
// UsIng SQLiteQueryBuilder instead of query() method
SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder();
// Check if the caller has requested a column which does not exists
checkColumns(projection);
// Set the table
queryBuilder.setTables(Consts.TABLE_WEBSITES_INFO);
int uriType = sURIMatcher.match(uri);
switch (uriType) {
case TOTAL_ELEMENTS:
break;
case SEARCH_SUGGEST:
queryBuilder.appendWhere(Consts.COLUMN_NAME + " LIKE '%" + uri.getLastPathSegment() + "%'");
break;
case ELEMENT_ID:
// Adding the ID to the original query
queryBuilder.appendWhere(Consts.COLUMN_ID + "=" + uri.getLastPathSegment());
break;
default:
throw new IllegalArgumentException("Unknown URI: " + uri);
}
SQLiteDatabase db = database.getWritableDatabase();
Cursor cursor = queryBuilder.query(db, projection, selection, selectionArgs, null, null, sortOrder);
/*
* If this request is from a SearchView then convert cursor to search Matrix cursor.
*/
if (uriType == SEARCH_SUGGEST)
cursor = buildSearchMatrixCursorFromStandardCursor(cursor);
// Make sure that potential listeners are getting notified
cursor.setNotificationUri(getContext().getContentResolver(), uri);
return cursor;
}
#Override
public Uri insert(Uri uri, ContentValues values) {
int uriType = sURIMatcher.match(uri);
SQLiteDatabase sqlDB = database.getWritableDatabase();
int rowsDeleted = 0;
long id = 0;
switch (uriType) {
case TOTAL_ELEMENTS:
id = sqlDB.insert(Consts.TABLE_WEBSITES_INFO, null, values);
break;
default:
throw new IllegalArgumentException("Unknown URI: " + uri);
}
getContext().getContentResolver().notifyChange(uri, null);
return Uri.parse(BASE_PATH + "/" + id);
}
#Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
int uriType = sURIMatcher.match(uri);
SQLiteDatabase sqlDB = database.getWritableDatabase();
int rowsDeleted = 0;
switch (uriType) {
case TOTAL_ELEMENTS:
rowsDeleted = sqlDB.delete(Consts.TABLE_WEBSITES_INFO, selection, selectionArgs);
break;
case ELEMENT_ID:
String id = uri.getLastPathSegment();
if (TextUtils.isEmpty(selection)) {
rowsDeleted = sqlDB.delete(Consts.TABLE_WEBSITES_INFO,
Consts.COLUMN_ID + "=" + id,
null);
} else {
rowsDeleted = sqlDB.delete(Consts.TABLE_WEBSITES_INFO,
Consts.COLUMN_ID + "=" + id + " and " + selection,
selectionArgs);
}
break;
default:
throw new IllegalArgumentException("Unknown URI: " + uri);
}
getContext().getContentResolver().notifyChange(uri, null);
return rowsDeleted;
}
#Override
public int update(Uri uri, ContentValues values, String selection,
String[] selectionArgs) {
int uriType = sURIMatcher.match(uri);
SQLiteDatabase sqlDB = database.getWritableDatabase();
int rowsUpdated = 0;
switch (uriType) {
case TOTAL_ELEMENTS:
rowsUpdated = sqlDB.update(Consts.TABLE_WEBSITES_INFO, values,
selection, selectionArgs);
break;
case ELEMENT_ID:
String id = uri.getLastPathSegment();
if (TextUtils.isEmpty(selection)) {
rowsUpdated = sqlDB.update(Consts.TABLE_WEBSITES_INFO, values,
Consts.COLUMN_ID + "=" + id,
null);
} else {
rowsUpdated = sqlDB.update(Consts.TABLE_WEBSITES_INFO, values,
Consts.COLUMN_ID + "=" + id + " and " + selection,
selectionArgs);
}
break;
default:
throw new IllegalArgumentException("Unknown URI: " + uri);
}
getContext().getContentResolver().notifyChange(uri, null);
return rowsUpdated;
}
private void checkColumns(String[] projection) {
String[] available = { Consts.COLUMN_NAME, Consts.COLUMN_ID };
if (projection != null) {
HashSet<String> requestedColumns = new HashSet<String>(Arrays.asList(projection));
HashSet<String> availableColumns = new HashSet<String>(Arrays.asList(available));
// Check if all columns which are requested are available
if (!availableColumns.containsAll(requestedColumns)) {
throw new IllegalArgumentException("Unknown columns in projection");
}
}
}
/*
* KEY METHOD THAT USES THE DATA FROM DATABASE THAT LISTVIEW ALSO USES
* TO CREATE A MATRIX CURSOR TO SEND BACK TO SEARCHVIEW
*/
private Cursor buildSearchMatrixCursorFromStandardCursor(Cursor cursor) {
MatrixCursor cursorSearch = new MatrixCursor(SEARCH_SUGGEST_COLUMNS);
int id = 0;
int index = cursor.getColumnIndex(Consts.COLUMN_NAME);
cursor.moveToFirst();
while (!cursor.isAfterLast()) {
String name = cursor.getString(index);
cursorSearch.addRow(new String[] {
String.valueOf(++id),
name,
name,
name,
SearchManager.SUGGEST_NEVER_MAKE_SHORTCUT
});
cursor.moveToNext();
}
return cursorSearch;
}
}
The ContentProvider you're using is generic and can be used for a search feature.
You may think at first that maybe you should write a ContentProvider that specifically works for search but:
You will have to duplicate a lot of code.
ContentProviders are not designed to be specific, they just abstract the access to data.
Your "Search Content Provider" will be used to make queries and you already have that with the Content Provider you have.
The ContentProvider doesn't need to be specific to search.
On the other hand, your Adpater should be specific.
I followed a tutorial about sqlite and content providers but it had only examples for a single table, I eventually managed to figure how to expand that provider to include two tables and everything seems to be working fine.
The app I'm trying to make as a self excercise has right now a todo mode and a notes mode, the classes are almost iedntical, the only difference is a few database column entries.
The todo mode (which was in the example) works perfectly, I can create new entries, view and delete them, while the notes mode can create and delete entries but for some bizarre reason it can't open them as it gives me an exception about the uri not being recognized.
This is the error I'm getting:
02-28 10:08:40.343: E/AndroidRuntime(20079): FATAL EXCEPTION: main
02-28 10:08:40.343: E/AndroidRuntime(20079): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.jackomel.maddonote/com.jackomel.maddonote.NotesDetailActivity}: java.lang.IllegalArgumentException: Unknown URI: content://com.jackomel.maddonote.contentprovider/maddonote/1
02-28 10:08:40.343: E/AndroidRuntime(20079): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2304)
02-28 10:08:40.343: E/AndroidRuntime(20079): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2354)
02-28 10:08:40.343: E/AndroidRuntime(20079): at android.app.ActivityThread.access$600(ActivityThread.java:150)
02-28 10:08:40.343: E/AndroidRuntime(20079): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1244)
02-28 10:08:40.343: E/AndroidRuntime(20079): at android.os.Handler.dispatchMessage(Handler.java:99)
02-28 10:08:40.343: E/AndroidRuntime(20079): at android.os.Looper.loop(Looper.java:137)
02-28 10:08:40.343: E/AndroidRuntime(20079): at android.app.ActivityThread.main(ActivityThread.java:5191)
02-28 10:08:40.343: E/AndroidRuntime(20079): at java.lang.reflect.Method.invokeNative(Native Method)
02-28 10:08:40.343: E/AndroidRuntime(20079): at java.lang.reflect.Method.invoke(Method.java:511)
02-28 10:08:40.343: E/AndroidRuntime(20079): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:795)
02-28 10:08:40.343: E/AndroidRuntime(20079): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:562)
02-28 10:08:40.343: E/AndroidRuntime(20079): at dalvik.system.NativeStart.main(Native Method)
02-28 10:08:40.343: E/AndroidRuntime(20079): Caused by: java.lang.IllegalArgumentException: Unknown URI: content://com.jackomel.maddonote.contentprovider/maddonote/1
02-28 10:08:40.343: E/AndroidRuntime(20079): at com.jackomel.maddonote.contentprovider.MyTodoContentProvider.query(MyTodoContentProvider.java:103)
02-28 10:08:40.343: E/AndroidRuntime(20079): at android.content.ContentProvider.query(ContentProvider.java:652)
02-28 10:08:40.343: E/AndroidRuntime(20079): at android.content.ContentProvider$Transport.query(ContentProvider.java:189)
02-28 10:08:40.343: E/AndroidRuntime(20079): at android.content.ContentResolver.query(ContentResolver.java:372)
02-28 10:08:40.343: E/AndroidRuntime(20079): at android.content.ContentResolver.query(ContentResolver.java:315)
02-28 10:08:40.343: E/AndroidRuntime(20079): at com.jackomel.maddonote.NotesDetailActivity.fillData(NotesDetailActivity.java:102)
02-28 10:08:40.343: E/AndroidRuntime(20079): at com.jackomel.maddonote.NotesDetailActivity.onCreate(NotesDetailActivity.java:56)
02-28 10:08:40.343: E/AndroidRuntime(20079): at android.app.Activity.performCreate(Activity.java:5104)
02-28 10:08:40.343: E/AndroidRuntime(20079): at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1080)
02-28 10:08:40.343: E/AndroidRuntime(20079): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2258)
02-28 10:08:40.343: E/AndroidRuntime(20079): ... 11 more
This is the content provider I have right now (skipping posting all the imports)
public class MyMaddoContentProvider extends ContentProvider {
// Database
private MaddoDatabaseHelper database;
// Used for urlMacher
private static final int TODOS = 10;
private static final int TODO_ID = 20;
private static final int NOTES = 11;
private static final int NOTE_ID = 21;
private static final String AUTHORITY = "com.jackomel.maddonote.contentprovider";
private static final String BASE_PATH = "maddo";
//private static final String NOTE_PATH = "notes";
public static final Uri TODO_URI = Uri.parse("content://" + AUTHORITY + "/" + BASE_PATH + "todo");
public static final Uri NOTE_URI = Uri.parse("content://" + AUTHORITY + "/" + BASE_PATH + "note");
public static final String CONTENT_TYPE_TODO = ContentResolver.CURSOR_DIR_BASE_TYPE + "/todos";
public static final String CONTENT_ITEM_TYPE_TODO = ContentResolver.CURSOR_ITEM_BASE_TYPE + "/todo";
public static final String CONTENT_TYPE_NOTE = ContentResolver.CURSOR_DIR_BASE_TYPE + "/notes";
public static final String CONTENT_ITEM_TYPE_NOTE = ContentResolver.CURSOR_ITEM_BASE_TYPE + "/note";
public static final String[] todoAvailable = { TodoTable.COLUMN_CATEGORY,
TodoTable.COLUMN_SUMMARY, TodoTable.COLUMN_DESCRIPTION,
TodoTable.COLUMN_ID };
public static final String[] noteAvailable = { NotesTable.COLUMN_CATEGORY,
NotesTable.COLUMN_SUMMARY, NotesTable.COLUMN_CONTENT, NotesTable.COLUMN_DATE,
TodoTable.COLUMN_ID
};
private static final UriMatcher sURIMatcher = new UriMatcher(
UriMatcher.NO_MATCH);
static {
sURIMatcher.addURI(AUTHORITY, BASE_PATH + "todo", TODOS);
sURIMatcher.addURI(AUTHORITY, BASE_PATH + "todo" + "/#", TODO_ID);
sURIMatcher.addURI(AUTHORITY, BASE_PATH + "note", NOTES);
sURIMatcher.addURI(AUTHORITY, BASE_PATH + "note" + "/#", NOTE_ID);
}
#Override
public boolean onCreate() {
database = new MaddoDatabaseHelper(getContext());
return false;
}
#Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
// Using SQLiteQueryBuilder instead of query() method
SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder();
// Check if the caller has requested a column which does not exists
//checkColumns(projection);
// Set the table
//queryBuilder.setTables(TodoTable.TABLE_NAME);
int uriType = sURIMatcher.match(uri);
checkColumns(projection, uriType);
switch (uriType) {
case TODOS:
queryBuilder.setTables(TodoTable.TABLE_NAME);
break;
case TODO_ID:
queryBuilder.setTables(TodoTable.TABLE_NAME);
// Adding the ID to the original query
queryBuilder.appendWhere(TodoTable.COLUMN_ID + "="
+ uri.getLastPathSegment());
break;
case NOTES:
queryBuilder.setTables(NotesTable.TABLE_NAME);
break;
case NOTE_ID:
queryBuilder.setTables(NotesTable.TABLE_NAME);
queryBuilder.appendWhere(NotesTable.COLUMN_ID + "=" + uri.getLastPathSegment());
default:
throw new IllegalArgumentException("Unknown URI: " + uri);
}
SQLiteDatabase db = database.getWritableDatabase();
Cursor cursor = queryBuilder.query(db, projection, selection,
selectionArgs, null, null, sortOrder);
// Make sure that potential listeners are getting notified
cursor.setNotificationUri(getContext().getContentResolver(), uri);
return cursor;
}
#Override
public String getType(Uri uri) {
return null;
}
#Override
public Uri insert(Uri uri, ContentValues values) {
int uriType = sURIMatcher.match(uri);
SQLiteDatabase sqlDB = database.getWritableDatabase();
int rowsDeleted = 0;
long id = 0;
String curPath;
switch (uriType) {
case TODOS:
System.out.println("Inserimento in tabella TODOS");
id = sqlDB.insert(TodoTable.TABLE_NAME, null, values);
curPath = "todo";
break;
case NOTES:
System.out.println("Inserimento in tabella NOTES");
id = sqlDB.insert(NotesTable.TABLE_NAME, null, values);
curPath = "note";
break;
default:
throw new IllegalArgumentException("Unknown URI: " + uri);
}
getContext().getContentResolver().notifyChange(uri, null);
return Uri.parse(BASE_PATH + curPath + "/" + id);
}
#Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
int uriType = sURIMatcher.match(uri);
SQLiteDatabase sqlDB = database.getWritableDatabase();
int rowsDeleted = 0;
String id;
switch (uriType) {
case NOTES:
rowsDeleted = sqlDB.delete(NotesTable.TABLE_NAME, selection, selectionArgs);
break;
case NOTE_ID:
id = uri.getLastPathSegment();
if (TextUtils.isEmpty(selection)) {
rowsDeleted = sqlDB.delete(NotesTable.TABLE_NAME, NotesTable.COLUMN_ID + "=" + id, null);
} else {
rowsDeleted = sqlDB.delete(NotesTable.TABLE_NAME, NotesTable.COLUMN_ID + "=" +
id + " and " + selection, selectionArgs);
break;
}
case TODOS:
rowsDeleted = sqlDB.delete(TodoTable.TABLE_NAME, selection,
selectionArgs);
break;
case TODO_ID:
id = uri.getLastPathSegment();
if (TextUtils.isEmpty(selection)) {
rowsDeleted = sqlDB.delete(TodoTable.TABLE_NAME,
TodoTable.COLUMN_ID + "=" + id, null);
} else {
rowsDeleted = sqlDB.delete(TodoTable.TABLE_NAME,
TodoTable.COLUMN_ID + "=" + id + " and " + selection,
selectionArgs);
}
break;
default:
throw new IllegalArgumentException("Unknown URI: " + uri);
}
getContext().getContentResolver().notifyChange(uri, null);
return rowsDeleted;
}
#Override
public int update(Uri uri, ContentValues values, String selection,
String[] selectionArgs) {
int uriType = sURIMatcher.match(uri);
SQLiteDatabase sqlDB = database.getWritableDatabase();
int rowsUpdated = 0;
String id;
switch (uriType) {
case NOTES:
rowsUpdated = sqlDB.update(NotesTable.TABLE_NAME, values, selection, selectionArgs);
break;
case NOTE_ID:
id = uri.getLastPathSegment();
if (TextUtils.isEmpty(selection)) {
rowsUpdated = sqlDB.update(NotesTable.TABLE_NAME, values,
NotesTable.COLUMN_ID + "=" + id, null);
} else {
rowsUpdated = sqlDB.update(TodoTable.TABLE_NAME, values,
NotesTable.COLUMN_ID + "=" + id + " and " + selection, selectionArgs);
}
break;
case TODOS:
rowsUpdated = sqlDB.update(TodoTable.TABLE_NAME, values, selection,
selectionArgs);
break;
case TODO_ID:
id = uri.getLastPathSegment();
if (TextUtils.isEmpty(selection)) {
rowsUpdated = sqlDB.update(TodoTable.TABLE_NAME, values,
TodoTable.COLUMN_ID + "=" + id, null);
} else {
rowsUpdated = sqlDB.update(TodoTable.TABLE_NAME, values,
TodoTable.COLUMN_ID + "=" + id + " and " + selection,
selectionArgs);
}
break;
default:
throw new IllegalArgumentException("Unknown URI: " + uri);
}
getContext().getContentResolver().notifyChange(uri, null);
return rowsUpdated;
}
private void checkColumns(String[] projection, int uriType) {
if (projection != null) {
HashSet<String> requestedColumns = new HashSet<String>(
Arrays.asList(projection));
HashSet<String> availableColumns = null;
switch (uriType) {
case TODOS: case TODO_ID:
availableColumns = new HashSet<String>(
Arrays.asList(todoAvailable));
break;
case NOTES: case NOTE_ID:
availableColumns = new HashSet<String>(
Arrays.asList(noteAvailable));
break;
}
// Check if all columns which are requested are available
if (!availableColumns.containsAll(requestedColumns)) {
throw new IllegalArgumentException(
"Unknown columns in projection");
}
}
}
}
And these are the activities in which the error is caused (again skipping imports):
public class NotesOverviewActivity extends ListActivity implements
LoaderManager.LoaderCallbacks<Cursor>{
private static final int ACTIVITY_CREATE = 0;
private static final int ACTIVITY_EDIT = 1;
private static final int DELETE_ID = Menu.FIRST + 1;
// private Cursor cursor;
private SimpleCursorAdapter adapter;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.notes_list);
this.getListView().setDividerHeight(2);
fillData();
registerForContextMenu(getListView());
}
// Create the menu based on the XML defintion
#Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.listmenu, menu);
return true;
}
// Reaction to the menu selection
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.insert:
createNote();
return true;
}
return super.onOptionsItemSelected(item);
}
#Override
public boolean onContextItemSelected(MenuItem item) {
switch (item.getItemId()) {
case DELETE_ID:
AdapterContextMenuInfo info = (AdapterContextMenuInfo) item
.getMenuInfo();
Uri uri = Uri.parse(MyMaddoContentProvider.NOTE_URI + "/"
+ info.id);
getContentResolver().delete(uri, null, null);
fillData();
return true;
}
return super.onContextItemSelected(item);
}
private void createNote() {
Intent i = new Intent(this, NotesDetailActivity.class);
startActivity(i);
}
// Opens the second activity if an entry is clicked
#Override
protected void onListItemClick(ListView l, View v, int position, long id) {
super.onListItemClick(l, v, position, id);
Intent i = new Intent(this, NotesDetailActivity.class);
Uri notesUri = Uri.parse(MyMaddoContentProvider.NOTE_URI + "/" + id);
i.putExtra(MyMaddoContentProvider.CONTENT_ITEM_TYPE_NOTE, notesUri);
startActivity(i);
}
private void fillData() {
// Fields from the database (projection)
// Must include the _id column for the adapter to work
String[] from = new String[] { NotesTable.COLUMN_SUMMARY };
// Fields on the UI to which we map
int[] to = new int[] { R.id.label };
getLoaderManager().initLoader(0, null, this);
adapter = new SimpleCursorAdapter(this, R.layout.notes_row, null, from,
to, 0);
setListAdapter(adapter);
}
#Override
public void onCreateContextMenu(ContextMenu menu, View v,
ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, v, menuInfo);
menu.add(0, DELETE_ID, 0, R.string.menu_delete);
}
// Creates a new loader after the initLoader () call
#Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
String[] projection = { NotesTable.COLUMN_ID, NotesTable.COLUMN_SUMMARY };
CursorLoader cursorLoader = new CursorLoader(this,
MyMaddoContentProvider.NOTE_URI, projection, null, null, null);
return cursorLoader;
}
#Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
adapter.swapCursor(data);
}
#Override
public void onLoaderReset(Loader<Cursor> loader) {
// data is not available anymore, delete reference
adapter.swapCursor(null);
}
}
the error seems to happen in the onListenClick method, right after it starts the notesDetailActivity, which I'm including below
public class NotesDetailActivity extends Activity {
private Spinner mCategory;
private EditText mTitleText;
private EditText mBodyText;
private EditText mDateText;
private Uri noteUri;
#Override
protected void onCreate(Bundle bundle) {
super.onCreate(bundle);
setContentView(R.layout.notes_edit);
mCategory = (Spinner) findViewById(R.id.category);
mTitleText = (EditText) findViewById(R.id.todo_edit_summary);
mBodyText = (EditText) findViewById(R.id.todo_edit_description);
mDateText = (EditText)findViewById(R.id.date);
mDateText.setText(java.text.DateFormat.getTimeInstance().format(Calendar.getInstance().getTime()));
Button confirmButton = (Button) findViewById(R.id.todo_edit_button);
Bundle extras = getIntent().getExtras();
// Check from the saved Instance
noteUri = (bundle == null) ? null : (Uri) bundle
.getParcelable(MyMaddoContentProvider.CONTENT_ITEM_TYPE_NOTE);
// Or passed from the other activity
if (extras != null) {
noteUri = extras
.getParcelable(MyMaddoContentProvider.CONTENT_ITEM_TYPE_NOTE);
fillData(noteUri);
}
confirmButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
if (TextUtils.isEmpty(mTitleText.getText().toString())) {
makeToast();
} else {
setResult(RESULT_OK);
finish();
}
}
});
}
// Create the menu based on the XML defintion
#Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.detailsmenu, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.save:
saveData();
return true;
}
return super.onOptionsItemSelected(item);
}
public void saveData() {
if (TextUtils.isEmpty(mTitleText.getText().toString())) {
makeToast();
} else {
setResult(RESULT_OK);
finish();
}
}
private void fillData(Uri uri) {
String[] projection = { NotesTable.COLUMN_SUMMARY,
NotesTable.COLUMN_CONTENT, NotesTable.COLUMN_CATEGORY, NotesTable.COLUMN_DATE };
Cursor cursor = getContentResolver().query(uri, projection, null, null,
null);
if (cursor != null) {
cursor.moveToFirst();
String category = cursor.getString(cursor
.getColumnIndexOrThrow(NotesTable.COLUMN_CATEGORY));
for (int i = 0; i < mCategory.getCount(); i++) {
String s = (String) mCategory.getItemAtPosition(i);
if (s.equalsIgnoreCase(category)) {
mCategory.setSelection(i);
}
}
mTitleText.setText(cursor.getString(cursor
.getColumnIndexOrThrow(NotesTable.COLUMN_SUMMARY)));
mBodyText.setText(cursor.getString(cursor
.getColumnIndexOrThrow(NotesTable.COLUMN_CONTENT)));
mDateText.setText(cursor.getString(cursor
.getColumnIndexOrThrow(NotesTable.COLUMN_DATE)));
// Always close the cursor
cursor.close();
}
}
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
saveState();
outState.putParcelable(MyMaddoContentProvider.CONTENT_ITEM_TYPE_NOTE, noteUri);
}
#Override
protected void onPause() {
super.onPause();
saveState();
}
private void saveState() {
String category = (String) mCategory.getSelectedItem();
String summary = mTitleText.getText().toString();
String description = mBodyText.getText().toString();
String date = mBodyText.getText().toString();
// Only save if either summary or description
// is available
if (description.length() == 0 && summary.length() == 0) {
return;
}
ContentValues values = new ContentValues();
values.put(NotesTable.COLUMN_CATEGORY, category);
values.put(NotesTable.COLUMN_SUMMARY, summary);
values.put(NotesTable.COLUMN_CONTENT, description);
values.put(NotesTable.COLUMN_DATE, date);
if (noteUri == null) {
// New note
noteUri = getContentResolver().insert(
MyMaddoContentProvider.NOTE_URI, values);
} else {
// Update note
getContentResolver().update(noteUri, values, null, null);
}
}
private void makeToast() {
Toast.makeText(NotesDetailActivity.this, "Please maintain a summary",
Toast.LENGTH_LONG).show();
}
}
I'm obviously doing something wrong with the uri, still no idea exactly what, considering the todo part is almost exactly the same (save for variable names and database table of course) and doesn't give such errors.
What is the problem?
I have followed the same example.. Here is your fix--
change your authority name in both manifest and MyMaddoContentProvider class as follows:-
private static final String AUTHORITY = "com.jackomel.maddonote.contentprovide.MyMaddoContentProviderr";
and
android:name="com.jackomel.maddonote.contentprovider.MyMaddoContentProvider"
android:authorities="com.jackomel.maddonote.contentprovider.MyMaddoContentProvider"
It should probably work now.
I think I may have found a solution to this problem. I was having a similar problem except for my error was saying that I had invalid tables instead of URI's. I followed Jackomels example above for his set tables queries and was able to get my edit to work. His Uri's are set up differently than mine which I am thinking is what the error is about. He uses the same BASE_PATH for both tables but I think that each table needs to have a different "base path".
I have private static final String BASE_PATH = "todos" & private static final String DEVICE_PATH = "devices";
I am pasting my code below in case it helps someone else.
package com.cossioinsurance.rentalsafety.contentprovider2;
import java.util.Arrays;
import java.util.HashSet;
import com.cossioinsurance.rentalsafety.database.TodoDatabaseHelper;
import com.cossioinsurance.rentalsafety.database.NoteTable;
import com.cossioinsurance.rentalsafety.database.DeviceTable;
import android.content.ContentProvider;
import android.content.ContentResolver;
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 MyNoteContentProvider extends ContentProvider{
// database
private TodoDatabaseHelper database;
// used for the UriMacher
private static final int TODOS = 10;
private static final int TODO_ID = 20;
private static final int DEVICES = 30;
private static final int DEVICE_ID = 40;
private static final String AUTHORITY = "com.cossioinsurance.rentalsafety.contentprovider2";
private static final String BASE_PATH = "todos";
private static final String DEVICE_PATH = "devices";
public static final Uri CONTENT_URI_TODOS = Uri.parse("content://" + AUTHORITY
+ "/" + BASE_PATH);
public static final Uri CONTENT_URI_DEVICES = Uri.parse("content://" + AUTHORITY
+ "/" + DEVICE_PATH);
public static final String CONTENT_TYPE_TODOS = ContentResolver.CURSOR_DIR_BASE_TYPE
+ "/todos";
public static final String CONTENT_TYPE_DEVICES = ContentResolver.CURSOR_DIR_BASE_TYPE
+ "/devices";
public static final String CONTENT_ITEM_TYPE = ContentResolver.CURSOR_ITEM_BASE_TYPE
+ "/todo";
public static final String CONTENT_ITEM_TYPE2 = ContentResolver.CURSOR_ITEM_BASE_TYPE
+ "/device";
private static final UriMatcher sURIMatcher = new UriMatcher(UriMatcher.NO_MATCH);
static {
sURIMatcher.addURI(AUTHORITY, BASE_PATH, TODOS);
sURIMatcher.addURI(AUTHORITY, BASE_PATH + "/#", TODO_ID);
sURIMatcher.addURI(AUTHORITY, DEVICE_PATH, DEVICES);
sURIMatcher.addURI(AUTHORITY, DEVICE_PATH + "/#", DEVICE_ID);
}
#Override
public boolean onCreate() {
database = new TodoDatabaseHelper(getContext());
return false;
}
#Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
// Uisng SQLiteQueryBuilder instead of query() method
SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder();
// check if the caller has requested a column which does not exists
checkColumns(projection);
// Set the table
int uriType = sURIMatcher.match(uri);
switch (uriType) {
case TODOS:
queryBuilder.setTables(NoteTable.TABLE_TODO);
break;
case TODO_ID:
queryBuilder.setTables(NoteTable.TABLE_TODO);
// adding the ID to the original query
queryBuilder.appendWhere(NoteTable.COLUMN_ID + "="
+ uri.getLastPathSegment());
break;
case DEVICES:
queryBuilder.setTables(DeviceTable.TABLE_DEVICE);
break;
case DEVICE_ID:
queryBuilder.setTables(DeviceTable.TABLE_DEVICE);
// adding the ID to the original query
queryBuilder.appendWhere(DeviceTable.COLUMN_ID + "="
+ uri.getLastPathSegment());
break;
default:
throw new IllegalArgumentException("Unknown URI: " + uri);
}
SQLiteDatabase db = database.getWritableDatabase();
Cursor cursor = queryBuilder.query(db, projection, selection,
selectionArgs, null, null, sortOrder);
// make sure that potential listeners are getting notified
cursor.setNotificationUri(getContext().getContentResolver(), uri);
return cursor;
}
#Override
public String getType(Uri uri) {
return null;
}
#Override
public Uri insert(Uri uri, ContentValues values) {
int uriType = sURIMatcher.match(uri);
SQLiteDatabase sqlDB = database.getWritableDatabase();
int rowsDeleted = 0;
long id = 0;
switch (uriType) {
case TODOS:
id = sqlDB.insert(NoteTable.TABLE_TODO, null, values);
break;
case DEVICES:
id = sqlDB.insert(DeviceTable.TABLE_DEVICE, null, values);
break;
default:
throw new IllegalArgumentException("Unknown URI: " + uri);
}
getContext().getContentResolver().notifyChange(uri, null);
return Uri.parse(BASE_PATH + "/" + id);
}
//Deleted Rows
#Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
int uriType = sURIMatcher.match(uri);
SQLiteDatabase sqlDB = database.getWritableDatabase();
int rowsDeleted = 0;
String id = uri.getLastPathSegment();
switch (uriType) {
case TODOS:
rowsDeleted = sqlDB.delete(NoteTable.TABLE_TODO, selection,
selectionArgs);
break;
case TODO_ID:
if (TextUtils.isEmpty(selection)) {
rowsDeleted = sqlDB.delete(NoteTable.TABLE_TODO,
NoteTable.COLUMN_ID + "=" + id,
null);
} else {
rowsDeleted = sqlDB.delete(NoteTable.TABLE_TODO,
NoteTable.COLUMN_ID + "=" + id
+ " and " + selection,
selectionArgs);
}
break;
case DEVICES:
rowsDeleted = sqlDB.delete(DeviceTable.TABLE_DEVICE, selection,
selectionArgs);
break;
case DEVICE_ID:
if (TextUtils.isEmpty(selection)) {
rowsDeleted = sqlDB.delete(DeviceTable.TABLE_DEVICE,
DeviceTable.COLUMN_ID + "=" + id,
null);
} else {
rowsDeleted = sqlDB.delete(NoteTable.TABLE_TODO,
DeviceTable.COLUMN_ID + "=" + id
+ " and " + selection,
selectionArgs);
}
break;
default:
throw new IllegalArgumentException("Unknown URI: " + uri);
}
getContext().getContentResolver().notifyChange(uri, null);
return rowsDeleted;
}
//Update Rows
#Override
public int update(Uri uri, ContentValues values, String selection,
String[] selectionArgs) {
int uriType = sURIMatcher.match(uri);
SQLiteDatabase sqlDB = database.getWritableDatabase();
int rowsUpdated = 0;
switch (uriType) {
case TODOS:
rowsUpdated = sqlDB.update(NoteTable.TABLE_TODO,
values,
selection,
selectionArgs);
break;
case TODO_ID:
String id = uri.getLastPathSegment();
if (TextUtils.isEmpty(selection)) {
rowsUpdated = sqlDB.update(NoteTable.TABLE_TODO,
values,
NoteTable.COLUMN_ID + "=" + id,
null);
} else {
rowsUpdated = sqlDB.update(NoteTable.TABLE_TODO,
values,
NoteTable.COLUMN_ID + "=" + id
+ " and "
+ selection,
selectionArgs);
}
break;
case DEVICES:
rowsUpdated = sqlDB.update(DeviceTable.TABLE_DEVICE,
values,
selection,
selectionArgs);
break;
case DEVICE_ID:
id = uri.getLastPathSegment();
if (TextUtils.isEmpty(selection)) {
rowsUpdated = sqlDB.update(DeviceTable.TABLE_DEVICE,
values,
DeviceTable.COLUMN_ID + "=" + id,
null);
} else {
rowsUpdated = sqlDB.update(DeviceTable.TABLE_DEVICE,
values,
DeviceTable.COLUMN_ID + "=" + id
+ " and "
+ selection,
selectionArgs);
}
break;
default:
throw new IllegalArgumentException("Unknown URI: " + uri);
}
getContext().getContentResolver().notifyChange(uri, null);
return rowsUpdated;
}
private void checkColumns(String[] projection) {
String[] available = { NoteTable.COLUMN_CATEGORY,
NoteTable.COLUMN_SUMMARY, NoteTable.COLUMN_DESCRIPTION, NoteTable.COLUMN_EMAIL, NoteTable.COLUMN_RENTALDATES,
NoteTable.COLUMN_ENDDATES, NoteTable.COLUMN_TIME, NoteTable.COLUMN_LOCATION, NoteTable.COLUMN_NOTES,
NoteTable.COLUMN_ID, DeviceTable.COLUMN_ID, DeviceTable.COLUMN_CATEGORY, DeviceTable.COLUMN_NAME, DeviceTable.COLUMN_TYPE };
if (projection != null) {
HashSet<String> requestedColumns = new HashSet<String>(Arrays.asList(projection));
HashSet<String> availableColumns = new HashSet<String>(Arrays.asList(available));
// check if all columns which are requested are available
if (!availableColumns.containsAll(requestedColumns)) {
throw new IllegalArgumentException("Unknown columns in projection");
}
}
}
}