zoukankan      html  css  js  c++  java
  • 自定义ContentProvider详解

    ContentProvider在android中的作用是对外共享数据,也就是说你可以通过ContentProvider把应用中的数据共享给其他应用访问,其他应用可以通过ContentProvider对你应用中的数据进行添删改查。


    要注意ContentProvider的作用,是为别的应用调用本应用中的数据或者文件提供接口,而它也是唯一的跨应用数据传递的接口。

    如果仅仅是同一个应用中的数据传递,则完全没有必要使用到自定义的ContentProvider。

    关于URI:

    Android各种类型的URI基本上都是有固定格式的,对于ContentProvider而言,由三部分构成一般形如

    content://cn.itcast.sqlite.provider/person/1

    红色:scheme协议,固定写法

    黄色:主机名或authority 

    path:表示路径,对于数据库来说,表示操作person表下id为1的记录

    下面来看一个例子

    比如说B应用要访问A应用中的数据库中的一张表。

    1.首先在A应用中要写一个java类,继承ContentProvider,重写insert、delete、query、update、getType、onCreate方法,如下:

    package cn.itcast.sqlite.provider;
    
    import cn.itcast.sqlite.dao.DBOpenHelper;
    
    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;
    
    
    public class SQLiteProvider extends ContentProvider {
    
    	private static final int PERSON = 1;
    	private static final int PERSON_ID = 2;
    	private UriMatcher matcher; 				 							// uri匹配器,用来解析uri
    	private DBOpenHelper dbhelper;
    
    	 // 程序第一次启动时执行,会驻留在后台,除非结束程序进程,再开启在此执行次此方法
    	public boolean onCreate() {				
    		System.out.println("创建内容提供者,执行onCreate");
    		matcher = new UriMatcher(UriMatcher.NO_MATCH);
    		dbhelper = new DBOpenHelper(getContext());
    		matcher.addURI("cn.itcast.sqlite.provider", "person", PERSON);
    		matcher.addURI("cn.itcast.sqlite.provider", "person/#", PERSON_ID);
    		return true;
    	}
    
    	//查询数据
    	public Cursor query(Uri uri, String[] projection, String selection,String[] selectionArgs, String sortOrder) {
    		SQLiteDatabase db = dbhelper.getReadableDatabase();
    		switch (matcher.match(uri)) {
    		case PERSON_ID:
    			long id = ContentUris.parseId(uri); // 获取传入过来的id
    			selection = "id=" + id;
    		case PERSON:
    			return db.query("person", projection, selection, selectionArgs,
    					null, null, sortOrder);
    		default:
    			throw new RuntimeException("没有匹配的uri");
    		}
    	}
    
    	//插入数据
    	public Uri insert(Uri uri, ContentValues values) {
    		System.out.println("insert");
    		SQLiteDatabase db = dbhelper.getReadableDatabase();
    		switch (matcher.match(uri)) {
    		case PERSON:
    			long id = db.insert("person", "id", values);
    			getContext().getContentResolver().notifyChange(uri, null); // 通知观察者数据进行了修改
    			return ContentUris.withAppendedId(uri, id);
    		default:
    			throw new RuntimeException("Uri不能识别" + uri);
    		}
    	}
    
    	//删除数据
    	public int delete(Uri uri, String selection, String[] selectionArgs) {
    		System.out.println("delete");
    		SQLiteDatabase db = dbhelper.getWritableDatabase();
    		switch (matcher.match(uri)) {
    		case PERSON_ID:
    			long id = ContentUris.parseId(uri); // 获取传入过来的id
    			selection = selection == null ? "id=" + id : selection + "AND id="
    					+ id;
    		case PERSON:
    			int updid = db.delete("person", selection, selectionArgs);
    			getContext().getContentResolver().notifyChange(uri, null); // 通知观察者数据进行了修改
    			return updid;
    		default:
    			throw new RuntimeException("没有匹配的uri");
    		}
    	}
    
    	//更新数据
    	public int update(Uri uri, ContentValues values, String selection,
    			String[] selectionArgs) {
    		SQLiteDatabase db = dbhelper.getWritableDatabase();
    		switch (matcher.match(uri)) {
    		case PERSON_ID:
    			long id = ContentUris.parseId(uri); // 获取id
    			getContext().getContentResolver().notifyChange(uri, null); // 通知观察者数据进行了修改
    			selection = selection == null ? "id=" + id : selection + "AND id="
    					+ id;
    		case PERSON:
    			return db.update("person", values, selection, selectionArgs);
    		default:
    			throw new RuntimeException("Uri不能识别" + uri);
    		}
    	}
    
    	
    	public String getType(Uri uri) {
    		// TODO Auto-generated method stub
    		switch (matcher.match(uri)) {
    		case PERSON_ID:
    			return "vnd.android.cursor.item/person";// 带了id,操作指定person
    		case PERSON:
    			return "vnd.android.cursor.dir/person";// 没带ID,操作所有person
    
    		default:
    			throw new RuntimeException("Uri不能识别" + uri);
    		}
    	}
    
    }
    
    在这个类中,如果需要及时通知你的应用别的应用通过ContentProvider访问你,比如说,B应用通过ContentProvider往你数据库插入了一条数据,A应用要及时更新,可以在A应用的Activity中注册一个内容观察者ContentObserver,然后在ContentProvider对应方法中通知观察者数据进行了修改(代码如上),在Activity中注册ContentObserver具体如下:

    public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.main);
            
            dao = new PersonDao(this);
            persons = dao.queryAll();					// 获取数据
            
            personLV = (ListView) findViewById(R.id.personLV);		// 获取ListView
            personLV.setAdapter(new MyBaseAdapter());			// 给ListView添加Adapter, 按照Adapter中的方法对ListView添加条目
            
            personLV.setOnItemClickListener(new MyOnItemClickListener());	// 给ListView添加条目点击监听器
            
            //注册方法
            Uri uri=Uri.parse("content://cn.itcast.sqlite.provider");
            getContentResolver().registerContentObserver(uri, true, new myContentObeserver()); //监听指定uri(包含子路径)的修改
        }
    	private class myContentObeserver extends ContentObserver{
    		
    		public myContentObeserver(){
    			super(new Handler());			//Handler是一个处理器,目前没有用到
    		}
    		public void onChange(boolean selfChange){	//当ContentProvider内容改变,执行此方法
    			System.out.println("数据改变了");
    			persons=dao.queryAll();			//重新查询数据
    			personLV.setAdapter(new MyBaseAdapter());//设置新的ListView
    		}
    	

    然后要在AndroidManifest.xml中声明provider,在Application下,与activity同级

     <provider
                android:name=".provider.SQLiteProvider" 
                android:authorities="cn.itcast.sqlite.provider"
      />


    2.在B应用中写一个测试类,测试访问A应用中数据库中的person表


    import android.content.ContentResolver;
    import android.content.ContentValues;
    import android.database.Cursor;
    import android.net.Uri;
    import android.test.AndroidTestCase;
    
    public class ProviderTest extends AndroidTestCase {
    	
    	public void testQueryAll() {
    		ContentResolver resolver = getContext().getContentResolver();
    		Uri uri = Uri.parse("content://cn.itcast.sqlite.provider/person");
    		Cursor c = resolver.query(uri, new String[]{"id","name","balance"}, "balance>?", new String[]{ 5000 + ""}, "balance DESC");
    		while (c.moveToNext()) {
    			Person p = new Person(c.getInt(0), c.getString(1), c.getInt(2));
    			System.out.println(p);
    		}
    	}
    	public void testQueryOne() {
    		ContentResolver resolver = getContext().getContentResolver();
    		Uri uri = Uri.parse("content://cn.itcast.sqlite.provider/person/2");
    		Cursor c = resolver.query(uri, null, null,null,null);
    		while (c.moveToNext()) {
    			Person p = new Person(c.getInt(0), c.getString(1), c.getInt(2));
    			System.out.println(p);
    		}
    	}
    	public void testInsert () {
    		ContentResolver resolver = getContext().getContentResolver();
    		Uri uri = Uri.parse("content://cn.itcast.sqlite.provider/person");
    		ContentValues values=new ContentValues();
    		values.put("name", "ob3");
    		values.put("balance", 123456);
    		uri=resolver.insert(uri, values);
    		System.out.println(uri);
    	}
    	public void testUpdate () {
    		ContentResolver resolver = getContext().getContentResolver();
    		Uri uri = Uri.parse("content://cn.itcast.sqlite.provider/person/13");//如果后面不带id,则更新所有
    		ContentValues values=new ContentValues();
    		values.put("name", "update");
    		values.put("balance", 654321);
    		int count=resolver.update(uri, values, null, null);				//更新了几条
    		System.out.println(count);
    		
    	}
    	public void testDelete() {
    		ContentResolver resolver = getContext().getContentResolver();
    		Uri uri = Uri.parse("content://cn.itcast.sqlite.provider/person/13");//如果后面不带id,则删除所有
    		int count=resolver.delete(uri, null, null);				//删除了几条
    		System.out.println(count);
    		
    	}
    	public void testGetType(){
    		ContentResolver resolver = getContext().getContentResolver();
    		String type1=resolver.getType(Uri.parse("content://cn.itcast.sqlite.provider/person"));
    		String type2=resolver.getType(Uri.parse("content://cn.itcast.sqlite.provider/person/2"));
    		System.out.println(type1);
    		System.out.println(type2);
    	}
    	
    }

    最后,关于ContentProvider中的GetType()方法,一直不知道有啥用,找到资料说是如下:

    它的作用是根据URI返回该URI所对应的数据的MIME类型字符串。这种字符串的格式分为两段:“A/B”。其中A段是固定的,集合类型(如多条数据)必须是vnd.android.cursor.dir,非集合类型(如单条数据)必须是vnd.android.cursor.item;B段可以是自定义的任意字符串;A、B两段通过“/”隔开。这个MIME类型字符串的作用是要匹配AndroidManifest.xml文件<activity>标签下<intent-filter>标签的子标签<data>的属性android:mimeType。如果不一致,则会导致对应的Activity无法启动。



  • 相关阅读:
    Android登录界面实现
    博客园自定义模板
    HttpClient + Jsoup模拟登录教务处并获取课表
    sublime编写markdown文件中Ctrl+B的作用
    Java学习路线图
    数学建模比赛论文的基本结构
    GitBash上传代码不计入贡献的问题处理
    Android知识体系图
    Java文件处理:分离全国省市县ID(数据来自和风天气)
    poj3484 Showstopper 二分
  • 原文地址:https://www.cnblogs.com/fzll/p/3954619.html
Copyright © 2011-2022 走看看