content provider 深入解析

       Content providers are one of the primary building blocks of Android applications, providing content to applications. They encapsulate data and provide it to applications through the single ContentResolver interface. A content provider is only required if you need to share data between multiple applications.  If you don't need to share data amongst multiple applications you can use a database directly via SQLiteDatabase.

 

      照我的理解的话,你可以把ContentProvider 当成是一个适配器。 也就是让应用程序能够通过Content provider提供的接口,调用database 提供的接口来访问database中的数据。也就是说用户可以直接使用ContentResolver操作ContentProvider  来间接访问其它应用程序存在database 中的数据。

    下面的例子是实现了这个过程。

一 实现custom content provider  

 

public class ReadingProvider extends ContentProvider {

    public static final String AUTHORITY = ReadingProvider.class.getName().toLowerCase();

 //下面是定义了两个访问类型的常量。
 //访问整张数据表
    private static final int TYPE_ALL_ITEMS           = 1;
    //访问该张表中特定的row的数据
    private static final int TYPE_SINGLE_ITEM         = 2;
   
    //这个contentprovider对应的数据库
    private ReadingOpenHelper dbhelper = null;

 //用来匹配content provider的 Uri
    private static final UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH);

    static {
        matcher.addURI(AUTHORITY, "items", TYPE_ALL_ITEMS);
  //注意这个# 的意思是占位符,对应的uri可以是这样的形式
  //static final Uri URI = Uri.parse("content://" + ReadingProvider.AUTHORITY + "/items");
  //itemUri = Uri.withAppendedPath(URI, "" + item_id);
        matcher.addURI(AUTHORITY, "items/#", TYPE_SINGLE_ITEM);
    }

 //在这个content provider创建的时候打开数据库
    @Override
    public boolean onCreate() {
     log.debug("readingprovider oncreate");
        dbhelper = new ReadingOpenHelper(getContext());
        return true;
    }
   
    @Override
    public int delete(Uri uri, String where, String[] whereArgs) {
        switch (matcher.match(uri)) {
        case TYPE_ALL_ITEMS:

        //当匹配TYPE_ALL_ITEMS 这个Uri的时候就删掉ItemColumns.TABLE_NAME 这个table中相应的数据
            return dbhelper.getWritableDatabase().delete(ItemColumns.TABLE_NAME, where, whereArgs);
        case TYPE_SINGLE_ITEM:

        //当匹配TYPE_SINGLE_ITEM 这个Uri的时候就删掉ItemColumns.TABLE_NAME 这个table中用id指定的row的数据
            String i_id = uri.getPathSegments().get(1);
            return dbhelper.getWritableDatabase().delete(ItemColumns.TABLE_NAME, ItemColumns._ID + "=" + i_id, null);
        }
        throw new IllegalArgumentException("Unsupported URI: " + uri);
    }

 

    @Override
    public String getType(Uri uri) {
        switch (matcher.match(uri)) {
        case TYPE_ALL_ITEMS:
            return null;//there is no type so return null
        case TYPE_SINGLE_ITEM:
            return null;
        }
        throw new IllegalArgumentException("Unsupported URI: " + uri);
    }
   
    @Override
    public Uri insert(Uri uri, ContentValues initialValues) {
        long id = 0L;
        switch (matcher.match(uri)) {
        case TYPE_ALL_ITEMS:

       //当匹配这个Uri的时候就在(ItemColumns.TABLE_NAME这个table中插入initialValues
            id = dbhelper.getWritableDatabase().insertOrThrow(ItemColumns.TABLE_NAME, null, initialValues);
            return ContentUris.withAppendedId(ItemColumns.URI, id);
        }
        throw new IllegalArgumentException("Illegal Uri: " + uri.toString());
    }

 

    @Override
    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sort) {
     //log.debug("reading provider query" + uri.toString());
     Cursor cursor = null;
        switch (matcher.match(uri)) {
        case TYPE_ALL_ITEMS:
         cursor = dbhelper.getReadableDatabase().query(ItemColumns.TABLE_NAME, projection, selection, selectionArgs, null, null, sort);
         break;
        case TYPE_SINGLE_ITEM:
            String i_id = uri.getPathSegments().get(1);
            cursor = dbhelper.getReadableDatabase().query(ItemColumns.TABLE_NAME, projection, ItemColumns._ID + "=" + i_id, null, null, null, null);
            break;
        default:
            throw new IllegalArgumentException("Illegal Uri: " + uri.toString());
        }
       
        if (cursor != null) {
         cursor.setNotificationUri(getContext().getContentResolver(), uri);
        } else {
            log.warn("query failed in reading provider");
        }
        return cursor;
    }

    @Override
    public int update(Uri uri, ContentValues initialValues, String where, String[] whereArgs) {
        switch (matcher.match(uri)) {
        case TYPE_ALL_ITEMS:
            return dbhelper.getWritableDatabase().update(ItemColumns.TABLE_NAME, initialValues, where, whereArgs);
        }
        throw new IllegalArgumentException("Illegal Uri: " + uri.toString());
    }
}

 

note: 由上面的content provider的实现我们可以看到,content provider的内部都是在对其相关联的那个数据库进行操作。

 

二 下面实现这个数据库。 ReadingOpenHelper  继承 SQLiteOpenHelper,使用父类提供的接口来对自己定义的数据库进行相关的操作

1.

public class ReadingOpenHelper extends SQLiteOpenHelper {
 
 private final Log log = Utils.getLog(getClass());

    public ReadingOpenHelper(Context context) {
        super(context, "bereader.db", null, 1);
    }

    @Override
    public void onCreate(SQLiteDatabase db) {    

        //下面是创建一个数据库的sql语句
        String sql_create_item = cat(
                "CREATE TABLE IF NOT EXISTS ", ItemColumns.TABLE_NAME, " (",
                ItemColumns._ID, " INTEGER PRIMARY KEY AUTOINCREMENT, ",
                ItemColumns.TITLE, " VARCHAR(256)"
                ");"
        );
        String sql_index_item_title = cat(
                "CREATE UNIQUE INDEX IDX_",
                ItemColumns.TABLE_NAME,
                "_",
                ItemColumns.TITLE,
                " ON ",
                ItemColumns.TABLE_NAME,
                " (",
                ItemColumns.TITLE,
                ");"
        );

        //执行这个sql语句

        db.execSQL(sql_create_item);
        db.execSQL(sql_index_item_title);
    }
   
    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
     log.debug("onUpdate, from: " + oldVersion + " to " + newVersion);
        if (oldVersion!=newVersion) {
            // drop db 更新数据库的时候要先删掉以前的数据库,这里我们调用onCreate(db);
           //来重新生成一个数据库
            db.execSQL(cat("DROP TABLE ", ItemColumns.TABLE_NAME));
            onCreate(db);
        }
    }

 

    String cat(String... ss) {
        StringBuilder sb = new StringBuilder(ss.length << 3);
        for (String s : ss)
            sb.append(s);
        return sb.toString();
    }
}

 

2.下面这个类就是表示数据库中的一个一个item实体,定义了这个item所在的数据表的名字,用来访问这个数据表的Uri,和这个item的field 这里只有一个TITLE

public interface ItemColumns extends BaseColumns {

    //用这个Uri就能够从provider中访问数据库中存储的ItemColumns 的内容

    static final Uri URI = Uri.parse("content://" + ReadingProvider.AUTHORITY + "/items");

    static final String TABLE_NAME = "beReaderItems";
    static final String TITLE = "title";
}

 

三: 下面我们来使用content provider来访问数据库中的数据。

void testProvider(){

 

      ContentValues cv = new ContentValues();
    ContentResolver cr = getContentResolver();
    
     cv.put(ItemColumns.TABLE_NAME, "title_name1");
     //插入一条item

     cr.insert(ItemColumns.URI,cv);
     //查询指定的item

     String itemUri = Uri.withAppendedPath(ItemColumns.URI, "" + item_id);
    Cursor cursor = cr.query(itemUri,
      new String [] {ItemColumns._ID,ItemColumns.TITLE,},
      null, null, null);

    

//更新一条记录

      cv.put(ItemColumns.TABLE_NAME, "title_name1");
        int n = cr.update(
                ItemColumns.URI,
                cv,
                ItemColumns.URI._ID + "=" + itemId,
                null
        );     
 }

你可能感兴趣的:(sql,android)