content provider 的简单介绍(sdk doc翻译)

内容提供器
内容提供器是用来读取和存储数据,使用它可以将我们自己的数据共享给别人,同时可以读取到别人的数据在别人容许的情况下。他是唯一个可以在不同的应用程序间共享数据的方式,没有公共的存储区域,所有的android应用程序都可以访问。

android系统自带一些内容提供器为常用的数据类型,如音乐,视频,图片,联系人资料等,你可以通过android.provider包查看这些东东,你可以通过这些内容提供器查询他们包含的数据(但是你必须要得到其他用户程序的许可)。

如果你想让你的数据可以让别人共享,你必须做两个操作,1.你需要建立你自己的contentProvider(一个系统提供的contentProvider的子类)存储数据,2.你通过别人提供的provider去存储自己的数据(这个provider必须很你需要操作的数据类型一样,且你拥有这个provider写的权利)。

contentprovider基础

一个contentprovider怎样存储数据,完全有他的开发者控制,但是所有的contentprovider必须实现相同的接口,用来查询内容和返回结果,比如添加数据,修改,和删除。

用户可以通过系统提供的一个接口getContentResolver回去contentResolver对象(在activity中调用这个对象),当你得到这个对象后,
一般在activity中使用的方法为
ContentResolver c = getContentResolver();这个时候你就可以和提供contentprovider的应用进行交互了,
当我们发起一个查询事件时,系统识别contentProvider通过在查询中提供的uri,然后确定这个contentprovider启动并且在运行,android系统在启动的时候就初始化所有的contentprovider对象(自己提供的contentprovider需要在manifest文件中声明,具体做法一会讲)
对一些公共的应用你永远不需要自己去实现(开源软件的好处,省力,省钱,支持开源,但同时也降低了我们程序员的水准),实际上你根本不需要直接和一个contentprovider打交道(除非是自己的),android系统为没个contentprovider提供了一个实例(单例模式),但是它可以和多个contentresolver打交道(线程安全的),线程安全是由contentresolver和contentprovider完成的,我们使用者不比为此担忧。

数据模式

contentprovider是按照表的方式公开自己的数据。每一个行是一条记录,每一列是一个具体的值,这里就不举例了,如果连表都不知道的话,建议你还是别存从事软件开发了,免得降低程序员的水准,呵呵,题外话

在android的中,每一行数据都必须包含一列,列名为"_id",他是表的主键。主键的概念和作用参考数据库方面的书

每一个查询都返回一个Cursor对象,做过oracle pl/sql编程的可定知道他的意思。cursor对象可以让我们从一行移另一行,一列移动到另一列,可以很方便的读数据。他还提供读取特定类型的数据的方法,如getString,getInteger等方法,前提是你必须知道每个字段所代表的类型。(一会将详细介绍查询结果和cursor对象)

Uri
uri的作用是准确的定位我们需要的contentprovider提供的数据,否则就会乱套(不安全的,得带),每一个contentprovider都提供一个公开的uri ,他可以准确的标识一个数据集,一个contentprovider控制多个数据集,通过uri可以准确的标识他们,中的每一个数据集。所有的uri必须以content://开头,content:是作为识别contentprovider的标识。

如果你自己定义了一个contentprovider,那么你也需要为他建立一个uri,简化他人调用的工作and make future updates cleaner(请大侠解释),android定义content_uri 常量给所有的和平台交互的provider(Android defines CONTENT_URI constants for all the providers that come with the platform)。例如,查询联系的联系人和联系的图片的uri为:
android.provider.Contacts.Phones.COntent_URI 和android.provider.Contacts.Photos.CONTENT_URI.
uri 对所有和contentprovider交互的用户。每个contentresolver的方法的第一个参数就是uri,他定义了将要和哪个contentprovider的contentresolver进行对话,以及将要对哪个表进行操作。

查询一个contentprovider

你需要分三步去查询一个contentprovidr

1.contentprovidr定义的uri
2.你需要返回的表的列名
3.这些数据的类型(本人有点疑问)

如果你要查询某条特定的数据,你还需要制定ID

生成查询

你可以通过ContentResolver对象的query方法或者Activity.managedQuery方法,这个方法的参数都一样,都返回一个cursor对象,但是managedQuery方法可以让activity管理cursor对象的生命周期,他可以做好多事情,比如,当activity pauses以后,会自动关闭cursor对象。当activity restart的时候,它可以自动去重新查询。你也可以调用activit的startmanagingCursor(Cursor c)方法去管理这个对象。

query方法和managedQuery方法的第一个参数为provider的uri,关于uri上面已经介绍过了,

android系统提供了一些辅助方法,比如,COntentUris.withAppendedId()和Uri.withAppendedPath()方法,他们可以很方便的为uri添加一个id,两个方法都是静态的,都返回一个uri对象,下面是android 帮助文档中提供的例子

import android.provider.Contacts.People;
import android.content.ContentUris;
import android.net.Uri;
import android.database.Cursor;

// Use the ContentUris method to produce the base URI for the contact with _ID == 23.
//Uri myPerson = ContentUris.withAppendedId(People.CONTENT_URI, 23);

// Alternatively, use the Uri method to produce the base URI.
// It takes a string rather than an integer.
Uri myPerson = Uri.withAppendedPath(People.CONTENT_URI, "23");

// Then query for this specific record:
Cursor cur = managedQuery(myPerson, null, null, null, null);

query()和managedQuery()方法的参数代表的意思如下:

参数1:uri。参数2:需要返回的列名,比如_id,number,nember_key等,如果为空,则返回所有列。参数3:相当于sql语句的where条件,比如 “_id” = 12,"_id" = ? 。如果为null的时候,则返回所有列,前提是你的uri是返回全部的uri。参数4:如果参选3中包含形如"_id" = ?的条件,那么此项不能为空。否则此项为空,目的是提供查询速度,让sql语句软解析。参数5:是排序,比如要按照id排序,则为“id desc ”,不需要加order by。详细请查看android api android.content.contentResolver

查询返回的数据

每个查询都会返回o个或者多条记录。不会返回null,而且每行都会包含_id这列,

读取返回的数据

从cursor中读数据的时候,一定要知道数据的类型,但是你也可以通过getString方法,读取到所有数据,但是返回的对象都是string类型的,在你实际应用中,你还是要转换成真正的类型,所以还是第一次就使用对象的get方法把,你可以使用index或者列名去读数据。好像没有提供直接使用列名读数据的方法,不知道为什么,待解(难道是我没注意到)。
如下:
if (cur.moveToFirst()) {

String name;
String phoneNumber;
int nameColumn = cur.getColumnIndex(People.NAME);
int phoneColumn = cur.getColumnIndex(People.NUMBER);
String imagePath;

do {
// Get the field values
name = cur.getString(nameColumn);
phoneNumber = cur.getString(phoneColumn);

// Do something with the values.
...

} while (cur.moveToNext());

}

如果一个查询返回的是二进制数据,如image或者音乐。那么数据可以直接存在表中,也可以通过一个uri链接到相应内容。使用uri可以获取数据。一般情况下,小数据,如20-50k或者更小的,直接存在数据库,可以通过getBlod()方法到到btye数据。如果table存在的uri,那么你不需要直接打开或者读取这个文件,(不过要有这个权限)。你应该调用ContentResolver.onpenInputStream()获取inputStream对象,然后可以读。

修改数据

1.add
2.updata
3.batch update
3.delete

一. 添加数据
添加数据的第一步,你需要创建一个key-value对象在ContentValues(相当于map,内部实现还是以map实现的,android封装了java的map对象)。数据设置好后,调用contentResolver的insert方法就可以插入了
insert方法返回的不是我们想象的id类型,而是一个uri对象,代表新插入记录的uri。你可以使用他查询刚才添加的记录。如下:
ContentValues values = new ContentValues();

// Add Abraham Lincoln to contacts and make him a favorite.
values.put(People.NAME, "Abraham Lincoln");
// 1 = the new contact is added to favorites
// 0 = the new contact is not added to favorites
values.put(People.STARRED, 1);

Uri uri = getContentResolver().insert(People.CONTENT_URI, values);


二. 修改,删除就不说了,基本上差不多,update和delete方法。

创建一个contentprovider


1.创建一个contentProvider子类
2.定义uri
3.使用创建的类。打开一个SQLiteDatabase对象。openRendHelper和openWirterHelper方法。
4.在manifest文件中声明这个类,一定要声明,<provider android:name="com.example.autos.AutoInfoProvider"
android:authorities="com.example.autos.autoinfoprovider"
. . . />
</provider>

实现类里,需要实现的方法有 query,insert update getType oncreate
格式为 content://xxx.xxx.xxx全部数据,某一条数据 content://xxx.xxx.xxx/id
<provider android:name="com.example.autos.AutoInfoProvider"
android:authorities="com.example.autos.autoinfoprovider"
. . . />
</provider>
import java.util.Calendar;
import java.util.Date;

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;

public class DiaryDbAdapter {

public static final String KEY_TITLE = "title";
public static final String KEY_BODY = "body";
public static final String KEY_ROWID = "_id";
public static final String KEY_CREATED = "created";

private static final String TAG = "DiaryDbAdapter";
private DatabaseHelper mDbHelper;
private SQLiteDatabase mDb;

private static final String DATABASE_CREATE = "create table diary (_id integer primary key autoincrement, "
+ "title text not null, body text not null, created text not null);";

private static final String DATABASE_NAME = "database";
private static final String DATABASE_TABLE = "diary";
private static final int DATABASE_VERSION = 1;

private final Context mCtx;

private static class DatabaseHelper extends SQLiteOpenHelper {

DatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}

@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(DATABASE_CREATE);
}

@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL("DROP TABLE IF EXISTS diary");
onCreate(db);
}
}

public DiaryDbAdapter(Context ctx) {
this.mCtx = ctx;
}

public DiaryDbAdapter open() throws SQLException {
mDbHelper = new DatabaseHelper(mCtx);
mDb = mDbHelper.getWritableDatabase();
return this;
}

public void closeclose() {
mDbHelper.close();
}

public long createDiary(String title, String body) {
ContentValues initialValues = new ContentValues();
initialValues.put(KEY_TITLE, title);
initialValues.put(KEY_BODY, body);
Calendar calendar = Calendar.getInstance();
String created = calendar.get(Calendar.YEAR) + "年"
+ calendar.get(Calendar.MONTH) + "月"
+ calendar.get(Calendar.DAY_OF_MONTH) + "日"
+ calendar.get(Calendar.HOUR_OF_DAY) + "时"
+ calendar.get(Calendar.MINUTE) + "分";
initialValues.put(KEY_CREATED, created);
return mDb.insert(DATABASE_TABLE, null, initialValues);
}

public boolean deleteDiary(long rowId) {

return mDb.delete(DATABASE_TABLE, KEY_ROWID + "=" + rowId, null) > 0;
}

public Cursor getAllNotes() {

return mDb.query(DATABASE_TABLE, new String[] { KEY_ROWID, KEY_TITLE,
KEY_BODY, KEY_CREATED }, null, null, null, null, null);
}

public Cursor getDiary(long rowId) throws SQLException {

Cursor mCursor =

mDb.query(true, DATABASE_TABLE, new String[] { KEY_ROWID, KEY_TITLE,
KEY_BODY, KEY_CREATED }, KEY_ROWID + "=" + rowId, null, null,
null, null, null);
if (mCursor != null) {
mCursor.moveToFirst();
}
return mCursor;

}

public boolean updateDiary(long rowId, String title, String body) {
ContentValues args = new ContentValues();
args.put(KEY_TITLE, title);
args.put(KEY_BODY, body);
Calendar calendar = Calendar.getInstance();
String created = calendar.get(Calendar.YEAR) + "年"
+ calendar.get(Calendar.MONTH) + "月"
+ calendar.get(Calendar.DAY_OF_MONTH) + "日"
+ calendar.get(Calendar.HOUR_OF_DAY) + "时"
+ calendar.get(Calendar.MINUTE) + "分";
args.put(KEY_CREATED, created);

return mDb.update(DATABASE_TABLE, args, KEY_ROWID + "=" + rowId, null) > 0;
}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值