Android课堂笔记(五)——内容提供者
一.内容提供者1.预备1.1使用 java代码 创建数据库SQLiteDatabase类:公开一些方法用于实现数据库增删改查,如insert(),update(),delete(),query(),execSQL()SQLiteOpenHelper类:用于创建和管理数据库,包括数据库版本管理Cursor接口:查询返回的结果集ContentValues类:一个该类对象表示...
·
目录
1.Android 四大组件及纽带
- 活动:Activity
- 内容提供者:Content Provider
- 服务:Service
- 广播接收器:BroadcastReceiver
- 连接四大组件的纽带:Intent
2.内容提供者功能、原理、分类
- 功能:
- 存储检索数据源数据,比如 应用访问手机自带通讯录
- 与其他应用共享数据,比如 应用访问另一应用数据库
- 原理:抽象底层数据源,将应用与数据层分离,:使数据源具有独立性
- 分类:
- 自定义内容提供者
- 本机内容提供者
3.实现内容提供者(ContentProvider)
3.1 实现步骤
- 自定义一个 ContentProvider类
- 重写抽象方法: onCreate()、 insert()、 update()、 delete()、 query()、 getType()(MIME)
- 在 AndroidManifest.xml 系统配置文件中注册 自定义内容提供者
- 指定要访问的 URI
- 在另一应用里通过 ContentResolver 访问内容提供者公开的数据
3.2 访问内容的 URI
- URI(Uniform Resource Identifier):统一资源标识符,是 URL 父级
- URI包含 本地+网络 地址,URL只有网络地址
- 每个内容提供者公开一个 URI:唯一标识该内容提供者的数据集
- 如果一个内容提供者控制多个数据集,则需要为每个数据集指定单独的 URI
- URI 以字符串 content:// 开头,就像网站 URL 以http://开头,两种格式如下:
- 请求 Example表中 所有记录:content://bagname.contenttprovider/Example
- 请求 Example表中 第一行记录:content://bagname.contenttprovider/Example/1
- 访问内容提供者,需要用 android.content 程序包的 UriMatcher 类
3.3 处理 MIME类型数据请求
- 处理内容提供者提供的 MIME数据类型 的请求,需要重写 getType() 方法
- getType() :将 URI 对象作为参数,并返回字符串,该字符串唯一描述 URI的 MIME类型,返回类型:
- vnd.android.cursor.item/<contenttype>:对 单条目 返回 单项
- 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" />
- 应用界面效果展示:
更多推荐
已为社区贡献1条内容
所有评论(0)