目录

1.Android 四大组件及纽带

2.内容提供者功能、原理、分类

3.实现内容提供者(ContentProvider)

3.1 实现步骤

3.2 访问内容的 URI

3.3 处理 MIME类型数据请求

3.4 访问内容提供者公开数据

4.功能一:与其他应用共享数据

4.1 应用一(ContactProvider)

4.2 应用二(ContentResolver)

5.功能二:存储检索本机数据


1.Android 四大组件及纽带

  • 活动:Activity
  • 内容提供者:Content Provider
  • 服务:Service
  • 广播接收器:BroadcastReceiver
  • 连接四大组件的纽带:Intent

2.内容提供者功能、原理、分类

  • 功能:
  1. 存储检索数据源数据,比如 应用访问手机自带通讯录      
  2. 与其他应用共享数据,比如 应用访问另一应用数据库
  • 原理:抽象底层数据源,将应用与数据层分离,:使数据源具有独立性
  • 分类:
  1. 自定义内容提供者
  2. 本机内容提供者

3.实现内容提供者(ContentProvider

3.1 实现步骤

  1. 自定义一个 ContentProvider类
  2. 重写抽象方法: onCreate()、 insert()、 update()、 delete()、 query()、 getType()(MIME)
  3. 在 AndroidManifest.xml 系统配置文件中注册 自定义内容提供者
  4. 指定要访问的 URI
  5. 在另一应用里通过 ContentResolver 访问内容提供者公开的数据

3.2 访问内容的 URI

  • URI(Uniform Resource Identifier):统一资源标识符,是 URL 父级
  • URI包含 本地+网络 地址,URL只有网络地址
  • 每个内容提供者公开一个 URI:唯一标识该内容提供者的数据集
  • 如果一个内容提供者控制多个数据集,则需要为每个数据集指定单独的 URI
  • URI 以字符串 content:// 开头,就像网站 URL 以http://开头,两种格式如下:
  1. 请求 Example表中 所有记录:content://bagname.contenttprovider/Example
  2. 请求 Example表中 第一行记录:content://bagname.contenttprovider/Example/1
  • 访问内容提供者,需要用 android.content 程序包的 UriMatcher 类

3.3 处理 MIME类型数据请求

  • 处理内容提供者提供的 MIME数据类型 的请求,需要重写 getType() 方法
  • getType() :将 URI 对象作为参数,并返回字符串,该字符串唯一描述 URI的 MIME类型,返回类型:
  1. vnd.android.cursor.item/<contenttype>:对 单条目 返回 单项
  2. vnd.android.cursor.dir/<contenttype>:对 所有条目 返回 所有项

3.4 访问内容提供者公开数据

  • 访问内容提供者公开的数据,需要使用 android.content.ContentResolver 类
  • 每个 Android 应用上下文都包括一个可访问的 ContentResolver实例,如下:
  • ContentResolver resolver = getContentResolver(); // 内容解析器
  • 从内容提供者检索记录:ContentResolver.query() 方法 或 Activity.managedQuery() 方法

4.功能一:与其他应用共享数据

4.1 应用一(ContactProvider

  • SQLHelper.java:创建数据库,初始化一些表的信息
public class SQLHelper extends SQLiteOpenHelper{
	public SQLHelper(Context context) {           // 创建自己数据库的构造函数
		super(context,"NIIT.db",null,1);          // 创建NIIT数据库,不需要工厂,版本是1
		Log.w("content:","初始化 SQLHelper类");
	}
	@Override
	public void onCreate(SQLiteDatabase db) {     // 数据库首次创建时调用 一般写创建表的代码
		db.execSQL("create table Contacts(id integer primary key autoincrement, " +
				"name text, mobile text)");       // 创建联系人表
		db.execSQL("insert into Contacts(name,mobile) values('阿呆','88888888')");
		db.execSQL("insert into Contacts(name,mobile) values('阿贝','66666666')");
		Log.w("content:","SQLHelper类的 onCreate()方法被调用");
	}
	@Override                                     // 数据库升级时调用 执行添加、修改等操作
	public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { 
		Log.w("content:","SQLHelper类的 onUpgrade()方法被调用");
	}}
  • MainActivity.java:不包含内容提供者,有增删查改,只有此文件的话,别的应用不能访问本应用程序数据
public class MainActivity extends Activity {
	Button b1, b2, b3, b4,selectAll;     // 声明五个按钮
	EditText etId, etName, etMobile;     // 声明三个编辑框
	SQLHelper helper;
	SQLiteDatabase db;
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);

		b1 = (Button) findViewById(R.id.insert);           // 插入按钮
		b2 = (Button) findViewById(R.id.modify);           // 修改按钮
		b3 = (Button) findViewById(R.id.delete);           // 删除按钮
		b4 = (Button) findViewById(R.id.query);            // 查询按钮
		selectAll = (Button) findViewById(R.id.selectAll); // 查询全部信息按钮
		etId = (EditText) findViewById(R.id.etId);         // id编辑视图
		etName = (EditText) findViewById(R.id.etName);     // 名字编辑视图
		etMobile = (EditText) findViewById(R.id.etMobile); // 手机编辑视图
		
		// 设置点击事件:以前通过匿名内部类创建点击事件 现在用下面的自定义点击事件
		ButtonListener listener = new ButtonListener();
		b1.setOnClickListener(listener);
		b2.setOnClickListener(listener);
		b3.setOnClickListener(listener);
		b4.setOnClickListener(listener);
		selectAll.setOnClickListener(listener);
		helper = new SQLHelper(this);
		db = helper.getWritableDatabase();
	}
	class ButtonListener implements OnClickListener { // 自定义点击事件
		@Override
		public void onClick(View v) {     // View 是按钮、文本等组件的父类
			switch (v.getId()) {         
			case R.id.insert:
				// 获取两个参数:名字、手机,编号是自动增长的所以不需要获取,注意顺序问题!				
				String[] args1={etName.getText().toString(),etMobile.getText().toString()};
				// 自己书写sql语句,通过上面定义的参数args1 将值传给sql中的?
				db.execSQL("insert into Contacts(name,mobile) values(?,?)",args1);
                // 插入成功后,弹出提示框,退出下面的遍历
				Toast.makeText(MainActivity.this,"插入成功!",Toast.LENGTH_SHORT).show();
				break;
			case R.id.modify:
				// 根据 id进行修改 需要获取id 注意顺序问题!args2顺序 和 sql?顺序一致
				String[] args2={etName.getText().toString(),etMobile.getText().toString(),
						etId.getText().toString()};
				db.execSQL("update Contacts set name=?,mobile=? where id=?",args2);
				Toast.makeText(MainActivity.this,"更新成功!",Toast.LENGTH_SHORT).show();
				break;
			case R.id.delete:
				db.execSQL("delete from Contacts where id=?",
						new String[]{etId.getText().toString()});
				Toast.makeText(MainActivity.this,"删除成功!",Toast.LENGTH_SHORT).show();
				break;
			case R.id.query:
				Cursor c=db.rawQuery("select * from Contacts where id=?",
						new String[]{etId.getText().toString()});
				if(c.moveToFirst()){  // 遍历查询 Cursor结果集 如果查询到 就执行下面代码
					etName.setText(c.getString(1)); // 设置显示内容
					etMobile.setText(c.getString(2));
				}else{	// 查询不到结果
					etName.setText(""); // 设置为空
					etMobile.setText("");
					Toast.makeText(MainActivity.this,"查不到这个人!",Toast.LENGTH_SHORT).show();
				}
				break;
			case R.id.selectAll:
                // 查询所有人 直接给表格 其他都是null
				Cursor cc = db.query("Contacts",null,null,null,null,null,null);
				StringBuffer sb = new StringBuffer();	// StringBuffer():遍历追加
				while(cc.moveToNext()){
					sb.append(cc.getInt(0)+"\t"+cc.getString(1)+"\t"+cc.getString(2)+"\n");
				}
				Toast.makeText(MainActivity.this,sb,Toast.LENGTH_LONG).show();
			}}}}
  • ContactProvider.java:内容提供者,重写了很多方法,有了此文件,别的应用就可以访问本应用数据
public class ContactProvider extends ContentProvider{ // 重写 ContentProvider类里的方法
	SQLHelper helper;
	SQLiteDatabase db;
	@Override
	public boolean onCreate() {     // onCreate():初始化数据源信息
		helper = new SQLHelper(this.getContext());  // 获取路径 this=ContentProvider
		db = helper.getWritableDatabase();
		Log.w("content:","ContactProvider类 onCreate()方法被调用");
		return true;
	}
	// query():实现数据查询(五个参数)
	// Uri:内容提供者地址
	// projection:要查询的列,如:new String[]{"name","mobile"},查询name和mobile列
	// selection:查询条件,如:where id=?
	// selectionArgs:查询条件的参数值,如:String[]{"1"}); 上述where条件参数值为1
	// sortOrder:排序,如:name desc 表示名字降序排列
	@Override
	public Cursor query(Uri uri, String[] projection, String selection,
			String[] selectionArgs, String sortOrder) { //返回一个 结果集Cursor
		Cursor c=db.query("Contacts",projection, selection, 
				selectionArgs, null,null,sortOrder);
		Log.w("content:","ContactProvider类 query()方法被调用");
		return c;
	}
	@Override
	public String getType(Uri uri) { // 处理内容提供者提供的 MIME数据类型的请求,一般不用
		Log.w("content:","ContactProvider类 getType()方法被调用");
		return null;
	}
	// insert():插入数据(两个参数)
	// ContentValues:要插入的行对象
	@Override
	public Uri insert(Uri uri, ContentValues values) {
		db.insert("Contacts",null,values);
		Log.w("content:","ContactProvider类 insert()方法被调用");
		return null;
	}
	// delete():删除记录(三个参数)
	@Override 
	public int delete(Uri uri, String selection, String[] selectionArgs) {
		int count = db.delete("Contacts",selection, selectionArgs);
		Log.w("content:","ContactProvider类 delete()方法被调用");
		return count; // 返回值 表示删除时受到影响的行数
	}
    //update():更新记录(四个参数)
	@Override
	public int update(Uri uri, ContentValues values, String selection,
			String[] selectionArgs) {
		int count=db.update("Contacts",values, selection, selectionArgs);
		Log.w("content:","ContactProvider类 update()方法被调用");
		return count; // 返回值 表示更新时受到影响的行数
	}}
  •  Andoid.Manifest.xml:注册内容提供者,设置相应权限
        <provider    // 注册内容提供者信息
            // name:内容提供者的完整类名,即包名.类名,必须根据实际类名定义        
            android:name="com.Lyrelion.contentprovider.ContactProvider"   
            // authorities:内容提供者的引用名/别名,可以自定义,但要唯一,最好以包名.类名格式写 
            android:authorities="com.Lyrelion.contentprovider.ContactProvider"
            //  exported:是否要共享数据
            android:exported="true" >
        </provider>
  • 应用一控制台效果展示:  
  • 应用一界面:  
  • 应用一查询展示:

4.2 应用二(ContentResolver

  • MainActivity.java:这里声明了内容解析器 ContentResolver,URI等,里面的方法参数和应用一是对应的
public class MainActivity extends Activity {
	Button b1, b2, b3, b4;
	EditText etId, etName, etMobile;
	Uri uri=Uri.parse("content://com.Lyrelion.contentprovider.ContactProvider"); // 权限中查看
	ContentResolver cr;	// 内容解析器
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		b1 = (Button) findViewById(R.id.insert);      // 插入按钮
		b2 = (Button) findViewById(R.id.modify);      // 修改按钮
		etId = (EditText) findViewById(R.id.etId);    // id编辑视图
		ButtonListener listener = new ButtonListener();
		b1.setOnClickListener(listener);
		// 内容解析器:Context类的 getContentResolver()方法创建 ontentResolver类
		cr = this.getContentResolver();}
		class ButtonListener implements OnClickListener {
		@Override
		public void onClick(View v) {
			switch (v.getId()) {
			case R.id.insert:	// 根据上面提供的Uri,查找到对应文件,执行插入
				ContentValues newrow = new ContentValues();     // 创建一行
				newrow.put("name",etName.getText().toString()); //设置 name列的值
				newrow.put("mobile",etMobile.getText().toString()); //设置 mobile列的值
				cr.insert(uri,newrow); // 把newrow 插入指定列
				Toast.makeText(MainActivity.this,"插入成功!",Toast.LENGTH_LONG).show();
				break;
			case R.id.modify:
				ContentValues uprow=new ContentValues();
				uprow.put("name",etName.getText().toString()); 
				uprow.put("mobile",etMobile.getText().toString());
				cr.update(uri,uprow,"id=?",new String[]{etId.getText().toString()});
				break;
                // ...
			}}}}
  • 应用二界面效果:应用二可以访问、修改应用一的内容提供者
  • 应用二界面:

5.功能二:存储检索本机数据

  • MainActivity.java:这是从本地手机获取的
public class MainActivity extends Activity {
	Button b;
	TextView tv;
	ContentResolver cr;
	Uri uri=Phone.CONTENT_URI; // Phone类 常参CONTENT_URI 获取本机联系人数据源
	@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        b=(Button)findViewById(R.id.button1);
        tv=(TextView)findViewById(R.id.textView1);
        cr=this.getContentResolver(); // 获取ContentResolver实例,内容解析器
        b.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				Cursor c=cr.query(uri, null,null,null,null); // 获取本机所有联系人结果集
				while(c.moveToNext()){ // 进行遍历
			  int nameindex=c.getColumnIndex(Phone.DISPLAY_NAME); // 获取名字列索引
			  int numberindex=c.getColumnIndex(Phone.NUMBER); // 获取号码列索引
					String name=c.getString(nameindex);     // 获取名字列的值
					String number=c.getString(numberindex); // 获取电话号码列的值
					tv.append("\n姓名:");
					tv.append(name);
					tv.append("\n电话:");
					tv.append(number);
					tv.append("\n----------------------------------");
				}}});}}
  •  Andoid.Manifest.xml: 设置相应的权限
    <!--要使用手机自身的一些功能,需要获取对应的权限才可-->
    <uses-permission android:name="android.permission.READ_CONTACTS" />
  • 应用界面效果展示:

 

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐