Android四大组件之Content Provider

ContentProvider:内容提供者

1、为存储和读取数据提供了统一的接口

 2、使用ContentProvider,应用程序可以实现数据共享

 3、android内置的许多数据都是使用ContentProvider形式,供开发者调用的(如视频,音频,图片,通讯录等)

 4、当应用继承ContentProvider类,并重写该类用于提供数据和存储数据的方法,就可以向其他应用共享其数据。


先来了解一下Uri:

Uri,即通用资源标识符

1、Uri代表要操作的数据,Android上可用的每种资源 - 图像、视频片段等都可以用Uri来表示

2、Uri一般由三部分组成:访问资源的命名机制;存放资源的主机名; 资源自身的名称,由路径表示。

      Android的Uri由以下三部分组成: "content://"+数据的路径+标示ID(可选)、

    如:所有联系人的Uri: content://contacts/people

    某个联系人的Uri: content://contacts/people/5    //联系人中id为5的联系人

3、如果要把一个字符串转换成Uri,可以使用Uri类中的parse()方法,如下:

Uri uri = Uri.parse("content://com.archer.ContentProvider")


ContentResolver:

在android中,每个应用程序是可以实现数据共享的,对于每一个应用程序程序都拥有一个ContentProvider实例进行存储,

而ContentResolver则是用于管理所有程序的ContentProvider实例,通过ContentRescolver可以对数据进行添加、删除、修改和查询操作

通过getContentRescolver()获取实例


下面通过创建一个Content Provider,并使用 SQLLite数据库实现数据共享


首先,定义ContentProvider的CONTENT_URI,并且是public static final的Uri类型的类变量

必须为其制定一个唯一的字符串值,一般用类的全名称命名

package com.ContentProviderDemo.Archer;

import android.net.Uri;
import android.provider.BaseColumns;

public class MyUsers {
	public static final String AUTHORITY = "com.archer.ContentProvider";
	
	//BaseColumn类中已经包含了 _id 字段
	public static final class User implements BaseColumns{
		public static final Uri CONTENT_URI =
				Uri.parse("content://com.archer.ContentProvider");
		//表数据列
		public static final String USER_NAME = "USER_NAME";
	}
}


之后创建一个类继承ContentProvider

package com.ContentProviderDemo.Archer;

import android.content.ContentProvider;
import android.content.ContentUris;
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.database.sqlite.SQLiteQueryBuilder;
import android.net.Uri;

public class MyContentProvider extends ContentProvider{

	/**
	 * 定义一个SQLiteDatabase变量
	 * Android提供了一个名为SQLiteDatabase的类,它封装了一些操作数据库的API。
	 * 使用它能实现基本的CRUD(插入、查询、更新、删除)操作,通过getWritableDatabase()和getReadableDatabase()可以获取数据库实例
	 */
	private SQLiteDatabase sqlDB;
	private DatabaseHelper dbHelper;
	private static final String DATABASE_NAME = "Users.db"; //数据库名
	private static final int DATABASE_VERSION = 1; //数据库版本
	//表名
	private static final String TABLE_NAME = "User";//表名
	
	/**
	 * 首先需要创建数据库(定义一个内部类,继承SQLiteOpenHelper类,重写其方法)
	 * SQliteOpenHelper是一个抽象类,来管理数据库的创建和版本的管理。
	 * 要使用它必须实现它的onCreate(SQLiteDatabase),onUpgrade(SQLiteDatabase, int, int)方法  
        * onCreate:当数据库第一次被建立的时候被执行,例如创建表,初始化数据等。
       * onUpgrade:当数据库需要被更新的时候执行,例如删除旧表,创建新表。
	 * @author Administrator
	 */
	private static class DatabaseHelper extends SQLiteOpenHelper{

		/**
		* 创建数据库的构造方法
		* name 数据库的名字
		* factory 查询数据库的游标工厂一般情况下用sdk默认的
		* version 数据库的版本一般大于0
		*/
		public DatabaseHelper(Context context){
			super(context,DATABASE_NAME,null,DATABASE_VERSION);
		}
		
		@Override
		public void onCreate(SQLiteDatabase db) {
		String sq1 = "Create table " + TABLE_NAME + "( _id INTEGER PRIMARY KEY AUTOINCREMENT, USER_NAME TEXT);"; //创建表的sql语句
			db.execSQL(sq1); //创建表
		}

		/**
		* 更新数据的时候调用的方法,如新增表、修改数据
		*/
		@Override
		public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
			//增加一列
			db.execSQL("DROP TABLE IF EXISTS" + TABLE_NAME);
			onCreate(db);
		}
		
	}
	
	@Override
	public int delete(Uri uri, String s, String[] arg2) {
		
		return 0;
	}

	@Override
	public String getType(Uri arg0) {
		
		return null;
	}
	
	/**
	 * 插入数据
	 * ContentValues类负责存储一些名值对,的名是一个String类型,而值都是基本类型。
	 */
	@Override
	public Uri insert(Uri uri, ContentValues contentValues) {
		//以读写方式打开数据库,一旦数据库的磁盘空间满了,数据库就只能读而不能写,就会打开失败
		sqlDB = dbHelper.getWritableDatabase(); 
		//插入一条新的纪录,如果插入成功则会返回这条记录的id,如果插入失败会返回-1
		long rowId = sqlDB.insert(TABLE_NAME, "", contentValues);
		if(rowId > 0){
			
			 // ContentUris 类用于获取Uri路径后面的ID部分
			 //appendId:为该Uri加上ID
			Uri rowUri = ContentUris.appendId(MyUsers.User.CONTENT_URI.buildUpon(), 
					rowId).build();
			
			 // getContextResolver().notifyChange():获得一个ContextResolver对象并且更新里面的内容。
			getContext().getContentResolver().notifyChange(rowUri, null);
			return rowUri;
		}
		throw new SQLException("Fail to insert row into"+uri);
	}

	/**
	 * 这是一个回调函数,当生成所在类的对象时,这个方法被调用,创建一个数据库
	 */
	@Override
	public boolean onCreate() {
		dbHelper = new DatabaseHelper(getContext());
		return (dbHelper == null) ? false:true;
	}

	/**
	 * 查询
	 */
	@Override
	public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
			String sortOrder) {
		//SQLiteQueryBuilder 是一个构造SQL查询语句的辅助类。
		SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
		//getReadableDatabase():先以读写方式打开数据库,如果数据库的磁盘空间满了,就会打开失败,当打开失败后会继续尝试以只读方式打开数据库
		SQLiteDatabase db = dbHelper.getReadableDatabase();
		qb.setTables(TABLE_NAME);
		/**
		 * Cursor 是每行的集合
		 * 在Android中 查询数据是通过Cursor 类来实现的。当我们使用 SQLiteDatabase.query()方法时,就会得到Cursor对象,
		 *  Cursor所指向的就是每一条数据
		 */
		Cursor c = qb.query(db, projection, selection, null, null, null, sortOrder);
		c.setNotificationUri(getContext().getContentResolver(), uri);
		return c;
	}

	@Override
	public int update(Uri arg0, ContentValues arg1, String arg2, String[] arg3) {
		
		return 0;
	}

}


在AndroidManifest.xml中进行注册:

<application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name=".MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <provider 
            android:name=".MyContentProvider"
            android:authorities="com.archer.ContentProvider">    
        </provider>
        <!-- android:authorities属性配置的就是该ContentProvider的名字,是它在Android系统中的名字,我们是通过这个名字去找对应的ContentProvider对象的-->
    </application>


最后,创建一个新的工程(测试用)

package com.ContentProviderDemo.Archer;

import android.app.Activity;
import android.content.ContentValues;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;

/**
 * 在另一个工程中访问创建的数据库,不用再注册provider,否则会保存
 * @author Administrator
 * 
 */
public class MainActivity extends Activity {

	public static final String AUTHORITY = "com.archer.ContentProvider";
	private Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY);

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		insertRecord("record1");
		displayRecords(); 
	}

	//插入数据
	private void insertRecord(String userName) {
		ContentValues values = new ContentValues();
		values.put("USER_NAME", userName);
		getContentResolver().insert(CONTENT_URI, values);
	}

	//查询数据
	private void displayRecords() {
		// 该数组中包含了所有要返回的字段
		String columns[] = new String[] { "_id", "USER_NAME" };
		Uri myUri = CONTENT_URI;
		Cursor cur = getContentResolver().query(myUri, columns, null, null,null);
		if (cur.moveToFirst()) {
			String id = null;
			String userName = null;
			do {
				id = cur.getString(cur.getColumnIndex("_id"));
				userName = cur.getString(cur.getColumnIndex("USER_NAME"));
				Log.e("TAG", "id:" + id + ";" + "userName:" + userName);
			} while (cur.moveToNext());
		}
		cur.close(); // 关闭Cursor对象
	}

}

这样,就是先不同应用程序间的数据共享了

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。