【原创】ContentProvider 示例
package com.firewings.smstools; import java.util.HashMap;import java.util.LinkedHashMap;import java.util.List; import android.content.ContentProvider;import android.content.ContentUris;import android.content.ContentValues;import android.content.Context;import android.content.UriMatcher;import android.content.pm.PackageManager;import android.database.Cursor;import android.database.sqlite.SQLiteDatabase;import android.database.sqlite.SQLiteQueryBuilder;import android.database.sqlite.SQLiteTransactionListener;import android.net.Uri;import android.os.Binder;import android.provider.BaseColumns;import android.provider.ContactsContract;import android.provider.SyncStateContract;import android.provider.ContactsContract.Data;import android.provider.ContactsContract.Groups;import android.provider.ContactsContract.RawContacts;import android.util.Log; public class SmsProvider extends ContentProvider implements SQLiteTransactionListener { private static final String TAG = "SmsProvider"; private static final boolean VERBOSE_LOGGING = Log.isLoggable(TAG, Log.VERBOSE); private DbHelper mDbHelper; private SQLiteDatabase mDb; private static final UriMatcher sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH); private static final int SMS = 1000; private static final int SMS_ID = 1001; public static final String SMS_ITEM_TYPE = "vnd.android.cursor.item/sms"; public static final String AUTHORITY = "com.firewings.smstools"; public static final Uri AUTHORITY_URI = Uri.parse("content://" + AUTHORITY); public static final HashMap<string, string=""> sCountProjectionMap; public static final HashMap<string, string=""> smsProjectionMap; static { final UriMatcher matcher = sUriMatcher; matcher.addURI(AUTHORITY, "sms", SMS); matcher.addURI(AUTHORITY, "sms/#", SMS_ID); sCountProjectionMap = new LinkedHashMap<string, string="">(); sCountProjectionMap.put(BaseColumns._COUNT, "COUNT(*)"); smsProjectionMap = new LinkedHashMap<string, string="">(); smsProjectionMap.put(DbHelper.SmsColumns._ID, DbHelper.SmsColumns._ID); smsProjectionMap.put(DbHelper.SmsColumns.ADDRESS, DbHelper.SmsColumns.ADDRESS); smsProjectionMap.put(DbHelper.SmsColumns.PERSON, DbHelper.SmsColumns.PERSON); smsProjectionMap.put(DbHelper.SmsColumns.DATE, DbHelper.SmsColumns.DATE); smsProjectionMap.put(DbHelper.SmsColumns.TYPE, DbHelper.SmsColumns.TYPE); smsProjectionMap.put(DbHelper.SmsColumns.BODY, DbHelper.SmsColumns.BODY); smsProjectionMap.put(DbHelper.SmsColumns.SEND, DbHelper.SmsColumns.SEND); } private final ThreadLocal<boolean> mApplyingBatch = new ThreadLocal<boolean>(); private volatile boolean mNotifyChange; @Override public int delete(Uri uri, String selection, String[] selectionArgs) { int count = 0; boolean applyingBatch = applyingBatch(); if (!applyingBatch) { mDb = mDbHelper.getWritableDatabase(); mDb.beginTransactionWithListener(this); try { count = deleteInTransaction(uri, selection, selectionArgs); if (count > 0) { mNotifyChange = true; } mDb.setTransactionSuccessful(); } finally { mDb.endTransaction(); } onEndTransaction(); } else { count = deleteInTransaction(uri, selection, selectionArgs); if (count > 0) { mNotifyChange = true; } } return count; } protected int deleteInTransaction(Uri uri, String selection, String[] selectionArgs) { if (VERBOSE_LOGGING) { Log.v(TAG, "updateInTransaction: " + uri); } int count = 0; final int match = sUriMatcher.match(uri); switch (match) { case SMS: { count = mDb.delete(DbHelper.Tables.SMS, selection, selectionArgs); break; } case SMS_ID: { long smsId = ContentUris.parseId(uri); if (selection != null) { selectionArgs = selectionArg(selectionArgs, String.valueOf(smsId)); count = mDb.delete(DbHelper.Tables.SMS, RawContacts._ID + "=?" + " AND (" + selection + ")", selectionArgs); } else { count = mDb.delete(DbHelper.Tables.SMS, RawContacts._ID + "=?", new String[] { String.valueOf(smsId) }); } break; } default: { throw new UnsupportedOperationException(exceptionMessage(uri)); } } return count; } @Override public String getType(Uri uri) { final int match = sUriMatcher.match(uri); switch (match) { case SMS: return SMS_ITEM_TYPE; default: throw new IllegalArgumentException(exceptionMessage(uri)); } } /** * Returns a detailed exception message for the supplied URI. It includes * the calling user and calling package(s). */ public String exceptionMessage(Uri uri) { return exceptionMessage(null, uri); } /** * Returns a detailed exception message for the supplied URI. It includes * the calling user and calling package(s). */ public String exceptionMessage(String message, Uri uri) { StringBuilder sb = new StringBuilder(); if (message != null) { sb.append(message).append("; "); } sb.append("URI: ").append(uri); final PackageManager pm = getContext().getPackageManager(); int callingUid = Binder.getCallingUid(); sb.append(", calling user: "); String userName = pm.getNameForUid(callingUid); if (userName != null) { sb.append(userName); } else { sb.append(callingUid); } final String[] callerPackages = pm.getPackagesForUid(callingUid); if (callerPackages != null && callerPackages.length > 0) { if (callerPackages.length == 1) { sb.append(", calling package:"); sb.append(callerPackages); } else { sb.append(", calling package is one of: ["); for (int i = 0; i < callerPackages.length; i++) { if (i != 0) { sb.append(", "); } sb.append(callerPackages); } sb.append("]"); } } return sb.toString(); } private boolean applyingBatch() { return mApplyingBatch.get() != null && mApplyingBatch.get(); } @Override public Uri insert(Uri uri, ContentValues values) { Uri result = null; boolean applyingBatch = applyingBatch(); if (!applyingBatch) { mDb = mDbHelper.getWritableDatabase(); mDb.beginTransactionWithListener(this); try { result = insertInTransaction(uri, values); if (result != null) { mNotifyChange = true; } mDb.setTransactionSuccessful(); } finally { mDb.endTransaction(); } onEndTransaction(); } else { result = insertInTransaction(uri, values); if (result != null) { mNotifyChange = true; } } return result; } protected Uri insertInTransaction(Uri uri, ContentValues values) { if (VERBOSE_LOGGING) { Log.v(TAG, "insertInTransaction: " + uri + " " + values); } final int match = sUriMatcher.match(uri); long id = 0; switch (match) { case SMS: { values.putNull(DbHelper.SmsColumns._ID); id = mDb.insert(DbHelper.Tables.SMS, DbHelper.SmsColumns._ID, values); break; } default: { throw new UnsupportedOperationException(exceptionMessage(uri)); } } if (id < 0) { return null; } return ContentUris.withAppendedId(uri, id); } @Override public boolean onCreate() { try { return initialize(); } catch (RuntimeException e) { Log.e(TAG, "Cannot start provider", e); return false; } } @Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { if (VERBOSE_LOGGING) { Log.v(TAG, "query: " + uri); } final SQLiteDatabase db = mDbHelper.getReadableDatabase(); SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); String groupBy = null; String limit = getLimit(uri); final int match = sUriMatcher.match(uri); switch (match) { case SMS: { setTablesAndProjectionMapForSms(qb, uri); break; } } return query(db, qb, projection, selection, selectionArgs, sortOrder, groupBy, limit); } private Cursor query(final SQLiteDatabase db, SQLiteQueryBuilder qb, String[] projection, String selection, String[] selectionArgs, String sortOrder, String groupBy, String limit) { if (projection != null && projection.length == 1 && BaseColumns._COUNT.equals(projection)) { qb.setProjectionMap(sCountProjectionMap); } final Cursor c = qb.query(db, projection, selection, selectionArgs, groupBy, null, sortOrder, limit); if (c != null) { c.setNotificationUri(getContext().getContentResolver(), AUTHORITY_URI); } return c; } private void setTablesAndProjectionMapForSms(SQLiteQueryBuilder qb, Uri uri) { StringBuilder sb = new StringBuilder(); sb.append(DbHelper.Tables.SMS); qb.setTables(sb.toString()); qb.setProjectionMap(smsProjectionMap); } @Override public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { int count = 0; boolean applyingBatch = applyingBatch(); if (!applyingBatch) { mDb = mDbHelper.getWritableDatabase(); mDb.beginTransactionWithListener(this); try { count = updateInTransaction(uri, values, selection, selectionArgs); if (count > 0) { mNotifyChange = true; } mDb.setTransactionSuccessful(); } finally { mDb.endTransaction(); } onEndTransaction(); } else { count = updateInTransaction(uri, values, selection, selectionArgs); if (count > 0) { mNotifyChange = true; } } return count; } protected int updateInTransaction(Uri uri, ContentValues values, String selection, String[] selectionArgs) { if (VERBOSE_LOGGING) { Log.v(TAG, "updateInTransaction: " + uri); } int count = 0; final int match = sUriMatcher.match(uri); switch (match) { case SMS: { count = mDb.update(DbHelper.Tables.SMS, values, selection, selectionArgs); break; } case SMS_ID: { long smsId = ContentUris.parseId(uri); if (selection != null) { selectionArgs = selectionArg(selectionArgs, String.valueOf(smsId)); count = mDb.update(DbHelper.Tables.SMS, values, RawContacts._ID + "=?" + " AND (" + selection + ")", selectionArgs); } else { count = mDb.update(DbHelper.Tables.SMS, values, RawContacts._ID + "=?", new String[] { String.valueOf(smsId) }); } break; } default: { throw new UnsupportedOperationException(exceptionMessage(uri)); } } return count; } /** * Inserts an argument at the beginning of the selection arg list. */ private String[] selectionArg(String[] selectionArgs, String arg) { if (selectionArgs == null) { return new String[] { arg }; } else { int newLength = selectionArgs.length + 1; String[] newSelectionArgs = new String; newSelectionArgs = arg; System.arraycopy(selectionArgs, 0, newSelectionArgs, 1, selectionArgs.length); return newSelectionArgs; } } private boolean initialize() { final Context context = getContext(); mDbHelper = (DbHelper) DbHelper.getInstance(context); return true; } private String getLimit(Uri uri) { String limitParam = getQueryParameter(uri, "limit"); if (limitParam == null) { return null; } // make sure that the limit is a non-negative integer try { int l = Integer.parseInt(limitParam); if (l < 0) { Log.w(TAG, "Invalid limit parameter: " + limitParam); return null; } return String.valueOf(l); } catch (NumberFormatException ex) { Log.w(TAG, "Invalid limit parameter: " + limitParam); return null; } } /* package */static String getQueryParameter(Uri uri, String parameter) { String query = uri.getEncodedQuery(); if (query == null) { return null; } int queryLength = query.length(); int parameterLength = parameter.length(); String value; int index = 0; while (true) { index = query.indexOf(parameter, index); if (index == -1) { return null; } index += parameterLength; if (queryLength == index) { return null; } if (query.charAt(index) == '=') { index++; break; } } int ampIndex = query.indexOf('&', index); if (ampIndex == -1) { value = query.substring(index); } else { value = query.substring(index, ampIndex); } return Uri.decode(value); } public void onBegin() { // TODO Auto-generated method stub } public void onCommit() { // TODO Auto-generated method stub } public void onRollback() { // TODO Auto-generated method stub } protected void onEndTransaction() { if (mNotifyChange) { mNotifyChange = false; notifyChange(true); } } protected void notifyChange(boolean syncToNetwork) { getContext().getContentResolver().notifyChange(AUTHORITY_URI, null, syncToNetwork); } }
页:
[1]