Android课堂笔记(五)——内容提供者

目录

1.Android 四大组件及纽带

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

3.实现内容提供者

3.1 内容提供者实现步骤

3.2 系统配置文件注册内容提供者

3.3 访问内容的 URI

3.4 处理 MIME类型数据的请求

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

4.应用内部使用内容提供者

5.跨应用使用内容提供者

6.使用手机自身内容提供者

7.内容提供者小结


1.Android 四大组件及纽带

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

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

  • 功能1:存储和检索来自 数据源 的数据      
  • 功能2:使用 内容提供者 进行 跨应用 数据共享 (不同程序之间的桥梁) 
  • 原理:通过抽象底层数据源,将应用与数据层分离,:使数据源具有独立性
  • 内容提供者分类:
  1. 自定义内容提供者
  2. 本机内容提供者

3.实现内容提供者

3.1 内容提供者实现步骤

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

3.2 系统配置文件注册内容提供者

<provider android:name="MyCustomProvider"  
android:authorities="com.DatabaseDemo.provider.MyCustomProvider">
</provider>

3.3 访问内容的 URI

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

3.4 处理 MIME类型数据的请求

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

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

  • 访问内容提供者公开的数据,需要使用 android.content.ContentResolver 类
  • 每个 Android 应用上下文都包括一个可访问的 ContentResolver实例,如下:
  • ContentResolver resolver = getContentResolver();
  • 从内容提供者检索记录:ContentResolver.query() 方法 或 Activity.managedQuery() 方法
  • 处理查询:必须在 ContentProvider 类扩展的类中实现 delete()、insert()、update() 和 query() 方法

4.应用内部使用内容提供者

  • SQLHelper.java:
// SQLHelper.java
public class SQLHelper extends SQLiteOpenHelper{
	public SQLHelper(Context context) {
		super(context,"NIIT.db",null,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) {
			switch (v.getId()) {
			case R.id.insert:
				// 获取两个参数:名字、手机,编号是自动增长的所以不需要获取,注意顺序问题!				
				String[] args1={etName.getText().toString(),etMobile.getText().toString()};
				// 自己书写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 注意顺序问题!不可以改变顺序
				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; // 返回值 表示更新时受到影响的行数
	}}
  • activity_main.xml:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"......>
    <TextView
        android:id="@+id/textView5"...
        android:text="联系人信息"/>
    <TextView // 编号提示信息
        android:id="@+id/textView1"...    
        android:text="编号"/>
    <EditText // 编号用户编辑区
        android:id="@+id/etId".../>
    <TextView // 姓名提示信息
        android:id="@+id/textView2"...
        android:text="姓名"/>
    <EditText // 姓名用户编辑区
        android:id="@+id/etName".../>
    <TextView // 手机提示信息
        android:id="@+id/textView3"...
        android:text="手机"/>
    <EditText // 手机用户编辑区
        android:id="@+id/etMobile".../>
    <!-- 嵌套布局:添加四个按钮使之一行 -->
    <LinearLayout
        android:gravity="center_horizontal" >
        <Button
            android:id="@+id/insert"
            android:text="插入" />
        <Button
            android:id="@+id/modify"
            android:text="修改" />
        <Button
            android:id="@+id/delete"
            android:text="删除" />
        <Button
            android:id="@+id/query"
            android:text="查询" />
    </LinearLayout>
    <Button
        android:id="@+id/selectAll" // 查询所有大按钮
        android:text="查看所有联系人" />
</LinearLayout>
  •  Andoid.Manifest.xml:
        <provider    // 注册内容提供者信息
            // name:内容提供者的完整类名,即包名.类名,必须根据实际类名定义        
            android:name="com.Lyrelion.contentprovider.ContactProvider"   
            // authorities:内容提供者的引用名/别名,可以自定义,但要唯一,最好以包名.类名格式写 
            android:authorities="com.Lyrelion.contentprovider.ContactProvider"
            //  exported:是否要共享数据
            android:exported="true" >
        </provider>
  • 控制台部分效果展示:  
  • 应用界面效果展示:  

5.跨应用使用内容提供者

  • MainActivity.java:
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;
			case R.id.delete:
				cr.delete(uri,"id=?",new String[]{etId.getText().toString()});
				Toast.makeText(MainActivity.this,"删除成功!",Toast.LENGTH_LONG).show();
				break;
			case R.id.query:
				Cursor c=cr.query(uri,null,"id=?",
						new String[]{etId.getText().toString()},null);
				if(c.moveToFirst()){
					etName.setText(c.getString(1));
					etMobile.setText(c.getString(2));
				}else {
					etName.setText("");
					etMobile.setText("");
					Toast.makeText(MainActivity.this,"查询到了!",Toast.LENGTH_LONG).show();}
				break;
			}}}}
  • 应用界面效果展示:   

6.使用手机自身内容提供者

  • MainActivity.java:
public class MainActivity extends Activity {
	Button b;
	TextView tv;
	ContentResolver cr;
	Uri uri=Phone.CONTENT_URI; //通过 iPhone类 常参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----------------------------------");
				}}});}}
  • activity_main.xml:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    <Button
        android:id="@+id/button1"
        android:text="显示联系人" />
    <TextView // 可以使用 append()追加文本内容
        android:id="@+id/textView1"
        android:text="联系人信息:" />
  •  Andoid.Manifest.xml: 
    <!--要使用手机自身的一些功能,需要获取对应的权限才可-->
    <uses-permission android:name="android.permission.READ_CONTACTS" />
  • 应用界面效果展示:

7.内容提供者小结

  • 内容提供者充当 应用间共享数据 的接口
  • 所有内容提供者 使用公共接口 查询提供者 并返回结果,添加、更新和删除数据也从相同接口执行
  • 要创建自己的内容提供者,需要创建 ContentProvider类 并重写其方法。
  • 要访问内容提供者,可使用 ContentResolver类
  • 创建内容提供者后,必须将其添加到 系统配置文件(AndroidManifest.xml) 
发布了29 篇原创文章 · 获赞 21 · 访问量 1654

猜你喜欢

转载自blog.csdn.net/Lyrelion/article/details/105066814