博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Android中的跨进程通信方法实例及特点分析(二):ContentProvider
阅读量:6068 次
发布时间:2019-06-20

本文共 13282 字,大约阅读时间需要 44 分钟。

1.ContentProvider简单介绍        

       在Android中有些数据(如通讯录、音频、视频文件等)是要供非常多应用程序使用的。为了更好地对外提供数据。Android系统给我们提供了Content Provider使用。通过它能够訪问上面所说的数据,比如非常多音乐播放器中的扫描功能事实上就用到了Content Provider功能(当然。也有的播放器是自己去实现更底层的功能)。这种优点是统一管理。比方添加了某个音频文件,底层就会将这种变化通知Content Provider,从而当应用程序訪问时就能够获得当前最新的数据。

       当然,Android也同意我们定义自己的Content Provider。仅仅要继承它的基类,而且实现以下的方法就可以。

public boolean onCreate() 在创建ContentProvider时调用
public Cursor query(Uri, String[], String, String[], String):用于查询指定Uri的ContentProvider。返回一个Cursor
public Uri insert(Uri, ContentValues):依据指定的Uri加入数据到ContentProvider中
public int update(Uri, ContentValues, String, String[]):用于更新指定Uri的ContentProvider中的数据
public int delete(Uri, String, String[]):依据Uri删除指定的数据
public String getType(Uri):用于返回指定的Uri中的数据的MIME类型
*假设操作的数据属于集合类型。那么MIME类型字符串应该以vnd.android.cursor.dir/开头。
比如:要得到全部p1记录的Uri为content://contacts/p1,那么返回的MIME类型字符串为"vnd.android.cursor.dir/p1"。
*假设要操作的数据属于非集合类型数据。那么MIME类型字符串应该以vnd.android.cursor.item/开头。
比如:要得到id为100的student记录的Uri为content://contacts/student/100。那么返回的MIME类型字符串应为"vnd.android.cursor.item/student"。

2.Uri简单介绍

     一个标准的Uri为content://authority/path可分为下面三部分:

(1)content://:这个部分是ContentProvider规定的,就像http://代表Http这个协议一样。使用ContentProvider的协议是content://

(2)authorities:它在所在的Android系统必须是唯一的,由于系统就是通过它来决定操作或訪问哪个ContentProvider的。这与互联网上的网址必须唯一是一样的道理。

(3)path:资源路径。

       显然,从上面的分析能够看出ContentProvider尽管也可实现跨进程通信。可是它适用的场景主要是与数据库相关。有时也可能是文本文件或XML等存储方式。

3.ContentResolver

       假设仅仅是定义一个ContentProvider的话,没有不论什么意义,由于ContentProvider仅仅是内容提供者,它要被别的应用(进程)读取才有价值。

与实现ContentProvder的方法相相应,使用ContentResolver相关的方法例如以下所看到的:

getContentResolver():Context类提供的,用于获取ContentResolver对象;

insert(Uri uri,ContentValues values):向Uri相应的ContentProvider中插入values相应的数据;

update(Uri uri,ContentValues values,String where,String[]selectionArgs):更新Uri相应的ContentProvider中where处的数据。当中selectionArgs是筛选參数。

query(Uri uri,String[]projection,String selection,String[]selectionArgs,String sortOrder):查询Uri相应的ContentProvider中where处的数据,当中selectionArgs是筛选參数,sortOrder是排序方式。

delete(Uri uri,String where,String[]selectionArgs):删除Uri相应的ContentProvider中where处的数据。当中selectionArgs是筛选參数。

4.UriMatcher

      为了确定一个ContentProvider实际能处理的Uri。以及确定每一个方法中Uri參数所操作的数据,Android系统提供了UriMatcher工具类。它主要有例如以下两个方法:

(1)void addURI(String authority,String path,String code):该方法用于向UriMatcher对象注冊Uri。

当中authority和path组合成一个Uri,而code则代表该Uri相应的标识码;

(2)int match(Uri uri):依据前面注冊的Uri来推断指定Uri相应的标识码。

假设找不到匹配的标识码。该方法将会返回-1。

        以下通过两个实例来解说ContentProvider的使用方法,第一个实例是自定义了一个ContentProvider而且在还有一个应用中读取它;第二个实例是读取当前手机中的联系人。

       首先是第一个样例,项目结构例如以下图所看到的:

以下是各个类的代码。首先是常量的定义:

package com.android.student.utils;import android.net.Uri;/** * 这里定义了与ContentProvider相关的字符串以及Student相应的数据表中的字段 * @author Bettar * */public class StudentWords {	//注意Manifest文件里的authorities属性要跟这里保持一致。	public static final String AUTHORITY="com.android.student.provider";		public static final Uri STUDENT_WITH_ID_URI=Uri.parse("content://"+AUTHORITY+"/student");	public static final Uri STUDENT_URI=Uri.parse("content://"+AUTHORITY+"/student");			public static final String TABLE_NAME="student";	public static final String ID="id";	public static final String NAME="name";	public static final String SCORE="score";	public static final String ADDR="address";}
然后是数据库帮助类:

import com.android.student.utils.StudentWords;import android.content.Context;import android.database.sqlite.SQLiteDatabase;import android.database.sqlite.SQLiteOpenHelper;import android.widget.Toast;public class StudentDbHelper extends SQLiteOpenHelper{	private Context context;	public StudentDbHelper(Context context,String name,int version)	{		super(context,name,null,version);		this.context=context;	}		@Override	public void onCreate(SQLiteDatabase db)	{		String createSQL="create table "+StudentWords.TABLE_NAME+"("+StudentWords.ID				+" integer primary key autoincrement,"				+StudentWords.NAME+" varchar,"				+StudentWords.SCORE+" integer,"				+StudentWords.ADDR+" varchar)";		db.execSQL(createSQL);	}	@Override	public void onUpgrade(SQLiteDatabase db,int oldVersion,int newVersion)	{		//升级版本号时,可能要运行表结构的改动之类,此处临时不考虑升级问题。因而仅仅是用Toast提示		Toast.makeText(context, 				"newVersion:"+newVersion+" will replace oldVersion:"+oldVersion,				Toast.LENGTH_LONG).show();		}	}
最后是ContentProvider类的定义:

package com.android.student.provider;import com.android.student.database.StudentDbHelper;import android.content.ContentProvider;import android.content.ContentUris;import android.content.ContentValues;import android.content.UriMatcher;import android.database.Cursor;import android.database.sqlite.SQLiteDatabase;import android.net.Uri;import android.provider.UserDictionary.Words;import com.android.student.utils.StudentWords;public class StudentProvider extends ContentProvider{	private static final String TAG="StudentProvider";	private static UriMatcher matcher=new UriMatcher(UriMatcher.NO_MATCH);	private static final int STUDENT_WITH_ID=1;    private static final int STUDENT=2;        private StudentDbHelper dbHelper;        static    {    	matcher.addURI(StudentWords.AUTHORITY,"student/#",STUDENT_WITH_ID);    	//matcher.addURI(StudentWords.AUTHORITY, "student", SINGLE_STUDENT);    	//注意当中的#为通配符    	matcher.addURI(StudentWords.AUTHORITY, "student", STUDENT);    }        @Override    public boolean onCreate()    {    	dbHelper=new StudentDbHelper(this.getContext(),"student.db3",1);    	return true;    }        @Override    public String getType(Uri uri)    {    	switch(matcher.match(uri))    	{    	case STUDENT_WITH_ID:    		return "vnd.android.cursor.item/com.android.student";	    	case STUDENT:    		return "vnd.android.cursor.dir/com.android.student";    		default:    			throw new IllegalArgumentException("Unknown Uri:"+uri);    	}    }        /**     * 由单一的selection这一个筛选条件组合成包括id的复杂筛选条件     * @param uri     * @param selection     * @return     */    private String getComplexSelection(Uri uri,String selection)    {    	long id=ContentUris.parseId(uri);    	String complexSelection=StudentWords.ID+"="+id;    	if(selection!=null&&!"".equals(selection))    	{    		complexSelection+=" and "+selection;    	}    	return complexSelection;    }    	@Override	public int delete(Uri uri,String selection,String[]selectionArgs) {				SQLiteDatabase db=dbHelper.getReadableDatabase();		int num=0;		switch(matcher.match(uri))		{		case STUDENT_WITH_ID:			String complexSelection=getComplexSelection(uri,selection);			num=db.delete(StudentWords.TABLE_NAME, complexSelection, selectionArgs);			break;		case STUDENT:			num=db.delete(StudentWords.TABLE_NAME,selection,selectionArgs);			break;		default:			throw new IllegalArgumentException("Unknown Uri:"+uri);		}		//通知数据已经改变		getContext().getContentResolver().notifyChange(uri, null);		return num;	}	@Override	public Uri insert(Uri uri, ContentValues values) {		SQLiteDatabase db=dbHelper.getReadableDatabase();		switch(matcher.match(uri))		{		     			case STUDENT_WITH_ID:			case STUDENT:				long rowId=db.insert(StudentWords.TABLE_NAME, StudentWords.ID,values);				if(rowId>0)				{					Uri studentUri=ContentUris.withAppendedId(uri, rowId);					//假设设置了观察者的话,要通知全部观察者					getContext().getContentResolver().notifyChange(studentUri, null);					return studentUri;				}				break;			default:				throw new IllegalArgumentException("Unknow Uri:"+uri);					}	    return null;	}	/**	 * 注意当中的projection事实上是columns,即列名数组	 */	@Override	public Cursor query(Uri uri, String[] projection, String selection,			String[] selectionArgs, String sortOrder) {		SQLiteDatabase db=dbHelper.getReadableDatabase();		switch(matcher.match(uri))		{		//这事实上是包括id信息的情况		case STUDENT_WITH_ID:			String complexSelection=getComplexSelection(uri,selection);			return db.query(StudentWords.TABLE_NAME,projection,complexSelection,selectionArgs,null,null,sortOrder);		//这是不带数字的情况,可是也未必就是好多个,一个也能够。		case STUDENT:				return db.query(StudentWords.TABLE_NAME					,projection,selection,selectionArgs,null,null,sortOrder);		default:				throw new IllegalArgumentException("Unknow Uri"+uri);		}		}	@Override	public int update(Uri uri, ContentValues values, String selection,			String[] selectionArgs) 	{		SQLiteDatabase db=dbHelper.getWritableDatabase();		int num=0;		switch(matcher.match(uri))		{		case STUDENT_WITH_ID:			String complexSelection=getComplexSelection(uri,selection);			num=db.update(StudentWords.TABLE_NAME, values, complexSelection, selectionArgs);				break;		case STUDENT:			num=db.update(StudentWords.TABLE_NAME, values, selection,selectionArgs);			break;			default:				throw new IllegalArgumentException("Unknow Uri:"+uri);		}				getContext().getContentResolver().notifyChange(uri,null);		return num;		}		}
当然,要记得在Manifest文件里增加ContentProvider的声明:

以下是对ContentResolver的样例,首先项目中的文件结构例如以下:

然后是layout文件 :

项目中也有StudentWords这个类,由于与上面的StudentWords全然同样,故此处不再列出,MainActivity的代码例如以下:

package com.android.student.studentcontentresolver;import java.util.ArrayList;import java.util.List;import java.util.Map;import com.android.student.utils.StudentWords;import android.net.Uri;import android.os.Bundle;import android.app.Activity;import android.content.ContentResolver;import android.content.ContentUris;import android.content.ContentValues;import android.database.Cursor;import android.view.Menu;import android.widget.Button;import android.widget.EditText;import android.widget.Toast;import android.view.View;public class MainActivity extends Activity implements View.OnClickListener{	ContentResolver contentResolver;		private EditText nameET,scoreET,addressET;	private Button insertButton;	private EditText inputNameET;	private Button searchButton;		private EditText inputIdForUpdateET,inputIdForDeleteET;	private Button updateButton,deleteButton;			private void initView()	{		nameET=(EditText)findViewById(R.id.nameET);		scoreET=(EditText)findViewById(R.id.scoreET);		addressET=(EditText)findViewById(R.id.addrET);		insertButton=(Button)findViewById(R.id.insertButton);		inputNameET=(EditText)findViewById(R.id.inputNameET);		searchButton=(Button)findViewById(R.id.searchButton);				inputIdForUpdateET=(EditText)findViewById(R.id.inputIdET);		inputIdForDeleteET=(EditText)findViewById(R.id.inputIdForDeleteET);				updateButton=(Button)findViewById(R.id.updateButton);		deleteButton=(Button)findViewById(R.id.deleteButton);				insertButton.setOnClickListener(this);		searchButton.setOnClickListener(this);		updateButton.setOnClickListener(this);		deleteButton.setOnClickListener(this);	}		@Override	protected void onCreate(Bundle savedInstanceState) {		super.onCreate(savedInstanceState);		setContentView(R.layout.activity_main);		contentResolver=getContentResolver();		initView();	}			@Override	public void onClick(View view)	{		switch(view.getId())		{		case R.id.insertButton:			insert();			break;		case R.id.searchButton:			query();			break;		case R.id.updateButton:			update();			break;		case R.id.deleteButton:			delete();			break;			default:				break;		}	}			private void insert()	{		String name=nameET.getText().toString();		String score=scoreET.getText().toString();		String addr=addressET.getText().toString();		ContentValues values=new ContentValues();		values.put(StudentWords.NAME, name);		values.put(StudentWords.SCORE, new Integer(score));		values.put(StudentWords.ADDR, addr);				//contentResolver.insert(StudentWords.SINGLE_STUDENT_URI, values);		//一个是多个的特例,所以此处用MANY_STUDENTS_URI就可以。		contentResolver.insert(StudentWords.STUDENT_URI, values);       				Toast.makeText(getBaseContext(), "加入学生信息成功", Toast.LENGTH_SHORT).show();							}		private void query()	{		String name=inputNameET.getText().toString();		//Cursor cursor=contentResolver.query(uri, projection, selection, selectionArgs, sortOrder)		Cursor cursor=contentResolver.query(StudentWords.STUDENT_URI, null, "name like ?

or address like ?", new String[]{"%"+name+"%","%"+name+"%"}, null); Toast.makeText(getBaseContext(), getResult(cursor), Toast.LENGTH_LONG).show(); } private void update() { //Uri updateUri=StudentWords.SINGLE_STUDENT_URI //更新id值为id的记录 Integer id=new Integer(inputIdForUpdateET.getText().toString()); Uri updateUri=ContentUris.withAppendedId(StudentWords.STUDENT_WITH_ID_URI,id); ContentValues values=new ContentValues(); values.put(StudentWords.NAME,"VictorWang"); contentResolver.update(updateUri, values, null, null); } private void delete() { //删除id值为id的记录 Integer id=new Integer(inputIdForDeleteET.getText().toString()); Uri deleteUri=ContentUris.withAppendedId(StudentWords.STUDENT_WITH_ID_URI, id); contentResolver.delete(deleteUri, null, null); } private List<String>convertCursor2List(Cursor cursor) { List<String>result=new ArrayList<String>(); while(cursor.moveToNext()) { result.add(cursor.getString(1)+" "); result.add(cursor.getString(2)+" "); result.add(cursor.getString(3)+" "); } return result; } private String getResult(Cursor cursor) { StringBuilder sb=new StringBuilder(); while(cursor.moveToNext()) { sb.append(cursor.getString(1)+" "); sb.append(cursor.getString(2)+" "); sb.append(cursor.getString(3)+"\n"); } return sb.toString(); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main, menu); return true; } }

执行结果例如以下:

今天先写到这里,联系人和ContentObserver的样例后面再加入。

     

你可能感兴趣的文章
No.2 PyQt学习
查看>>
阿里安全资深专家杭特辣评中国网络安全人才之“怪现状”
查看>>
MonoDB的数据准备
查看>>
AngularJS------命令行
查看>>
价值1400美元的CEH(道德黑客)认证培训课程长啥样?(3)工具集
查看>>
Docker数据卷
查看>>
vscode常用设置
查看>>
程序员之---C语言细节20(符号和有符号之间转换、两数相加溢出后数值计算)...
查看>>
zookeeper学习
查看>>
【mac】mac上安装软件,报错 鉴定错误,但是安装包都是好的
查看>>
设计模式的6大原则
查看>>
【转】观看视频时启用硬件加速有什么用?如果关闭硬件加速又有什么区别呢?...
查看>>
Weblogic12c 单节点安装
查看>>
CentOS7下安装Docker-Compose操作记录
查看>>
【wpf】在win10系统上弹出toast和notification
查看>>
.axf 转化 .bin文件 的方法
查看>>
sql server无log ldf日志文件附件mdf数据库重新生成ldf日志文件
查看>>
Chapter 4 Invitations——15
查看>>
Spring Boot 2.0 Release Notes
查看>>
谈一谈python的垃圾回收机制
查看>>