ContentProvider 的创建以及增删改查操作(你想看的都在这里了)

一、创建

新建:新建一个继承自ContentProvider的类
重写:重写6个方法,分别是create(),insert(),delete(),update(),query(),getType()
注册:需要在Manifest中注册provider。这样当外部程序访问本程序数据时,可以精确知道用的是哪个provider
            
 
            android:authorities="com.example.administrator.sqliteexecsql.provider"
            android:name="com.example.administrator.sqliteexecsql.DBProvider"
            android:exported="true"/>
name 是继承自ContentProvider的类名
authorities 是自己起的一个名字,作为外部程序使用ContentProvider的识别.格式最好写com.example.provider
exported 设置为true表示允许外部程序使用provider,设为false则外部程序不能使用
调用:ContentResolver resolver = getContentResolver();之后根据设置的uri来具体调用ContentProvider中的方法
URI: content://com.example.provider/person/10
        content:// ----->固定写法
        com.example.provider即是你在清单文件中注册provider时的authorities
       person-------->path
        10-------------->pweson id

二、查(从比较难的查开始,其他的增删改则不在话下了)

//查询方法,需要传入uri,可以传入列名,查询条件,Where后面占位符的值,以及排序方式
    @Override
    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
        SQLiteDatabase db =myHelper.getReadableDatabase();
       /* Cursor c = db.query("person",null,null,null,null,null,null); 查询所有,所有列,无条件,无排序方式等。
       如果那边在调用Cursor query()方法时,需要有条件,则这边db.query()中需要加上相应的参数
        例如,那边要查balance>? orderBy为  “balance DESC”,那么这边就要
       Cursor c = db.query("person",null,selection,selectionArgs,null,null,sortOrder);
        但是,另一个问题出现了,就是这里写死了查person表,如果数据库里有多个表,如何指定查哪张表呢?
        在外部应用在使用本程序的数据时,查哪张表,别人可以在Uri指定path,本程序要做对应处理,如何处理?
        分析,外部应用,指定查哪张表的uri:content://com.example.provider/person  后面的person(path)即为表名
        我们只要在本程序中可以拿到后面的表名就可以设置逻辑判断,分析结束
        解决方法:UriMatcher 对象的addURI("authorities",path,code)方法,给每个表一个数字编码
        具体代码如下:
        matcher.addURI(authorities,"person",0);
        matcher.addURI(authorities,"student",1);
        matcher.addURI(authorities,"person/#",2);
        UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH);
        authorities就写Manifest中配置的。下面两行将person表的编码设为0,student表的编码设为1

        设完之后如何判断?matcher.match(uri),可以返回code
        判断查哪张表的逻辑已经清晰了(UriMatcher-->matcher.addURI(,,,)-->matcher.match(uri)-->得到code)
        现在又另外一个问题,我想查当前表的具体哪一个id,当然可以再外部程序调用时加上where条件
        外部程序中Cursor c =resolver.query("person",null,"id=?",new String[]{"10"},null);
        但是太麻烦。我想把id=?去掉,即selection为null,不直接写条件
        想直接在Uri的person后面在加上一个id作为新的path
        例如content://com.example.provider/person/10查person表中id为10 的元素
        如何知道匹配uri后面加上person同时又跟上了id?--->matcher.addURI("","person/#",2);
        方法:addURI()的第二个参数写成person/#
        如何得到id ?--->>long id = ContentUris.parseId(uri);
        得到id之后?在本方法中将case 2方法写在case 0之前,不加break,将selection 改为selection ="id="+id;
        之后顺序执行,便可以返回一个Cursor对象
        问题又来了,我们在最开始查balance>?时,外部程序写的是:
         Cursor c = resolver.query("person",null,"balance>?",new String[]{5000+""},"balance DESC");
        也就是说此时传入的条件selection已经不为空了,此时有两个条件 balance>?AND id=10
        所以,要先判断selection是否为空(是不是只有id等于多少这一个条件)
        selection =selection==null?"id="+id:selection +"AND id="+id
        总结:addURI(,"person/#",)-->long id =ContentUris.parseId(uri)-->selection==null?
        另外一个细节,我们一般不写case 0 ,case 1等等,可以写成
        private static final int PERSON =0;  case PERSON:....*/

        switch (matcher.match(uri)){
            case PERSON_ID:
              long id =  ContentUris.parseId(uri);
                selection =selection==null?"id="+id:selection+"AND id="+id;

            case PERSON:
                return  db.query("person",null,selection,selectionArgs,null,null,sortOrder);

            case STUDENT:
                //查学生表
                return null;
            default:
                throw new RuntimeException("URI不能识别");

        }


    }
}


三、增删改

 1.增

    在MyContentProvider中写的方法:
   
 //插入方法,需要传进来两个参数
    //db.indert会返回一个long 类型的id
    //ContentUris.withAppendedId(uri,id);
    //将得到的id和原来的uri凑在一起,返回一个uri(一个后面带有原来的path再加上)
    @Override
    public Uri insert(Uri uri, ContentValues values) {

        SQLiteDatabase db = myHelper.getWritableDatabase();
       long id=  db.insert("person","id",values);
        return ContentUris.withAppendedId(uri,id);
    }

在外部程序调用的方法:
 case R.id.insert:

                ContentValues values = new ContentValues();
                values.put("name","lee");
                values.put("balance",10000);
                uri1= resolver.insert(uri1,values);//调用DBProvider中的insert方法,插入并返回一个Uri
                Toast.makeText(MainActivity.this,uri1+"",Toast.LENGTH_LONG).show();
                break;

2.删

在MyContentProvider中写的方法:
//int类型,返回的是删除的个数,如果是带有id的id的Uri,如果删除了,返回1
    //不带id的uri,则返回实际删除了多少个
    @Override
    public int delete(Uri uri, String selection, String[] selectionArgs) {
        SQLiteDatabase db = myHelper.getWritableDatabase();
        switch (matcher.match(uri)){
            case PERSON_ID:
                long id = ContentUris.parseId(uri);
                selection = selection==null?"id="+id:selection+"AND id="+id;
            case PERSON:
                return  db.delete("person",selection,selectionArgs);
            default:
                throw new RuntimeException("Uri cannot be identified");
        }

在外部程序中调用的方法:
case R.id.delete:
                //resolver.delete返回的是删除掉的个数,删除一个返回1,没找到需要删除的返回0,删除掉用带id的uri只能删除一个,下面换一个uri
                //将path指定为person,删除大于5000的,此时便返回删除的个数

              int deletedCount=  resolver.delete(uri1,"balance >?",new String[]{5000+""});
                Toast.makeText(MainActivity.this,deletedCount+"",Toast.LENGTH_LONG).show();
                break;

3.改

在MyContentProvider中写的方法:
 //返回的是改变成功的个数
    @Override
    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
        SQLiteDatabase db =myHelper.getWritableDatabase();
        switch (matcher.match(uri)) {
            case PERSON_ID:
                long id = ContentUris.parseId(uri);
                selection = selection == null ? "id=" + id : selection + "AND id=" + id;
            case PERSON:
                return db.update("person", values, selection, selectionArgs);
            default:
                throw new RuntimeException("Uri cannot be identified");



        }
    }


在外部程序中调用的方法:
 case R.id.update:
               ContentValues values1 = new ContentValues();
                values1.put("name","lee");
                values1.put("balance",30000);

                int b = resolver.update(uri1,values1,"balance

至此增删改查全都有了,getType()和几个小细节会再稍后更
1.Type
调用getType,传入一个Uri,会返回这个uri对应的MIME类型
有固定的格式:
vnd.android.cursor.dir/vnd.authority.path(如果uri不带id只带path)
vnd.android.cursor.item/vnd.authority.path(如果uri带有id)

2.DBProvider中的onCreate()方法什么时候执行?
   第一次启东时执行,启动后常驻后台,除非杀死,否则不会再执行
3.在外部程序调用生成resolver时,该往哪里写?
 只能写在方法里,要么在MainActivit的onCreate()写一次,要么,每次在测试每个方法时都生成一次。不能在方法外部,直接写
 ContentResolver resolver = getContext().getContentResolver();
因为执行过程是:.class-->.dex---->.apk--->安装---->开启进程(开启主线程)----->创建MainActivity对象----->setContext()---->onCreate()---->getContext()
所以再方法外部写resolver会得到空指针异常

下面是全部代码:
MyContentProvider:
package com.example.administrator.sqliteexecsql;

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;
import android.provider.SyncStateContract;
import android.util.Log;

/**
 * Created by Administrator on 2015/7/24 0024.
 */
public class DBProvider extends ContentProvider{

    private static final int PERSON =0;
    private static final int STUDENT =1;
    private static final int PERSON_ID=2;

    DBOpenHelper myHelper;
    UriMatcher matcher;
    @Override
    public boolean onCreate() {
        //一些初始化的工作在这里面写
        //注意,实例化DBOpenHelper时,传递的参数为数据库的名字,不是表名
        //建表的工作在DBOpenHelper的OnCreate()方法里。
        matcher = new UriMatcher(UriMatcher.NO_MATCH);
        String authorities = "com.example.administrator.sqliteexecsql.provider";
        matcher.addURI(authorities,"person",0);
        matcher.addURI(authorities,"student",1);
        matcher.addURI(authorities,"person/#",2);
       myHelper = new DBOpenHelper(getContext(),"person.db",null,8);
        return true;
    }



    @Override
    public String getType(Uri uri) {
        return null;
    }

    //插入方法,需要传进来两个参数
    //db.indert会返回一个long 类型的id
    //ContentUris.withAppendedId(uri,id);
    //将得到的id和原来的uri凑在一起,返回一个uri(一个后面带有原来的path再加上)
    @Override
    public Uri insert(Uri uri, ContentValues values) {

        SQLiteDatabase db = myHelper.getWritableDatabase();
       long id=  db.insert("person","id",values);
        return ContentUris.withAppendedId(uri,id);
    }

    //int类型,返回的是删除的个数,如果是带有id的id的Uri,如果删除了,返回1
    //不带id的uri,则返回实际删除了多少个
    @Override
    public int delete(Uri uri, String selection, String[] selectionArgs) {
        SQLiteDatabase db = myHelper.getWritableDatabase();
        switch (matcher.match(uri)){
            case PERSON_ID:
                long id = ContentUris.parseId(uri);
                selection = selection==null?"id="+id:selection+"AND id="+id;
            case PERSON:
                return  db.delete("person",selection,selectionArgs);
            default:
                throw new RuntimeException("Uri cannot be identified");
        }



    }


    //返回的是改变成功的个数
    @Override
    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
        SQLiteDatabase db =myHelper.getWritableDatabase();
        switch (matcher.match(uri)) {
            case PERSON_ID:
                long id = ContentUris.parseId(uri);
                selection = selection == null ? "id=" + id : selection + "AND id=" + id;
            case PERSON:
                return db.update("person", values, selection, selectionArgs);
            default:
                throw new RuntimeException("Uri cannot be identified");



        }
    }

    //查询方法,需要传入uri,可以传入列名,查询条件,Where后面占位符的值,以及排序方式
    @Override
    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
        SQLiteDatabase db =myHelper.getReadableDatabase();
       // Cursor c = db.query("person",null,null,null,null,null,null); 查询所有,所有列,无条件,无排序方式等。
        //如果那边在调用Cursor query()方法时,需要有条件,则这边db.query()中需要加上相应的参数
        //例如,那边要查balance>? orderBy为  “balance DESC”,那么这边就要
      // Cursor c = db.query("person",null,selection,selectionArgs,null,null,sortOrder);
        //但是,另一个问题出现了,就是这里写死了查person表,如果数据库里有多个表,如何指定查哪张表呢?
        //在外部应用在使用本程序的数据时,查哪张表,别人可以在Uri指定path,本程序要做对应处理,如何处理?
        //分析,外部应用,指定查哪张表的uri:content://com.example.provider/person  后面的person(path)即为表名
        //我们只要在本程序中可以拿到后面的表名就可以设置逻辑判断,分析结束
        //解决方法:UriMatcher 对象的addURI("authorities",path,code)方法,给每个表一个数字编码
        //具体代码如下:
       // matcher.addURI(authorities,"person",0);
       // matcher.addURI(authorities,"student",1);
        //matcher.addURI(authorities,"person/#",2);
        //UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH);
        //authorities就写Manifest中配置的。下面两行将person表的编码设为0,student表的编码设为1

        //设完之后如何判断?matcher.match(uri),可以返回code
        //判断查哪张表的逻辑已经清晰了(UriMatcher-->matcher.addURI(,,,)-->matcher.match(uri)-->得到code)
        //现在又另外一个问题,我想查当前表的具体哪一个id,当然可以再外部程序调用时加上where条件
        //外部程序中Cursor c =resolver.query("person",null,"id=?",new String[]{"10"},null);
        //但是太麻烦。我想把id=?去掉,即selection为null,不直接写条件
        //想直接在Uri的person后面在加上一个id作为新的path
        //例如content://com.example.provider/person/10查person表中id为10 的元素
        //如何知道匹配uri后面加上person同时又跟上了id?--->matcher.addURI("","person/#",2);
        //方法:addURI()的第二个参数写成person/#
        //如何得到id ?--->>long id = ContentUris.parseId(uri);
        //得到id之后?在本方法中将case 2方法写在case 0之前,不加break,将selection 改为selection ="id="+id;
        //之后顺序执行,便可以返回一个Cursor对象
        //问题又来了,我们在最开始查balance>?时,外部程序写的是:
        // Cursor c = resolver.query("person",null,"balance>?",new String[]{5000+""},"balance DESC");
        //也就是说此时传入的条件selection已经不为空了,此时有两个条件 balance>?AND id=10
        //所以,要先判断selection是否为空(是不是只有id等于多少这一个条件)
        //selection =selection==null?"id="+id:selection +"AND id="+id
        //总结:addURI(,"person/#",)-->long id =ContentUris.parseId(uri)-->selection==null?
        //另外一个细节,我们一般不写case 0 ,case 1等等,可以写成
        //private static final int PERSON =0;  case PERSON:。。。。

        switch (matcher.match(uri)){
            case PERSON_ID:
              long id =  ContentUris.parseId(uri);
                selection =selection==null?"id="+id:selection+"AND id="+id;

            case PERSON:
                return  db.query("person",null,selection,selectionArgs,null,null,sortOrder);

            case STUDENT:
                //查学生表
                return null;
            default:
                throw new RuntimeException("URI不能识别");

        }


    }
}
外部程序调用:
package com.example.administrator.visitprovider;

import android.content.ContentResolver;
import android.content.ContentValues;
import android.database.Cursor;
import android.net.Uri;
import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;


public class MainActivity extends ActionBarActivity implements View.OnClickListener{



    private Button query;
    private Button insert;
    private Button delete;
    private Button update;
    Uri uri = Uri.parse("content://com.example.administrator.sqliteexecsql.provider/person/10");
    Uri uri1 = Uri.parse("content://com.example.administrator.sqliteexecsql.provider/person");
    ContentResolver resolver;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        resolver =getApplicationContext().getContentResolver();

        query = (Button) findViewById(R.id.query);
        insert = (Button) findViewById(R.id.insert);
        delete = (Button) findViewById(R.id.delete);
        update = (Button) findViewById(R.id.update);

        query.setOnClickListener(this);
        insert.setOnClickListener(this);
        delete.setOnClickListener(this);
        update.setOnClickListener(this);
       // resolver.insert(uri,new ContentValues());
    }

  
    //共四个按钮,分别是增删改查,访问上个程序的数据库,并且更改数据
    @Override
    public void onClick(View v) {
        switch (v.getId()){
            case R.id.query:
              
              Cursor c =  resolver.query(uri,null,"balance>?",new String[]{5000+""},"balance DESC");
                while (c.moveToNext()){
                    Person p = new Person(c.getInt(0),c.getString(1),c.getInt(2));
                    System.out.println(p.toString());
                }
                break;
            case R.id.insert:

                ContentValues values = new ContentValues();
                values.put("name","lee");
                values.put("balance",10000);
                uri1= resolver.insert(uri1,values);//调用DBProvider中的insert方法,插入并返回一个Uri
                Toast.makeText(MainActivity.this,uri1+"",Toast.LENGTH_LONG).show();
                break;
            case R.id.delete:
                //resolver.delete返回的是删除掉的个数,删除一个返回1,没找到需要删除的返回0,删除掉用带id的uri只能删除一个,下面换一个uri
                //将path指定为person,删除大于5000的,此时便返回删除的个数

              int deletedCount=  resolver.delete(uri1,"balance >?",new String[]{5000+""});
                Toast.makeText(MainActivity.this,deletedCount+"",Toast.LENGTH_LONG).show();
                break;
            case R.id.update:
               ContentValues values1 = new ContentValues();
                values1.put("name","lee");
                values1.put("balance",30000);

                int b = resolver.update(uri1,values1,"balance


你可能感兴趣的:(Android,基础)