赞
踩
1) ContentProvider 为存储和读取数据提供了统一的接口
2) 使用 ContentProvider,应用程序可以实现数据共享3) android内置的许多数据都是使用ContentProvider形式,供开发者调用的(如视频,音频,图片,通讯录)等
当应用继承 ContentProvider 类,并重写该类用于提供数据和存储数据的方法,就可以向其他应用共享其数据。虽然使用其他方法也可以对外共享数据,但数据访问方式会因数据存储的方式而不同,如:采用文件方式对外共享数据,需要进行文件操作读写数据;采用 sharedpreferences 共享数据,需要使用 sharedpreferences API 读写数据。而使用 ContentProvider 共享数据的好处是统一了数据访问方式。
Uri uri = Uri.parse("content://com.changcheng.provider.contactprovider/contact")
在Content Provider中使用的查询字符串有别于标准的SQL查询。很多诸如 select、add、delete、modify 等操作我们都使用一种特殊的URI来进行,这种URI由3个部分组成, “content://”, 代表数据的路径,和一个可选的标识数据的ID。以下是一些示例URI:
content://media/internal/images 这个URI将返回设备上存储的所有图片
content://contacts/people/ 这个URI将返回设备上的所有联系人信息
content://contacts/people/45 这个URI返回单个结果(联系人信息中 ID 为 45 的联系人记录)
尽管这种查询字符串格式很常见,但是它看起来还是有点令人迷惑。为此,Android提供一系列的帮助类(在 android.provider 包下),里面包含了很多以类变量形式给出的查询字符串,这种方式更容易让我们理解一点,因此,如上面 content://contacts/people/45 这个URI就可以写成如下形式:
Uri person = ContentUris.withAppendedId(People.CONTENT_URI, 45);
1、创建数据库管理类,并创建所需的表和数据
- public class MyDatabaseHelper extends SQLiteOpenHelper {
- private static final String DATABASE_NAME = "Users.db";
- private static final int DATABASE_VERSION= 1;
- private static final String TABLE_NAME= "User";
-
- public MyDatabaseHelper(Context context) {
- super(context, DATABASE_NAME, null, DATABASE_VERSION);
- }
-
- @Override
- public void onCreate(SQLiteDatabase db) {
- //创建用于存储数据的表
- db.execSQL("Create table " + TABLE_NAME + "( _id INTEGER PRIMARY KEY AUTOINCREMENT, USER_NAME TEXT);");
- }
-
- @Override
- public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
- db.execSQL("DROP TABLE IF EXISTS " + TABLE_NAME);
- onCreate(db);
- }
- }
2、创建一个类,定义uri并存储用户名称并显示所有的用户名称(使用 SQLLite数据库存储这些数据)
- public class MyUsers {
- public static final String AUTHORITY = "com.cx.datastored.MyContentProvider";
-
- //BaseColumn类中已经包含了 _id字段
- public static final class User implements BaseColumns {
- //定义uri
- public static final Uri CONTENT_URI = Uri.parse("content://com.cx.datastored.MyContentProvider");
- // 表数据列
- public static final String USER_NAME = "USER_NAME";
- }
- }
3、重写ContentProvider,完成自己的MyContentProvider,这里只做了插入和查询功能
- public class MyContentProvider extends ContentProvider {
- private SQLiteDatabase sqlDB;
- private MyDatabaseHelper dbHelper;
- private static final String TABLE_NAME= "User";
-
- @Override
- public int delete(Uri arg0, String arg1, String[] arg2) {
- //根据Uri删除arg1指定的条件所匹配的全部记录
- return 0;
- }
-
- @Override
- public String getType(Uri arg0) {
- //返回当前Uri的MIME类型,如果该URI对应的数据可能包含多条记录,那么MIME类型字符串就是以vnd.android.dir开头
- //如果该URI对应的数据只有一条,该MIME类型字符串就是以vnd..android.cursor.item开头
- return null;
- }
-
- @Override
- public Uri insert(Uri arg0, ContentValues arg1) {
- //根据Uri插入arg1对应的数据
- sqlDB = dbHelper.getWritableDatabase();
- long rowId = sqlDB.insert(TABLE_NAME, "", arg1);
- if (rowId > 0) {
- Uri rowUri = ContentUris.appendId(MyUsers.User.CONTENT_URI.buildUpon(), rowId).build();
- getContext().getContentResolver().notifyChange(rowUri, null);
- return rowUri;
- }
- throw new SQLException("Failed to insert row into " + arg0);
- }
-
- @Override
- public boolean onCreate() {
- // 在ContentProvider创建后被调用
- dbHelper = new MyDatabaseHelper(getContext());
- return (dbHelper == null) ? false : true;
- }
-
- @Override
- public Cursor query(Uri arg0, String[] arg1, String arg2, String[] arg3,
- String arg4) {
- //根据Uri查询出arg2指定的条件所匹配的全部记录,并且可以指定查询那些列,以什么方式(arg4)排序
- SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
- SQLiteDatabase db = dbHelper.getReadableDatabase();
- qb.setTables(TABLE_NAME);
- Cursor c = qb.query(db, arg1, arg2, null, null, null, arg4);
- c.setNotificationUri(getContext().getContentResolver(), arg0);
- return c;
- }
-
- @Override
- public int update(Uri arg0, ContentValues arg1, String arg2, String[] arg3) {
- //根据Uri修改arg2指定的条件所匹配的全部记录
- return 0;
- }
- }
4、 在AndroidMenifest.xml中使用<provider>标签来设置ContentProvider
- <provider
- android:exported="true"
- android:name="com.cx.datastored.MyContentProvider"
- android:authorities="com.cx.datastored.MyContentProvider" >
- </provider>
注:android:exported="true"如果不设置,在本应用中访问数据时正常,但在其他应用中访问时就会出现异常。
5、在本应用中测试
- public class MainActivity extends Activity {
-
- @SuppressLint("SdCardPath")
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
-
- insertRecord("user");
- displayRecords();
- }
-
- private void insertRecord(String userName) {
- ContentValues values = new ContentValues();
- values.put(MyUsers.User.USER_NAME, userName);
- getContentResolver().insert(MyUsers.User.CONTENT_URI, values);
- }
-
- private void displayRecords() {
- ContentResolver cr = getContentResolver();
- String columns[] = new String[] { MyUsers.User._ID, MyUsers.User.USER_NAME };
- Uri myUri = MyUsers.User.CONTENT_URI;
- Cursor cur = cr.query(myUri, columns, null, null, null);
- if (cur.moveToFirst()) {
- String id = null;
- String userName = null;
- do {
- id = cur.getString(cur.getColumnIndex(MyUsers.User._ID));
- userName = cur.getString(cur.getColumnIndex(MyUsers.User.USER_NAME));
- Toast.makeText(this, id + " " + userName, Toast.LENGTH_LONG).show();
- } while (cur.moveToNext());
- }
- }
- }
6、在其他应用中测试,这里需要新建一个工程。
1)新建工程中创建一个与上面2相同的类
- public class MyUsers {
- public static final String AUTHORITY = "com.cx.datastored.MyContentProvider";
-
- //BaseColumn类中已经包含了 _id字段
- public static final class User implements BaseColumns {
- //定义uri
- public static final Uri CONTENT_URI = Uri.parse("content://com.cx.datastored.MyContentProvider");
- // 表数据列
- public static final String USER_NAME = "USER_NAME";
- }
- }
2)测试代码也与5相同,只是他们是不同的应用
- public class MainActivity extends Activity {
-
- @SuppressLint("SdCardPath")
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
-
- insertRecord("user");
- displayRecords();
- }
-
- private void insertRecord(String userName) {
- ContentValues values = new ContentValues();
- values.put(MyUsers.User.USER_NAME, userName);
- getContentResolver().insert(MyUsers.User.CONTENT_URI, values);
- }
-
- private void displayRecords() {
- ContentResolver cr = getContentResolver();
- String columns[] = new String[] { MyUsers.User._ID, MyUsers.User.USER_NAME };
- Uri myUri = MyUsers.User.CONTENT_URI;
- Cursor cur = cr.query(myUri, columns, null, null, null);
- if (cur.moveToFirst()) {
- String id = null;
- String userName = null;
- do {
- id = cur.getString(cur.getColumnIndex(MyUsers.User._ID));
- userName = cur.getString(cur.getColumnIndex(MyUsers.User.USER_NAME));
- Toast.makeText(this, id + " " + userName, Toast.LENGTH_LONG).show();
- } while (cur.moveToNext());
- }
- }
- }
注意:只有在先运行了上面的应用后,再运行测试应用源码才会看到效果。
由于ContentProvider的主要用途是不同应用间的数据共享,所以在开发时很少会用到。例如,一个公司的一系列产品中的的某些数据需要相互使用。
1、实现代码
- public class MainActivity extends Activity {
-
- @SuppressLint("SdCardPath")
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
-
- ContentResolver cr = getContentResolver();
- //向联系人中插入一条数据
- ContentValues values = new ContentValues();
- Uri uri = cr.insert(RawContacts.CONTENT_URI, values);
- //解析uri
- Long raw_contacts_id = ContentUris.parseId(uri);
- values.clear();
- //插入人名,指定联系人和插入行
- values.put(StructuredName.RAW_CONTACT_ID, raw_contacts_id);
- //追加插入联系人信息
- values.put(StructuredName.DISPLAY_NAME, "张三");
- values.put(StructuredName.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE);
- uri = cr.insert(Data.CONTENT_URI, values);
-
- //插入电话信息
- values.clear();
- values.put(Phone.RAW_CONTACT_ID, raw_contacts_id);
- values.put(Phone.NUMBER, "123434556456");
- values.put(Phone.MIMETYPE, Phone.CONTENT_ITEM_TYPE);
- uri = cr.insert(Data.CONTENT_URI, values);
-
-
- //查询通讯录数据
- Cursor c = cr.query(ContactsContract.Contacts.CONTENT_URI, new String[]{Contacts._ID, Contacts.DISPLAY_NAME}, null, null, null);
- if(c != null){
- while (c.moveToNext()) {
- //如果不知道对应字段名称可以写成Contacts._ID和Contacts.DISPLAY_NAME
- int id = c.getInt(c.getColumnIndex("_id"));
- Log.e(">>>>>>>>>>>>", "_id" + id);
- Log.e(">>>>>>>>>>>>", "name" + c.getString(c.getColumnIndex("display_name")));
-
- //查询联系人电话号码,必须使用ID获取。通过ID查询号码和类型
- Cursor c1 = cr.query(Phone.CONTENT_URI, new String[]{Phone.NUMBER, Phone.TYPE}, Phone.CONTACT_ID + "=" + id, null, null);
- if(c1 != null){
- while (c1.moveToNext()) {
- int type = c1.getInt(c1.getColumnIndex(Phone.TYPE));
- if(type == Phone.TYPE_HOME){
- Log.e(">>>>>>>>>>>>", "家庭电话:" + c1.getString(c1.getColumnIndex(Phone.NUMBER)));
- }else if (type == Phone.TYPE_MOBILE){
- Log.e(">>>>>>>>>>>>", "手机:" + c1.getString(c1.getColumnIndex(Phone.NUMBER)));
- }
- }
- c1.close();
- }
-
- //根据联系人id查询出联系人的邮箱地址
- Cursor c2 = cr.query(ContactsContract.CommonDataKinds.Email.CONTENT_URI, new String[]{Email.DATA, Email.TYPE}, Email.CONTACT_ID + "=" + id, null, null);
- if(c2 != null){
- while (c2.moveToNext()) {
- int type = c2.getInt(c2.getColumnIndex(Email.TYPE));
- if(type == Email.TYPE_WORK){
- Log.e(">>>>>>>>>>>>", "工作邮箱:" + c2.getString(c2.getColumnIndex(Email.DATA)));
- }
- }
- c2.close();
- }
- }
- }
- c.close();
- }
- }
2、添加权限
- <!-- 查询联系人 -->
- <uses-permission android:name="android.permission.READ_CONTACTS" />
- <!-- 添加联系人 -->
- <uses-permission android:name="android.permission.WRITE_CONTACTS" />
对于 Framework 开发来说,经常需要向 APP 暴露一些系统的状态,例如电源、蓝牙、wifi状态等。这时可以可以通过 get 方法以及回调函数获取,但这样如果是第三方应用需要通过提供jar包,调取里面的方法,jar包更新和调用都不是太方便。所以我们可以使用 ContentProvider 进行数据存储和读取。
Settings.System.putInt(getContentResolver(), "user_name_id", 1);
int userId = Settings.System.getInt(getContentResolver(), "user_name_id", -1);
- //监听内容变化
- getContentResolver().registerContentObserver(Settings.System.getUriFor("user_name_id"), true,
- new ContentObserver(new Handler()) {
- @Override
- public void onChange(boolean selfChange) {
- super.onChange(selfChange);
- //监听到内容有变化
- int userId = Settings.System.getInt(getContentResolver(), "user_name_id", -1);
- }
- });
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。