四大组件之内容提供者(ContentProvider)

为什么需要内容提供者?
简单来说,就是另外一个应用想要访问此应用中私有的数据库,此应用中提供了一个中间对象来供其他应用访问,这个中间对象就是内容提供者。
在这里插入图片描述

内容提供者把数据进行封装然后提供出来,其他应用都是通过内容解析者来访问。
首先我们在第一个应用中创建一个名为Account.db的数据库。

public class MyOpenHelper extends SQLiteOpenHelper {

	
	/**
	 * @param context
	 * name 数据库名字
	 * factory 游标工厂
	 * 
	 * 
	 * 
	 */
	public MyOpenHelper(Context context) {
		super(context, "Account.db", null, 1);
		
	}

	//表结构的初始化
	@Override
	public void onCreate(SQLiteDatabase db) {
		db.execSQL("create table info(_id integer primary key autoincrement,name varchar(20),money varchar(20))");
        db.execSQL("insert into info(name,money) values(?,?)",new String[]{"张三","5000"});
        db.execSQL("insert into info(name,money) values(?,?)",new String[]{"李四","3000"});
	}

	@Override
	public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
		// TODO Auto-generated method stub

	}

}

MainActivity

public class MainActivity extends Activity {

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		
		MyOpenHelper myOpenHelper=new MyOpenHelper(getApplicationContext());
		SQLiteDatabase db=myOpenHelper.getReadableDatabase();	
		
		//在本应用中执行查询。
		Cursor cursor=db.query("info", null, null, null, null, null,null);
		if(cursor!=null&&cursor.getCount()>0){
			while(cursor.moveToNext()){
				String name=cursor.getString(1);
				String money=cursor.getString(2);
				System.out.println("name:"+name+"------money"+money);
			}
		}
	}
}

这样我们就在第一个应用中创建好了一个数据库。
如果另外一个应用想要访问此数据库,可以通过chmod修改文件权限的方式来访问
在另一个应用中编写代码:

public class MainActivity extends Activity {

	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		//需求  读取第一个应用私有的数据库
		/*
		 * path 路径 Account.db
		 * factory游标工厂
		 * falgs 访问模式
		 *  
		 * */
		//&&& chmod修改要操作数据库的访问权限   chmod 777 Account.db
		
		//注意:此行代码找不到数据库位置  需要调试(把Account.db生成的附加库删掉)
		SQLiteDatabase db=SQLiteDatabase.openDatabase("data/data/com.example.db/databases/Account.db",null,SQLiteDatabase.OPEN_READWRITE);
		System.out.println("已找到数据库");
		Cursor cursor=db.query("info", null, null, null, null, null,null);
		if(cursor!=null&&cursor.getCount()>0){
			while(cursor.moveToNext()){
				String name=cursor.getString(1);
				String money=cursor.getString(2);
				System.out.println("第二个应用:name:"+name+"------money"+money);
			}
		}
	}
}

但是我们不推荐这种做法,我们今天用内容提供者来将应用私有的数据库暴露出去。
定义内容提供者

public class AccountProvider extends ContentProvider {

	//[1]定义一个urimatcher 定义路径匹配器
	private static final UriMatcher sURIMatcher=new UriMatcher(UriMatcher.NO_MATCH);
	private static final int QUERYSUCCESS = 0; //ctrl shift x   大小写变换
	private MyOpenHelper myOpenHelper;
	//[2]定义静态代码块 添加匹配规则(在类实例化的时候就执行,并且只执行一次)
	static{
		/**
		 * authority 注意 这个参数和你定义在清单文件中的要一样 
		 *URL  http://www.baidu.com
		 *uri    com.example.privider/query
		 *
		 *
		 */
		sURIMatcher.addURI("com.example.provider", "query", QUERYSUCCESS);
		
	}
	
	@Override
	public boolean onCreate() {
		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==QUERYSUCCESS){
			//说明路径匹配成功  把query方法给实现 数据库的查询方法  对数据库进行查询的操作 想操作数据库必须获得SQLliteDataBase对象
			SQLiteDatabase db=myOpenHelper.getReadableDatabase();
			Cursor cursor=db.query("info", projection, selection, selectionArgs, null, null, sortOrder);
			//cursor 不能关闭 注意
			return cursor;
		}else{
			//路径不匹配
			throw new IllegalArgumentException("您的路径不匹配,请检查路径");
		}
	}

	@Override
	public String getType(Uri uri) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public Uri insert(Uri uri, ContentValues values) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public int delete(Uri uri, String selection, String[] selectionArgs) {
		// TODO Auto-generated method stub
		return 0;
	}

	@Override
	public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
		// TODO Auto-generated method stub
		return 0;
	}
}

清单文件注册(配置主机名authorities):

<!-- 配置内容提供者 -->
        <provider android:name="com.example.db.AccountProvider"
            android:authorities="com.example.provider">
        </provider>

定义内容提供者步骤:
1.定义一个类继承ContentProvider
2.在清单文件里配置内容提供者,定义主机名
3.写一个静态代码块,添加匹配规则
4.暴露你想暴露的方法(增删改查)
5.如果你发现你的日志中有这样一段日志,说明内容提供者没有问题
ActivityThread: Pub com.example.provider: com.example.db.AccountProvider
6.其他应用可以通过内容解析者去操作数据库

Cusor cusor=getContentResover().query(uri,null,null,null,null);

由于第一个应用的私有数据库已经通过内容提供者暴露出来了,所以可以直接通过内容解析者进行访问

public class MainActivity extends Activity {

	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		//通过上下文获取内容解析者
		Uri uri=Uri.prase("content://com.example.provider/query");//路径和内容提供者中定义的路径一致
		Cusor cusor=getContentResover().query(uri,null,null,null,null);
		if(cursor!=null&&cursor.getCount()>0){
			while(cursor.moveToNext()){
				String name=cursor.getString(1);
				String money=cursor.getString(2);
				System.out.println("第二个应用:name:"+name+"------money"+money);
			}
		}
	}
}

内容观察者
第三个应用监听第二个应用操作第一个应用数据库的操作。
在这里插入图片描述
第三个应用中注册内容观察者

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //注册内容观察者
        Uri uri=Uri.parse("content://com.example.provider");
        getContentResolver().registerContentObserver(uri,true,new MyContentObserver(new Handler()));
    }
    private class MyContentObserver extends ContentObserver{

        public MyContentObserver(Handler handler) {
            super(handler);
        }

        @Override
        public void onChange(boolean selfChange) {
            System.out.print("哈哈,数据库的内容发生了改变");
            super.onChange(selfChange);
        }
    }
}

在内容提供者中操作数据库结束后发送一条信息给观察者。相当于员工写日报。

getContext().getContentResover().notifyChange(uri,null);//null表示发送给所有观察者
发布了54 篇原创文章 · 获赞 17 · 访问量 4万+

猜你喜欢

转载自blog.csdn.net/weixin_43311389/article/details/83054910