Android 第九天重置版_Contentprovider_注意事项

本文探讨了Android中使用ContentProvider的原因,强调了其优于直接使用SQLite数据库的开放性。内容提供者的工作原理、实现步骤以及在备份短信、插入短信和读取联系人等场景的应用被详细阐述,并提到了权限管理和内容观察者的重要性。
摘要由CSDN通过智能技术生成

为什么需要内容提供者:


第六点就是为什么需要内容提供者


SQLiteDatabase.openDatabase(path, factory, flags)

可以通过这个方法打开一个数据库的文件。但是这个数据库文件必须是其他用户可以使用的权限  -rwx(当前用户权限) rwx(当前用户组权限) rwx其他用户权限) 


我们可以使用cursor.getColumnIndex("列名")来返回你指定列名的 索引.

这样的好处就是当我们 不知道索引的情况下 也可以查找出内容。


我们为了实现访问另外一个应用程序中的数据库的内容。可以使用上面的方式。

但是这种方式不是 Android 推荐的方式。


所以我们要使用内容提供者。

————————————————————————————————

内容提供者原理:



————————————————————————————————

实现内容提供者的步骤:


<span style="font-size:18px;">public class AccountProvider extends ContentProvider {

	
	
	//[1]定一个一个uri路径匹配器 
	private static final UriMatcher sURIMatcher = new UriMatcher(UriMatcher.NO_MATCH);
	private static final int QUERYSUCESS = 0;  //ctrl+shift+X  变大写   小写加y
	private static final int INSERTSUCESS = 1;
	private static final int UPDATESUCESS = 2;
	private static final int DELETESUCESS = 3;
	private MyOpenHelper myOpenHelper;
	//[2]创建一个静态代码块 在这个里面添加 uri 
	static{
		
		/**
		 *                                  http://www.baidu.com 
		 * authority 注意: 和清单文件里面定义的一样  com.itheima.provider/query 
		 *  
		 */
		sURIMatcher.addURI("com.itheima.provider", "query", QUERYSUCESS);
		sURIMatcher.addURI("com.itheima.provider", "insert", INSERTSUCESS);
		sURIMatcher.addURI("com.itheima.provider", "update", UPDATESUCESS);
		sURIMatcher.addURI("com.itheima.provider", "delete", DELETESUCESS);
	}
	
	
	//当内容提供者初始化  会执行此方法 
	@Override
	public boolean onCreate() {
		
		//[3]初始化 myopenHelpler 对象    就可以获取到sqlitedatabases对象 我们就可以操作数据库 
	
		myOpenHelper = new MyOpenHelper(getContext());
		
		return false;
	}

	//这个方法对外暴露的 
	@Override
	public Cursor query(Uri uri, String[] projection, String selection,
			String[] selectionArgs, String sortOrder) {
		int code = sURIMatcher.match(uri);
		if (code ==QUERYSUCESS ) {
			//说明路径匹配成功
			SQLiteDatabase db = myOpenHelper.getReadableDatabase();
			//调用query方法
			Cursor cursor = db.query("info", projection, selection, selectionArgs, null, null, sortOrder);
			
			//发送一条消息 说明说明数据库被操作了 
			getContext().getContentResolver().notifyChange(uri, null);
			
			
//			db.close();
			//小细节 ☆ 这个cursor不能关 
			return cursor;
			
		}else{
			//说明路径不匹配
//			return null;
			throw new IllegalArgumentException("哥们 :uri路径不匹配 请检测路径");
			
		}
			
		
	}

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

	@Override
	public Uri insert(Uri uri, ContentValues values) {
		
		int code = sURIMatcher.match(uri);
		if (code == INSERTSUCESS) {
			//说明路径匹配成功 
			SQLiteDatabase db = myOpenHelper.getReadableDatabase();
			
			long insert = db.insert("info", null, values);
			Uri uri2 = Uri.parse("com.hahaheheheihei/"+insert); 
			
			if (insert>0) {
				//发送一条消息 说明说明数据库被操作了 
				getContext().getContentResolver().notifyChange(uri, null);
			}
			
			
			db.close();//关闭数据库
			return uri2;
			
		}else {
			throw new IllegalArgumentException("姐们 :uri路径不匹配 请检测路径");
		}
		
		
	}

	@Override
	public int delete(Uri uri, String selection, String[] selectionArgs) {
		
		int code = sURIMatcher.match(uri);
		if (code == DELETESUCESS) {
			//匹配成功 
			SQLiteDatabase db = myOpenHelper.getReadableDatabase();
			
			
			//代表影响的行数
			int delete = db.delete("info", selection, selectionArgs);
			
			if (delete>0) {
				//发送一条消息 说明说明数据库被操作了 
				getContext().getContentResolver().notifyChange(uri, null);
				
			}
			
			return delete;
			
		}
		
		return 0;
	}

	@Override
	public int update(Uri uri, ContentValues values, String selection,
			String[] selectionArgs) {
		int code = sURIMatcher.match(uri);
		
		if (code == UPDATESUCESS) {
			//路径匹配成功
			SQLiteDatabase db = myOpenHelper.getWritableDatabase();
			
			//代表影响的行数 
			int update = db.update("info", values, selection, selectionArgs);
			if(update>0){
				//发送一条消息 说明说明数据库被操作了 
				getContext().getContentResolver().notifyChange(uri, null);
				
			}
			
			
			
			return update;
			
			
		}else{
			throw new IllegalArgumentException("大爷:uri路径不匹配 请检测路径");
			
		}
			
		
	}

}
</span>


<span style="font-size:18px;">public class MainActivity extends Activity {

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

	
	//点击按钮 往数据库里面插入一条数据
	public void click1(View v){
		//因为第一个应用里面的私有的数据库 已经通过内容提供者暴露出来了 所以通过内容解析者去获取数据
		Uri uri = Uri.parse("content://com.itheima.provider/insert");
		ContentValues values = new ContentValues(); //实际是map  
		//key:  代表列名  value 对应的值 
		values.put("name", "zhaoliu");
		values.put("money", 1000);
		//插入一条数据
		Uri uri2 = getContentResolver().insert(uri, values);
		
		System.out.println("uri2:"+uri2);
		
		
		
	}
	
	//点击按钮删除 赵六删掉 
	public void click2(View v){
		//[1]获取内容的解析者 
		Uri uri = Uri.parse("content://com.itheima.provider/delete");
		//[2]代表影响的函数
		int delete = getContentResolver().delete(uri, "name=?", new String[]{"zhaoliu"});
		Toast.makeText(getApplicationContext(), "删除了"+delete+"行", 1).show();
		
	}    
	
	//给赵六多点钱  1000元
	public void click3(View v){
		//[1] 创建uri
	    Uri uri = Uri.parse("content://com.itheima.provider/update");
		//[2]获取内容的解析者
	    ContentValues values = new ContentValues();
	    values.put("money", "10000000");
	    int update = getContentResolver().update(uri, values, "name=?",new String[]{"zhaoliu"});
	    Toast.makeText(getApplicationContext(), "更新了"+update+"行", 1).show();
		
	}
	
	
	//点击按钮 查询第一个应用里面数据库的信息 
	public void click4(View v){
		// 第二种 查询方式  因为第一个应用里面的私有的数据库 已经通过内容提供者暴露出来了 所以通过内容解析者去获取数据
		Uri uri = Uri.parse("content://com.itheima.provider/query");
		//通过内容解析者获取数据
		Cursor cursor = getContentResolver().query(uri, new String[]{"name","money"}, null, null, null);
         if (cursor!=null) {
			
			while(cursor.moveToNext()){
				String name = cursor.getString(0);
				String money = cursor.getString(1);
				
				System.out.println("第二个应用:"+name+"---"+money);
				
			}
         }
		
	}
	
	

}</span>


————————————————————————————————

备份短信案例:


当我们看见包名有providers 时候,我们就应该知道  这些内容已经通过内容提供者暴露出来了。我们只要使用内容解析者接收 就可以了。


//点击按钮查询短信内容 然后把短信内容进行备份
	public void click(View v) {

		try {
			//[1]获取XmlSerializer的实例
			XmlSerializer serializer = Xml.newSerializer();
			//[2]设置序列化器参数 
			File file = new File(Environment.getExternalStorageDirectory().getPath(),"smsbackup.xml");
			FileOutputStream fos = new FileOutputStream(file);
			serializer.setOutput(fos, "utf-8");
			//[3]写xml文档开头 
			serializer.startDocument("utf-8", true);
			
			//[4]写xml的根节点
			serializer.startTag(null, "smss");
			//[5]构造uri
			Uri uri = Uri.parse("content://sms/");
			
			//[6]由于短信的数据库已经通过内容提供者暴露出来 所以我们直接通过内容解析者查询 
			Cursor cursor = getContentResolver().query(uri, new String[]{"address","date","body"}, null, null, null);
			while(cursor.moveToNext()){
				String address = cursor.getString(0);
				String date = cursor.getString(1);
				String body = cursor.getString(2);

				//[7]写sms节点 
				serializer.startTag(null, "sms");
				//[8]写address节点 
				serializer.startTag(null, "address");
				serializer.text(address);
				serializer.endTag(null, "address");
				
				//[9]写date节点 
				serializer.startTag(null, "date");
				serializer.text(date);
				serializer.endTag(null, "date");
				//[10]写body节点 
				serializer.startTag(null, "body");
				serializer.text(body);
				serializer.endTag(null, "body");
				
				serializer.endTag(null, "sms");
				
			}
			
			serializer.endTag(null, "smss");
			serializer.endDocument();
			fos.close();
			
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		
		
		
		
	}



这里的Uri.parse("content://")前面是默认的写法。后面就是在 内容提供者里面定义的。

记住要加权限:android.permission.READ_SMS

                        android.permission.WRITE_SMS

————————————————————————————————

利用内容提供者插入短信:


————————————————————————————————

读取联系人案例:

记住要加权限:android.permission.READ_CONTACTS

                        android.permission.WRITE_CONTACTS

注意一点,谷歌工程师设计的联系人删除的时候,只是把raw_contact表 中的raw_contact_id 设置为空。但是 实际的数据并没有删除。

所以我们在查询contact_id的时候要判断是否为空.


//查询联系人的工具类
public class QueryContactsUtils {

	
	public static List<Contact> queryContacts(Context context){
		//[0]创建一个集合
		
		List<Contact>  contactLists = new ArrayList<Contact>();
		//[1]先查询row_contacts表 的contact_id列 我们就知道一共有几条联系人 
		Uri uri = Uri.parse("content://com.android.contacts/raw_contacts");
		Uri dataUri = Uri.parse("content://com.android.contacts/data");
		Cursor cursor = context.getContentResolver().query(uri,new String[]{"contact_id"} , null, null, null);
		while(cursor.moveToNext()){
			String contact_id = cursor.getString(0);
			
			
			if (contact_id!=null) {
			//创建javabean对象
			Contact contact = new Contact();
			
			contact.setId(contact_id);
			
			System.out.println("contact_id:"+contact_id);
			//[2]根据contact_id去查询data表  查询data1列和mimetype_id 
			
			//☆ ☆ ☆ ☆ 当我们在查询data表的时候 其实查询的是view_data的视图
			
			Cursor dataCursor = context.getContentResolver().query(dataUri, new String[]{"data1","mimetype"}, "raw_contact_id=?", new String[]{contact_id}, null);
			while(dataCursor.moveToNext()){
				String data1 = dataCursor.getString(0);
				String mimetype = dataCursor.getString(1);
				//[3]根据mimetype 区分data1列的数据类型 
				if ("vnd.android.cursor.item/name".equals(mimetype)) {
					contact.setName(data1);
				}else if ("vnd.android.cursor.item/phone_v2".equals(mimetype)) {
					contact.setPhone(data1);
				}else if ("vnd.android.cursor.item/email_v2".equals(mimetype)) {
					contact.setEmail(data1);
				}
				
				
			}
			
			//把javabean对象加入到集合中
			contactLists.add(contact);
			}
			
		}
		
		return contactLists;
		
	}
	
}
public class MainActivity extends Activity {

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		
		
		List<Contact> queryContacts = QueryContactsUtils.queryContacts(getApplicationContext());
		for (Contact contact : queryContacts) {
			System.out.println("contat:"+contact);
			
		}
		
		
		
	}

	

}

	public void click(View v) {
		Uri uri = Uri.parse("content://com.android.contacts/raw_contacts");
		Uri dataUri = Uri.parse("content://com.android.contacts/data");
		
		//[2]获取name phone email Textutils
		String name = et_name.getText().toString().trim();
		String phone = et_phone.getText().toString().trim();
		String email = et_email.getText().toString().trim();
		
		//[2.1]在插入联系人id的时候 先查询一下 row_contact 一共有几条数据    加+1就是联系人的id 
		Cursor cursor = getContentResolver().query(uri, null, null, null, null);
		int count = cursor.getCount();
		int contact_id = count +1;
		
		//[3] 先往row_contact表  插入联系人的id (contact_id)  
		ContentValues values = new ContentValues();
		values.put("contact_id", contact_id);
		getContentResolver().insert(uri,values);
		
		//[4]在把name phone email 插入到data表 
		ContentValues nameValues = new ContentValues();
		nameValues.put("data1", name);
		//☆ ☆ ☆ ☆ ☆ 插入的数据要告诉数据库 属于第几条联系人  和  数据类型 
		nameValues.put("raw_contact_id", contact_id);
		nameValues.put("mimetype", "vnd.android.cursor.item/name");
		getContentResolver().insert(dataUri, nameValues);
		
		//[5]把phone号码 插入到data表 
		ContentValues phoneValues = new ContentValues();
		phoneValues.put("data1", phone);
		phoneValues.put("mimetype", "vnd.android.cursor.item/phone_v2");
		phoneValues.put("raw_contact_id", contact_id);
		getContentResolver().insert(dataUri, phoneValues);
		
		
		//[5]把phone号码 插入到data表 
		ContentValues emailValues = new ContentValues();
		emailValues.put("data1", email);
		emailValues.put("mimetype", "vnd.android.cursor.item/email_v2");
		emailValues.put("raw_contact_id", contact_id);
		getContentResolver().insert(dataUri, emailValues);
		
	}


注意一点:

我们查询的data表,其实是查询view_data表,所以当你去查询mimetype_id的时候

你会发现报错,因为view-data表没有这个数据。 所以我们应该查询mimetype的数据。


还有data表中的raw-contacts_id 就是就是raw-contacts表中的 contacts-id的数据.

————————————————————————————————

内容观察者原理:


注意:内容观察者不是四大组件之一,不需要再清单文件中配置。




————————————————————————————————

内容观察者引用场景:

短信监听



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值