前言
- 学到了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();
}
}
}
完成