ContentProvider与sqlit的搭配使用

来源:互联网 发布:asp.net 进销存源码 编辑:程序博客网 时间:2024/05/10 03:20

上一篇文章Android持久化存储的几种方式已经讲诉了Android开发中文件存储、网络存储和SharedPreferences这三种持久化存储的方式,以及大致讲了什么是ContentProvider和它的使用场景。那么这篇文章我们就来具体讲诉一下如何使用ContentProvider与sqlit搭配,实现与一个APP对另一个APP的数据增删改查。

首先我们使用SQLiteOpenHelper这个类来创建一个数据库,并创建一个储存个人信息的People_Message的表。

public class MyDatabaseHelper extends SQLiteOpenHelper {    //sql语句,用来创建表。    public static final String People_Message="create table people("            +"num integer primary key autoincrement,"            +"name text,"            +"sex text)";    Context mContext;    public MyDatabaseHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {        //调用父类构造方法,创建数据库。第一个参数是context。第二个参数是数据库的名字,第三个参CursorFactory指定在执行查询时获得一个游标实例的工厂类,设置为null,代表使用系统默认的工厂类,第四个参数是数据库的版本号,不能小于一。        super(context, name, factory, version);        mContext=context;    }    @Override    public void onCreate(SQLiteDatabase db) {        //创建表,执行sql语句        db.execSQL(People_Message);    }    @Override    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {        //如果需要升级数据库,会调用该方法。可以用来删除表或者添加表。    }}

上面是一个继承了SQLiteOpenHelper类的类。在构造方法中会调用父类构造方法,创建一个数据库。然后在onCreate中使用 db.execSQL()这个方法执行sql语句,进行表创建。
然后我们需要在主线程中创建一个MyDatabaseHelper对象,这样就创建好了数据库和表(如果数据库和表已经存在,将不会创建)。

mMyDatabaseHelper=new MyDatabaseHelper(getApplicationContext(),"people_message",null,1);

然后我们需要得到一个SQLiteDatabase 对象,这个对象可以用来操作数据库。

//得到可以读写数据库的SQLiteDatabasedb=mMyDatabaseHelper.getWritableDatabase();//得到只读数据库的SQLiteDatabase//db=mMyDatabaseHelper.getReadableDatabase();   

上面代码可以,我们可以通过刚才创造的SQLiteOpenHelper对象来获取SQLiteDatabase。其中有两种获取方式,一个可以对数据库进行写入,另一个只读。
SQLiteDatabase这个对象中有几个方法,是对修改数据库的几种方式进行了包装。
从数据库中查询数据
db.query(String table,String[] columns,String selection,String[] selectionArgs,String groupBy,String having,String orderBy,String limit)
参数意义:
table:表名
columns:需要得到的列名数组
selection:条件字句,相当于where
selectionArgs:条件字句,条件的数组
groupBy:分组列名
having:分组条件
orderBy:排序列名
limit:查询限制

往数据库中插入数据
db.insert(String table,String nullColumnHack,ContentValues values)
参数意义:
table:表名
nullColumnHack:空列的默认值
values:插入的数据,key-value类型的集合

把数据库中指定的数据删除
db.delete(String table,String whereClause,String[] whereArgs)
参数意义:
table:表名
whereClause:删除条件
whereArgs:删除条件值数组

修改数据库中指定的数据
db.update(String table,ContentValues values,String whereClause, String[] whereArgs)
参数意义:
table:表名
values:修改的数据,key-value类型的集合
whereClause:修改条件
whereArgs:修改条件值数组

执行具体的sql语句
db.execSQL(“sql语句”)

db.XXXX的方法还有许多,如果上面的不能满足你的要求,你可以看看源码,选择自己需要的方法。
上述方法中都有很多参数,除了db.execSQL()中的参数是你需要执行的sql语句外,其他的参数都有很多,这里不细讲,使用的时候大家可以再学习。

上面我们已经建立了一个数据库并且创建了一个表。下面就是需要对表进行操作了。这里我们使用ContentProvider来对表进行操作。

我们创建一个类继承与ContentProvider,并在AndroidManifast中进行注册。

public class MyContentProvider extends ContentProvider{    public MyContentProvider()    {    }    @Override    public int delete(Uri uri, String selection, String[] selectionArgs)    {        // Implement this to handle requests to delete one or more rows.        throw new UnsupportedOperationException("Not yet implemented");    }    @Override    public String getType(Uri uri)    {        // TODO: Implement this to handle requests for the MIME type of the data        // at the given URI.        throw new UnsupportedOperationException("Not yet implemented");    }    @Override    public Uri insert(Uri uri, ContentValues values)    {        // TODO: Implement this to handle requests to insert a new row.        throw new UnsupportedOperationException("Not yet implemented");    }    @Override    public boolean onCreate()    {        // TODO: Implement this to initialize your content provider on startup.        return false;    }    @Override    public Cursor query(Uri uri, String[] projection, String selection,                        String[] selectionArgs, String sortOrder)    {        // TODO: Implement this to handle query requests from clients.        throw new UnsupportedOperationException("Not yet implemented");    }    @Override    public int update(Uri uri, ContentValues values, String selection,                      String[] selectionArgs)    {        // TODO: Implement this to handle requests to update one or more rows.        throw new UnsupportedOperationException("Not yet implemented");    }}

上面代码可以看见,除了无参构造函数之外,还会自动生成几个重写方法,这几个方法就是上面我们所说的增删改查几个方法,我们可以在对应函数中就可以自己编写对数据库的操作了。
我们发现上面的几个方法中第一个参数类型都是Uri,这个参数代表要操作的数据。我们先来简单说一下Uri的构造,理解一下Uri具体的用法。

Uri 通用资源标志符(Universal Resource Identifier)

uri及基本结构是 [scheme:][//authority][path][?query][#fragment] 这个五个部分,但是除了[scheme:][//authority]必须有之外,其他的每一个部分都可以不需要。但是顺序不能改变。
拿一个例子来说
uri=http://www.java2s.com:8080/yourpath/fileName.htm?stove=10&path=32&id=4#harvic
对于这个uri来说,我们来解析一下它的各部分结构。
[scheme:]=http 在//之前都属于[scheme:]
[//authority]=www.java2s.com:8080 主机名 //之后[path]之前
[path]=yourpath/fileName.htm 具体的路径 主机名之后[?query]之前都属于[path]
[?query]=?stove=10&path=32&id=4 ?号之后 #之前
[#fragment]=#harvic #之后都属于[#fragment]
(上面只是对Uri结构的简单的介绍,如果详细了解可以点击Uri详解之——Uri结构与代码提取查看)

上面就是Uri的具体结构,我们通过具体的Uri就可以访问我们需要访问的数据了,对于ContentProvider来说,用来访问它的Uri有具体的格式。
[scheme:]=content
[//authority]=主机名,在AndroidManifest文件中可以对具体ContentProvider的authorities属性进行修改和查看,这里我们上面定义ContentProvider的authorities为”test_contentProvider”。

<provider            android:name=".contentProvider.MyContentProvider"            android:authorities="test_contentProvider"            android:enabled="true"            android:exported="true"></provider>

[path]就是我们表的名字,在这个事例程序中就是”people”。
所以这个ContentProvider的指定Uri就是

Uri PEO=Uri.parse("content://test_contentProvider/people");

那么我们来看看完整的MyContentProvider类应该是怎样的

public class MyContentProvider extends ContentProvider{    MyDatabaseHelper mMyDatabaseHelper;    SQLiteDatabase db;    UriMatcher sMatcher;    Uri PEO=Uri.parse("content://test_contentProvider/people");    public MyContentProvider()    {    }    //用于匹配传入的URI,如果不匹配返回-1    public int getUriMatcher(Uri uri){        return sMatcher.match(uri);    }    @Override    public int delete(Uri uri, String selection, String[] selectionArgs)    {        //删除数据        if(getUriMatcher(uri)==1){            db.delete("people",selection,selectionArgs);            getContext().getContentResolver().notifyChange(PEO,null);            return 1;        }        return 0;    }    @Override    public String getType(Uri uri)    {        // TODO: Implement this to handle requests for the MIME type of the data        // at the given URI.        throw new UnsupportedOperationException("Not yet implemented");    }    @Override    public Uri insert(Uri uri, ContentValues values)    {        //判断传入的URI是否匹配,匹配的话将数据插入数据库        if (getUriMatcher(uri)==1){            db.insert("people",null,values);            getContext().getContentResolver().notifyChange(PEO,null);        }        return null;    }    @Override    public boolean onCreate()    {        //打开数据库,得到db        mMyDatabaseHelper=new MyDatabaseHelper(getContext(),"data",null,1);        //得到可以读写数据库的SQLiteDatabase        db=mMyDatabaseHelper.getWritableDatabase();        //UriMatcher.NO_MATCH表示不匹配任何Uri的返回码-1        sMatcher=new UriMatcher(UriMatcher.NO_MATCH);        //添加一个匹配规则:第一个参数contentProvider的authority值,第二个参数数据表名,第三个参数 匹配后返回值        sMatcher.addURI("test_contentProvider","people",1);        return false;    }    @Override    public Cursor query(Uri uri, String[] projection, String selection,                        String[] selectionArgs, String sortOrder)    {        //查询数据        if (getUriMatcher(uri)==1){            Cursor cursor=db.query("people",null,selection,selectionArgs,null,null,sortOrder);            return cursor;        }        return  null;    }    @Override    public int update(Uri uri, ContentValues values, String selection,                      String[] selectionArgs)    {        //更新数据        if (getUriMatcher(uri)==1){            db.update("people",values,selection,selectionArgs);            getContext().getContentResolver().notifyChange(PEO,null);            return 1;        }        return  0;    }

1.首先我们在onCreate构造函数中,创建或打开要操作的数据库,得到用来操作数据库的db。
2.接着我们为new出一个UriMatcher对象,给这个对象添加一个URi(可以同时添加多个,只要返回码不一样),这个Uri就是用来访问当前MyContentProvider的指定Uri,通过对ContentProvider时传入的URI进行校验,判断是否可以能够匹配,根据匹配的返回码,得知具体需要操作的数据。
3.在增删改查的四个方法中,进行具体的数据操作,这篇文章主要是对数据库的增删改查操作,所以直接使用db.xxxx()方法来进行操作。
4.在增删改完成之后,如果对数据进行了修改,使用getContext().getContentResolver().notifyChange(PEO,null)这段代码,对指定的URI添加一个通知,通知当前URI的数据有修改,便于ContentObserver进行监听。

上面就构造出了一个自定义的ContentProvider。它的指定Uri”content://test_contentProvider/people”。
我们初始化数据库,向数据库中插入十条数据,便于显示和查询。

public class PeopleActivity extends AppCompatActivity{    MyDatabaseHelper mMyDatabaseHelper;    SQLiteDatabase db;    MyContentProvider mMyContentProvider;    ListView mListView;    List<PeopleBeen> mPeopleBeens;    @Override    protected void onCreate(Bundle savedInstanceState)    {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_people);        mListView=(ListView)findViewById(R.id.list);        mPeopleBeens=new ArrayList<>();        mMyDatabaseHelper=new MyDatabaseHelper(getApplicationContext(),"data",null,1);        //得到可以读写数据库的SQLiteDatabase        db=mMyDatabaseHelper.getWritableDatabase();        PeopleBeen p;        for(int i=0;i<10;i++){            p=new PeopleBeen();            p.setNum(10+i);            p.setName("王"+i);            p.setSex(((i%3==0)?"女":"男"));            ContentValues values = new ContentValues();            values.put("num", p.getNum());            values.put("name", p.getName());            values.put("sex",p.getSex());            db.insert("people",null, values);        }        Cursor cursor=db.query("people",null,null,null,null,null,null);        while (cursor.moveToNext()){            PeopleBeen pp=new PeopleBeen();            pp.setNum(cursor.getInt(cursor.getColumnIndex("num")));            pp.setName(cursor.getString(cursor.getColumnIndex("name")));            pp.setSex(cursor.getString(cursor.getColumnIndex("sex")));            mPeopleBeens.add(pp);        }        //mMyContentProvider=new MyContentProvider();        mListView.setAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_expandable_list_item_1, getData()));    }    private List<String> getData(){        List<String> data = new ArrayList<String>();        for(PeopleBeen p:mPeopleBeens){            data.add(p.getNum()+"   名字:"+p.getName()+"   性别:"+p.getSex());        }        return data;    }    @Override    protected void onDestroy()    {        super.onDestroy();        db.close();;    }}

运行结果:
这里写图片描述

现在我们新建一个项目,在另一个项目中使用这个ContentProvider。

public class MainActivity extends AppCompatActivity implements View.OnClickListener{    EditText ed_num;    EditText ed_name;    EditText ed_sex;    Button bt_cx;    Button bt_cr;    Button bt_xg;    Button bt_sc;    TextView tv_jg;    ContentResolver mContentResolver;    PersonOberserver personOberserver;    Uri PEO=Uri.parse("content://test_contentProvider/people");    Handler mHandler=new Handler(){        @Override        public void handleMessage(Message msg)        {            super.handleMessage(msg);            Toast.makeText(getApplication(),"修改成功",Toast.LENGTH_LONG).show();        }    };    @Override    protected void onCreate(Bundle savedInstanceState)    {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        ed_num=(EditText)findViewById(R.id.et_num);        ed_name=(EditText)findViewById(R.id.et_name);        ed_sex=(EditText)findViewById(R.id.et_sex);        bt_cx=(Button)findViewById(R.id.bt_cx);        bt_cr=(Button)findViewById(R.id.bt_cr);        bt_xg=(Button)findViewById(R.id.bt_xg);        bt_sc=(Button)findViewById(R.id.bt_sc);        tv_jg=(TextView)findViewById(R.id.tv_jg);        bt_cx.setOnClickListener(this);        bt_cr.setOnClickListener(this);        bt_xg.setOnClickListener(this);        bt_sc.setOnClickListener(this);        //初始化ContentResolver,用来与ContentProvider建立联系        mContentResolver=getContentResolver();        //初始化ContentOberserver,用来监听指定URI数据的改变。        personOberserver=new PersonOberserver(mHandler);        //注册监听,当指定URI发生改变时,personOberserver中的onChange()会得到执行。        mContentResolver.registerContentObserver(PEO,true,personOberserver);    }    @Override    public void onClick(View view)    {        switch (view.getId()){            case R.id.bt_cr:                //插入数据                ContentValues values = new ContentValues();                values.put("num", Integer.parseInt(ed_num.getText().toString()));                values.put("name", ed_name.getText().toString());                values.put("sex",ed_sex.getText().toString());                mContentResolver.insert(PEO,values);                break;            case R.id.bt_cx:                //根据编号查询数据                tv_jg.setText("");                Cursor cursor = mContentResolver.query(PEO, null, "num=?", new String[]{ed_num.getText().toString()}, null);                while (cursor.moveToNext()){                    tv_jg.setText("编号:"+cursor.getInt(cursor.getColumnIndex("num"))+"   姓名:"+cursor.getString(cursor.getColumnIndex("name"))+"   性别:"+cursor.getString(cursor.getColumnIndex("sex")));                }                break;            case R.id.bt_sc:                //根据编号删除数据                int result=mContentResolver.delete(PEO,"num=?",new String[]{ed_num.getText().toString()});                break;            case R.id.bt_xg:                //根据编号修改数据                ContentValues values_xg = new ContentValues();                values_xg.put("name", ed_name.getText().toString());                values_xg.put("sex", ed_sex.getText().toString());                mContentResolver.update(PEO,values_xg,"num=?",new String[]{ed_num.getText().toString()});                break;        }    }    @Override    protected void onDestroy()    {        super.onDestroy();        mContentResolver.unregisterContentObserver(personOberserver);    }}public class PersonOberserver extends ContentObserver{    Handler mHandler;    public PersonOberserver(Handler handler)    {        super(handler);        mHandler=handler;    }    @Override    public void onChange(boolean selfChange)    {        Log.e("dd","dd");        Message message=new Message();        mHandler.sendMessage(message);    }}

我们看上面的代码,首先在onCreate周期函数中,初始化了ContentResolver,ContentResolver叫做内容解析者,当外部应用需要对ContentProvider中的数据进行添加、删除、修改和查询操作时,可以使用ContentResolver 类来完成。ContentResolver 中也拥有insert(),delete(),update(),query()这四种方法,里面的参数和数据库操作时使用的增删改查方法的参数差不多。这四种方法对应的就是ContentProvider的四种数据操作方法
接着初始化了PersonOberserver对象,这个对象是一个可以用来监听特定URI数据变化的对象。我们用registerContentObserver方法来给ContentResolver注册一个PersonOberserver,这样,当指定URI的数据发生改变时,PersonOberserver中的onChange方法就会得到调用。
我们为四个button绑定了各自的监听事件,在监听事件中,我们使用了mContentResolver.xxxxx()方法来进行增删改查,它们的参数中都有一个URI参数,而这个URI参数就是找到指定ContentProvider的标识。有了这个URI,我们才能通过ContentResolver去执行指定ContentProvider中的方法,并得到相应的数据。

另一个app的演示结果
查:
这里写图片描述

增:
这里写图片描述
这里写图片描述

原创粉丝点击