【Android】学习ContentProvider和ContentResolver,写个CRUD案例

前言

  • 学到了contentProvider,记录一下学到的知识,写一个CRUD的案例
  • 案例内容(Provider负责CRUD的持久层操作,Resolver对Provider返回的Uri或者Cursor数据进行解析

1.Provider的代码逻辑

(1)创建数据库连接DBHelper类

  • 使用到了SQLite,因此需要继承SQLiteOpenHelper
  • 构造函数中,删除多余的传参,自己手动传一个表名,factory=null,version=1
  • 然后再DBHelper启动的时候,onCreate中执行两段sql语句,建立person表,并先插入一条记录。
public class DBHelper extends SQLiteOpenHelper {
    private static final String TAG = "DBHelper";

    public DBHelper(@Nullable Context context) {
        super(context, "wang.db", null, 1);
    }

    @Override
    public void onCreate(SQLiteDatabase sqLiteDatabase) {
        Log.e(TAG, "onCreate()");
        //建表
        sqLiteDatabase.execSQL("create table person(_id integer primary key autoincrement, name varchar)");
        //插入初始化数据
        sqLiteDatabase.execSQL("insert into person (name) values ('Tom')");

    }

    @Override
    public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {

    }
}

(2)创建一个自定义的Provider类

  • 需要继承ContentProvider类,并重写其方法,方法中包括增删改查等方法。
  • Provider并不需要和任何视图进行绑定。
  • 记得在清单中对这个Provider进行注册!注册的时候需要写上intent-filter,因为需要别的app调用
  • 下面代码我尽量注释地详细点。
/**
 * 操作Person的provider
 */
public class PersonProvider extends ContentProvider {
    //存放合法URI的容器,构造函数㤇传一个默认值,也就是不匹配的值-1
    private static UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH);
    //引入DBHelper
    private DBHelper dbHelper;

	//matcher是一个Uri的容器,我们需要先对其添加一些URI规则,
	//在后面的时候才可以对传来的URI根据matcher中的URI规则进行判断,如下,不带参数的为1,带参数的为2,
	//写在静态代码块中,以便一开始matcher就有这些规则
    static {
        matcher.addURI("com.wang.ch07_provider.personprovider", "/person", 1);
        matcher.addURI("com.wang.ch07_provider.personprovider", "/person/#", 2);//#匹配任意的数字
    }

	//log的打印TAG
    private static final String TAG = "PersonProvider";

    public PersonProvider() {
        Log.e(TAG, "PersonProvider()");
    }

    @Override
    public boolean onCreate() {
        Log.e(TAG, "onCreate()");
        //PersonProvider创建的时候回调onCreate方法就会赋值一个DBHelper给这里的成员变量。
        //方便之后获取数据库连接
        dbHelper = new DBHelper(getContext());
        return false;
    }

    /**
     * 查询包括根据id和不根据id查询
     * 还需要判断URI是否合法,也就是在不在Matcher中需要判断
     */
    @Nullable
    @Override
    public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection,
                        @Nullable String[] selectionArgs,
                        @Nullable String sortOrder) {
        Log.e(TAG, "query()");
        //1.匹配URI,返回code,如果合法那么进行查询,不合法抛出异常
        int code = matcher.match(uri);
        //得到数据库连接对象
        SQLiteDatabase database = dbHelper.getReadableDatabase();
        if (code == 1) {
            //不根据ID查询
            Cursor cursor = database.query("person", projection, selection, selectionArgs,
                    null, null, null);
            return cursor;
        } else if (code == 2) {
            //根据ID进行查询
            long id = ContentUris.parseId(uri);
            Cursor cursor = database.query("person", projection, "_id=?",
                    new String[]{id + ""}, null, null, null);
            return cursor;
        } else {
            throw new RuntimeException("查询URI不合法");
        }
    }

    @Nullable
    @Override
    public Uri insert(@NonNull Uri uri, @Nullable ContentValues contentValues) {
        Log.d(TAG, "insert()");
        //首先匹配Uri,通过code判断是哪种操作
        int code = matcher.match(uri);
        SQLiteDatabase database = dbHelper.getReadableDatabase();
        //插入不可以带id参数。。因此不存在code==2,只有code==1合法
        if (code == 1) {
            long id = database.insert("person", null, contentValues);
            //这里因为返回的是Uri,因此可以将数据库连接关闭
            database.close();
            //需要将这个id添加到Uri中,使用工具类
            return ContentUris.withAppendedId(uri, id);
        } else {
            database.close();
            throw new RuntimeException("插入URI不合法");
        }
    }

    @Override
    public int delete(@NonNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs) {
        Log.d(TAG, "delete()");
        int code = matcher.match(uri);
        SQLiteDatabase database = dbHelper.getReadableDatabase();
        int deleteCount = -1;
        if (code == 1) {
            deleteCount = database.delete("person", selection, selectionArgs);
        } else if (code == 2) {
            deleteCount = database.delete("person", "_id=?", new String[]{ContentUris.parseId(uri) + ""});
        } else {
            database.close();
            throw new RuntimeException("delete Uri 非法");
        }
        database.close();
        return deleteCount;
    }

    @Override
    public int update(@NonNull Uri uri, @Nullable ContentValues contentValues, @Nullable String selection, @Nullable String[] selectionArgs) {
        Log.d(TAG, "update()");
        int code = matcher.match(uri);
        int updateCount = -1;
        SQLiteDatabase database = dbHelper.getReadableDatabase();
        if (code == 1) {
            //如果不根据id进行更新就是将所有的记录进行更新
            updateCount = database.update("person", contentValues, selection, selectionArgs);
        } else if (code == 2) {
            updateCount = database.update("person", contentValues, "_id=?", new String[]{ContentUris.parseId(uri) + ""});
        } else {
            database.close();
            throw new RuntimeException("update Uri 非法");
        }
        database.close();
        return updateCount;
    }

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

(3)在清单中注册该PersonProvider

  • name就取全限定名称就好,具有唯一性
  • authorities就取全限定名称的全小写
  • exported为true,意味着别的app可以调用该provider
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.wang.ch07_provider">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.Provider">
        <activity
            android:name=".MainActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <provider
            android:name="com.wang.ch07_provider.PersonProvider"
            android:authorities="com.wang.ch07_provider.personprovider"
            android:exported="true" />
    </application>

</manifest>

2.Resolver的代码逻辑

(1)界面布局xml

  • 来四个键就好,每个键都有一个onClick绑定的事件方法在MainActivity中进行监听。
<?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="vertical">

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:onClick="insert"
        android:text="Insert" />

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:onClick="update"
        android:text="Update" />

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:onClick="delete"
        android:text="Delete" />

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:onClick="query"
        android:text="Query" />

</LinearLayout>
  • 长这样
    在这里插入图片描述

(2)MainActivity代码逻辑

  • 首先在onCreate中加载布局
  • 其次每个监听方法中的逻辑基本上一致:(1)获取resolver;(2)使用resolver,通过Uri和其他参数,来调用对应Provider中的对应方法,并处理返回的Uri或者数据库Cursor。
public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    public void insert(View view) {
        //1.得到contentResolver对象
        ContentResolver resolver = getContentResolver();
        Uri uri = Uri.parse("content://com.wang.ch07_provider.personprovider/person/");
        ContentValues contentValues = new ContentValues();
        contentValues.put("name", "wang");
        Uri insertUri = resolver.insert(uri, contentValues);
        Toast.makeText(this, "添加学生1,姓名为:" + contentValues.get("name") +
                "\n返回的uri为:" + insertUri.toString(), Toast.LENGTH_SHORT).show();

    }

    public void update(View view) {
        //1.获取contentResolver
        ContentResolver resolver = getContentResolver();
        Uri uri = Uri.parse("content://com.wang.ch07_provider.personprovider/person/1");
        ContentValues contentValues = new ContentValues();
        contentValues.put("name", "update-Tom");
        int updateRow = resolver.update(uri, contentValues, null, null);
        Toast.makeText(this, "update row = " + updateRow, Toast.LENGTH_SHORT).show();
    }

    public void delete(View view) {
        //1.获取
        ContentResolver resolver = getContentResolver();
        //删除id为2的学生
        Uri uri = Uri.parse("content://com.wang.ch07_provider.personprovider/person/2");
        int deleteRow = resolver.delete(uri, null, null);
        Toast.makeText(this, "update row = " + deleteRow, Toast.LENGTH_SHORT).show();
    }

    public void query(View view) {
        //1.得到contentResolver对象
        ContentResolver resolver = getContentResolver();
        //2.执行contentResolver对象,调用query方法得到cursor
        Uri uri = Uri.parse("content://com.wang.ch07_provider.personprovider/person/1");//根据id查询
        //下面query参数含义,uri,查询那些字段,条件字段,条件字段的参数..
        Cursor cursor = resolver.query(uri, null, null, null, null);
        //3.取出cursor中的数据,并显示
        if (cursor.moveToNext()) {
            int id = cursor.getInt(0);
            String name = cursor.getString(1);
            Toast.makeText(this, "学生id为:" + id + "\n学生姓名为:" + name, Toast.LENGTH_SHORT).show();
        }
    }
}

完成

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值