数据持久化方案(三)ContentProvider

数据库在Android当中是私有的,不能将数据库设为WORLD_READABLE,每个数据库都只能创建它的包访问。这意味着只有创建这个数据库的应用程序才可访问它。也就是说不能跨越进程和包的边界,直接访问别的应用程序的数据库。那么如何在应用程序间交换数据呢? 如果需要在进程间传递数据,可以使用ContentProvider来实现。
大部分使用ContentProvider操作的数据都来自于数据库,但是也可以来自于文件、SharedPreferences、XML或网络等其他存储方式。
第一步:创建一个类,继承ContentProvider,实现以下几个方法
    @Override
    public boolean onCreate() {
        return false;
    }

    @Nullable
    @Override
    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
        return null;
    }

    @Nullable
    @Override
    public String getType(Uri uri) {
        return null;
    }

    @Nullable
    @Override
    public Uri insert(Uri uri, ContentValues values) {
        return null;
    }

    @Override
    public int delete(Uri uri, String selection, String[] selectionArgs) {
        return 0;
    }

    @Override
    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
        return 0;
    }

那么我们就建立一个BaseContentProvider来实现这些方法:
我们要知道,contentProvider,是根据uri的地址来进行查询的。
所以如果要对不同的表进行操作,也就需要不同的uri地址。
那么我们再建立一个类,用来获取uri的地址

    protected abstract String getTable();

    protected abstract String getType();

    protected abstract Uri getContentUri();

    /**
     * 根据类创建ContentValues
     * @param t
     * @return
     */
    public ContentValues createContentValues(T t){
        ContentValues values = new ContentValues();
        Class<?> cls = t.getClass();
        for (Field field : cls.getDeclaredFields()) {
            String typeName = field.getType().getName();
            String fieldName = field.getName();
            if (fieldName.equals(BaseColumns._ID))
                continue;
            field.setAccessible(true);
            try {
                if (typeName.equals(STRING_NAME)) {
                    values.put(fieldName, (String) field.get(t));
                } else if (typeName.equals(INT_NAME)) {
                    values.put(fieldName, field.getInt(t));
                } else if (typeName.equals(FLOAT_NAME)) {
                    values.put(fieldName, field.getFloat(t));
                } else if (typeName.equals(DOUBLE_NAME)) {
                    values.put(fieldName, field.getDouble(t));
                } else if (typeName.equals(BOOLEAN_NAME)) {
                    values.put(fieldName, field.getBoolean(t) ? 1 : 0);
                }
            } catch (Exception e) {
                if (e != null && StringUtil.isNotEmpty(e.getMessage())) {
                    Log.e(TAG, e.getMessage());
                }
            }
        }
        return values;
    }

    public T create(Class<T> cls, Cursor cursor) throws InstantiationException, IllegalAccessException {
        T t = cls.newInstance();
        for (Field field : cls.getDeclaredFields()) {
            String typeName = field.getType().getName();
            String fieldName = field.getName();
            field.setAccessible(true);
            int columnIndex = cursor.getColumnIndex(fieldName);
            if (columnIndex != -1) {
                if (typeName.equals(STRING_NAME)) {
                    field.set(t, cursor.getString(columnIndex));
                } else if (typeName.equals(INT_NAME)) {
                    field.setInt(t, cursor.getInt(columnIndex));
                } else if (typeName.equals(FLOAT_NAME)) {
                    field.setFloat(t, cursor.getFloat(columnIndex));
                } else if (typeName.equals(DOUBLE_NAME)) {
                    field.setDouble(t, cursor.getDouble(columnIndex));
                } else if (typeName.equals(BOOLEAN_NAME)) {
                    field.setBoolean(t, cursor.getInt(columnIndex) == 1 ? true : false);
                }
            }
        }
        return t;
    }

然后我们可以创建一个具体的类来实现几个抽象方法

public class UserColumn extends ColumnsType<User> implements BaseColumns {

    public static final String TABLE_USER = "user";

    private static final Uri CONTENT_URI = Uri.parse(MyContentProvider.BASE_URI + TABLE_USER);
    private static final String CONTENT_TYPE = MyContentProvider.BASE_TYPE + TABLE_USER;

    @Override
    protected String getTable() {
        return TABLE_USER;
    }

    @Override
    protected String getType() {
        return CONTENT_TYPE;
    }

    @Override
    protected Uri getContentUri() {
        return CONTENT_URI;
    }

}

接下来我们开始实现delete等方法了
比如:delete

    @Override
    public int delete(Uri uri, String selection, String[] selectionArgs) {
        ColumesType<User> ct = new ColumesType();
        String table = ct.getTable();
        int count = db.delete(table, selection, selectionArgs);
        //观察者模式,通知发生变化
        getContext().getContentResolver().notifyChange(uri, null, true);
        return count ;
    }

通过上面这个方法,那我们直接就可以删除这个user表的数据,那我们可以再抽取一下:

    @Override
    public int delete(Uri uri, String selection, String[] selectionArgs) {
        int typeCode = uriMatcher.match(uri);
        ColumnsType<?> columnsType = createColumnsType(typeCode);
        String table = columnsType.getTable();
        int count = db.delete(table, selection, selectionArgs);
        getContext().getContentResolver().notifyChange(uri, null, true);
        return count;
    }

通过匹配uri,确定我们的表名等数据

public class MyContentProvider extends BaseContentProvider {

    public static String BASE_URI;
    public static final String BASE_TYPE = "vnd.android.cursor.dir/";
    private static final int TABLE_USER = 1;
    private static String AUTHORITY;

    static {
        BASE_URI = "content://com.csdn.provider/";
        AUTHORITY = "com.csdn.provider";
    }

    public MyContentProvider() {
        super(new UriMatcher(UriMatcher.NO_MATCH));
    }

    @Override
    public boolean onCreate() {
        Context context = getContext();
        PackageInfo pi = null;
        try {
            pi = context.getPackageManager().getPackageInfo(context.getPackageName(), 0);
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
        }
        DataBaseHelper helper = DataBaseHelper.getInstance(context,pi == null ? 1 : pi.versionCode);
        db = helper.getWritableDatabase();
        return super.onCreate();
    }

    //通过匹配uri,得到columnsType,可以获取表的信息
    @Override
    protected ColumnsType<?> createColumnsType(int typeCode) {
        ColumnsType<?> columnsType;
        switch (typeCode) {
            case TABLE_USER:
                columnsType = new UserColumn();
                break;
            default:
                throw new IllegalArgumentException("Unknown typecode " + typeCode);
        }
        return columnsType;
    }

    //添加匹配
    @Override
    protected void addColumnsType(UriMatcher uriMatcher) {
        uriMatcher.addURI(AUTHORITY, UserColumn.TABLE_USER,TABLE_USER);
    }
}

最后,不要忘了注册哈

        <!-- 注册ContentProvider
        需要添加3条属性
        android:name 用于指定ContentProvider的子类的具体路径
        android:authorities  用于指定后期ContentResolver在读取的时候,Uri路径中间的作者名
        android:exported="true"  向外开放数据

ContentProvider用来暴露数据,ContentResolver当然就用来获取数据啦
同理,我们只要根据uri匹配,获取到我们这个类的uri,就可以进行操作了,再以delete为例:

    public void delete(String key, String value) {
        context.getContentResolver().delete(columns.getContentUri(), key + "=?", new String[]{value});
    }

地址:http://u.download.csdn.net/upload/success

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值