设计两个程序,一个A程序,一个B程序,在A程序中创建ContentProvider暴露我们想要暴露的数据,然后再在程序中创建ContentResolver对A程序暴露的数据进行访问;
在创建的过程尤其值得注意的是:如果想要在B程序中访问A程序暴露的数据,必须在A程序的注册文件中的相应ContentProvider加上android:exported="true"属性;
如果你忘记加上这个属性,那么在B程序中试图访问A的暴露数据,那么就会出现以下错误:
这样写的A,B程序有个问题是,如果A程序没有运行过,或者说被强行关闭后,B程序就不能获取到A程序的数据,容易造成空指针,如果想处理这个问题
可以把ContentProvider代码写在后台运行(不能接触强行关闭的)
先创建A程序,A程序结构如下:
先给出布局文件代码:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<TextView
android:text="我是内容提供 "
android:layout_height="wrap_content"
android:layout_width="wrap_content"/>
</LinearLayout>
然后是创建SQLiteOpenHelperd 的myDBSQLite类;主要负责上下文传递和相应创建数据库.代码如下:
package com.example.dao;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteDatabase.CursorFactory;
import android.database.sqlite.SQLiteOpenHelper;
public class myDBSQLite extends SQLiteOpenHelper {//第一个程序的SQLiteOpenHelper
//构造函数,提供上下文
public myDBSQLite(Context context)
{
super(context, "persons.db", null, 3);//创建persons数据库
// TODO 自动生成的构造函数存根
}
//创建表格
@Override
public void onCreate(SQLiteDatabase arg0) {
// TODO 自动生成的方法存根
arg0.execSQL("create table persons(id Integer primary key autoincrement,name nvchar(20),nameText nvchar(20))");
}
//版本更新时候调用
@Override
public void onUpgrade(SQLiteDatabase arg0, int arg1, int arg2) {
// TODO 自动生成的方法存根
}
}
再给出ContentProvider 来暴露A程序的数据。代码如下:
package com.example.myoperationcontentprovider;
import com.example.dao.myDBSQLite;
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 myContentProvider extends ContentProvider {
private static UriMatcher matcher =new UriMatcher(UriMatcher.NO_MATCH);//获取uri匹配器
private static final int INSERT=1;//添加数据成功匹配Uri路径成功时候返回值
private static final int UPDATE=2;//更新数据成功后匹配uri路径成功时候的返回值
private static final int DELETE=3;//删除数据成功后匹配uri成功时候返回值
private static final int QUERY=4;//查询到数据匹配uri成功时候的返回值
private static final int QUERYONE=5;//查询到一行数据匹配uri成功时候的返回值
private myDBSQLite helper;
static {
matcher.addURI("cn.itcast.myContent", "insert", INSERT); //增加数据插入匹配规程
matcher.addURI("cn.itcast.myContent", "update", UPDATE);//更新数据
matcher.addURI("cn.itcast.myContent", "delete", DELETE);//删除数据
matcher.addURI("cn.itcast.myContent", "query/#", QUERYONE);//查询特定数据
matcher.addURI("cn.itcast.myContent", "query", QUERY);//查询一系列数据
}
@Override
public int delete(Uri arg0, String arg1, String[] arg2) {//删除数据
if(matcher.match(arg0)==DELETE){//匹配删除成功
SQLiteDatabase db=helper.getWritableDatabase();
db.delete("persons", arg1, arg2);
}else{
throw new IllegalArgumentException("路径匹配失败,不能执行删除操作 ");//异常必须是IllegalArgumentException,若是Exception则需要在try中书写
}
// TODO 自动生成的方法存根
return 0;
}
@Override
public String getType(Uri arg0) {
if(matcher.match(arg0)==QUERY){
return "vnd.android.cursor.dir/persons";//表示返回一个集合
}
else if(matcher.match(arg0)==QUERYONE){
// TODO 自动生成的方法存根
return "vnd.android.cursor.item/persons";//返回一个数据
}
return null;
}
@Override
public Uri insert(Uri arg0, ContentValues arg1) {
if(matcher.match(arg0)==INSERT){
SQLiteDatabase db=helper.getWritableDatabase();
db.insert("persons", null, arg1);
}
else{
throw new IllegalArgumentException("路径匹配失败,不鞥执行插入操作");
}
// TODO 自动生成的方法存根
return null;
}
@Override
public boolean onCreate() {
helper=new myDBSQLite(getContext());
// TODO 自动生成的方法存根
return false;
}
@Override
public Cursor query(Uri arg0, String[] arg1, String arg2, String[] arg3,
String arg4) {
if(matcher.match(arg0)==QUERYONE){//如果匹配查询一个数据
SQLiteDatabase db=helper.getReadableDatabase();
long id=ContentUris.parseId(arg0);//获取当前uri、中数据的id
Cursor cursor=db.query("persons", arg1, "id=?", new String []{""+id}, null, null, arg4);
return cursor;//返回一个游标数据,如果没有该返回,在contentresolverz中将查询不到数据
}
else if(matcher.match(arg0)==QUERY){//如果匹配到一个查询集合数据
SQLiteDatabase db=helper.getReadableDatabase();
Cursor cursor=db.query("persons", arg1, arg2, arg3, null, null, arg4);
return cursor;//返回一个游标数据,如果没有该返回,在contentresolverz中将查询不到数据
}
else {
throw new IllegalArgumentException("路径不匹配,不能执行查询");
}
// TODO 自动生成的方法存根
}
@Override
public int update(Uri arg0, ContentValues arg1, String arg2, String[] arg3) {
if(matcher.match(arg0)==UPDATE){
SQLiteDatabase db=helper.getWritableDatabase();
db.update("persons", arg1, arg2, arg3);
}else{
throw new IllegalArgumentException("路径匹配失败,不能更新操作");
}
// TODO 自动生成的方法存根
return 0;
}
}
然后是操作对象的实体类,代码如下:
package com.example.javabean;
public class Person {
//保存相关数据操作的类
private long id;
private String name;
private String nameText;
public Person(int id,String name,String nameText){
this.id=id;
this.name=name;
this.nameText=nameText;
}
public Person(String name,String nameText){
this.name=name;
this.nameText=nameText;
}
public Person(){
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getNameText() {
return nameText;
}
public void setNameText(String nameText) {
this.nameText = nameText;
}
}
然后是实体代码的实现类,主要是对实体操作的数据库具体实现:代码如下:
package com.example.dao;
import java.util.ArrayList;
import java.util.List;
import com.example.javabean.Person;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.widget.ListView;
public class PersonDao {
private myDBSQLite helper;
public PersonDao(Context context){
helper=new myDBSQLite(context);
//实例化SQLiteOpenHelper的对象
}
//书写插入方法
public long insert(Person person){
SQLiteDatabase db=helper.getWritableDatabase();//获得一个可以写入数据库对象,不需要权限说明
ContentValues contentValues=new ContentValues();
contentValues.put("name", person.getName());
contentValues.put("nameText", person.getNameText());
long ids=db.insert("persons", null, contentValues);
db.close();
return ids;//返回受到影响的行数
}
public List<Person> query(){//查询一系列数据
List<Person> list=new ArrayList<Person>();
SQLiteDatabase db=helper.getReadableDatabase();//得到一个可以只读的数据库对象
String sql="";
Cursor cursor=db.query("persons", null, null, null, null, null, null);
//查询persons表格中所有数据
while(cursor.moveToNext()){
//得到数据库中想要的值
int id=cursor.getInt(cursor.getColumnIndex("id"));//得到游标中的取得数据库标识为id的数据
String name=cursor.getString(cursor.getColumnIndex("name"));
String nameText=cursor.getString(cursor.getColumnIndex("nameText"));
//判断数据是不是空,如果是空表示没有查到数据
if((id+"")!=""&&(name!="")&&(nameText!="")){
list.add(new Person(id, name, nameText));
}
}
cursor.close();//关闭游标,关闭数据库,否则容易造成内存浪费,可能造成内存不足
db.close();
return list;//返回查询到的数据,用集合
}
}
最后在主界面中对数据库插入数据:代码如下:
package com.example.myoperationcontentprovider;
import java.util.ArrayList;
import java.util.List;
import com.example.dao.PersonDao;
import com.example.javabean.Person;
import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
import android.widget.Toast;
public class MainActivity extends Activity {
private List<Person> list;
private PersonDao personDao;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
list=new ArrayList<Person>();
personDao=new PersonDao(this);
//插入数据(如果数据库里面没有数据就查询的话容易造成空指针异常)
for(int i=0;i<3;i++){
personDao.insert(new Person("我"+i,"没事没事"+i));
}
//判断数据是否为空
list=personDao.query();
for(int i=0;i<list.size();i++){
if(list.get(i).equals("")){
Toast.makeText(this, "数据插入失败", Toast.LENGTH_SHORT).show();
}
else{
Toast.makeText(this, "数据插入"+list.get(i).getId()+"成功", Toast.LENGTH_SHORT).show();
}
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
}
A程序主要0的注册文件如下:
<provider
android:exported="true"
android:name="com.example.myoperationcontentprovider.myContentProvider"
android:authorities="cn.itcast.myContent"/>
A程序结束,运行结果如下:
B程序开始:B的代码结构如下:
B的主界面布局为:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<ListView
android:id="@+id/listview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
</LinearLayout>
ListView具体布局如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal" >
"
<TextView
android:id="@+id/name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:hint="这是name" />
<TextView
android:layout_marginLeft="30dp"
android:id="@+id/nameText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:hint="这是nameText" />
</LinearLayout>
实体类和上面所讲一样就不再赘述:
主界面实现代码如下:完成适配器数据配对和获取A程序的暴露数据
package com.example.myopearationcontentresolver;
import java.util.ArrayList;
import java.util.List;
import com.example.javabean.Person;
import android.R.integer;
import android.app.Activity;
import android.content.ContentResolver;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
public class MainActivity extends Activity {
private myAdapter adapter;
List<Person> list;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ListView listView=(ListView)findViewById(R.id.listview);
getPersonInfos();
adapter=new myAdapter();
//测试查询数据是否成功
for(int i=0;i<list.size();i++){
Toast.makeText(this, list.get(i).getName(), Toast.LENGTH_SHORT).show();
}
//绑定适配器
listView.setAdapter(adapter);
}
private void getPersonInfos(){
list=new ArrayList<Person>();
ContentResolver resolver=getContentResolver();
//注意,如果想要在B程序中访问A程序的contentProvider就需要在A程序的Contentprovider注册加入
//android:exported="true"属性,否则会报安全错误
//content不能丢
String path="content://cn.itcast.myContent/query";
Uri uri=Uri.parse(path);
Cursor cursor=resolver.query(uri, null, null, null, null);
if(cursor==null){
Toast.makeText(this, "contentR失败", 1).show();
}
else{//cursor数据 不为空
while(cursor.moveToNext()){
int id=cursor.getInt(cursor.getColumnIndex("id"));
String name=cursor.getString(cursor.getColumnIndex("name"));
String nameText=cursor.getString(cursor.getColumnIndex("nameText"));
list.add(new Person(id,name,nameText));
}
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
private class myAdapter extends BaseAdapter {
//简单baseAdapter运用
@Override
public int getCount() {
// TODO Auto-generated method stub
return list.size();
}
@Override
public Object getItem(int position) {
// TODO Auto-generated method stub
return list.get(position);
}
@Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
View view=View.inflate(MainActivity.this, R.layout.listview, null);
Person person=list.get(position);
TextView nameTextView=(TextView)view.findViewById(R.id.name);
TextView nameTextTextView=(TextView)view.findViewById(R.id.nameText);
nameTextView.setText("姓名为:"+person.getName());
nameTextTextView.setText("信息为:"+person.getNameText());
return view;
}
}
}