生成Content Provider
BDFlow甚至可以很简单地生成Content Provider
。
开始
此功能主要使用了schematic库。
ContentProvider描述类
为了生成一个ContentProvider
,我们首先需要定义一个描述类:
@ContentProvider(authority = TestContentProvider.AUTHORITY,
database = TestDatabase.class,
baseContentUri = TestContentProvider.BASE_CONTENT_URI)
public class TestContentProvider {
public static final String AUTHORITY = "com.raizlabs.android.dbflow.test.provider";
public static final String BASE_CONTENT_URI = "content://";
}
当然你也可以在任何类上通过注解将其定义为ContentProvider的描述类。推荐的一个写法就是将@Database
描述类同时作为@ContentProvider
的描述类。它们同时注解于同一个类上是完全没问题的:
@ContentProvider(authority = TestDatabase.AUTHORITY,
database = TestDatabase.class,
baseContentUri = TestDatabase.BASE_CONTENT_URI)
@Database(name = TestDatabase.NAME, version = TestDatabase.VERSION)
public class TestDatabase {
public static final String NAME = "TestDatabase";
public static final int VERSION = "1";
public static final String AUTHORITY = "com.raizlabs.android.dbflow.test.provider";
public static final String BASE_CONTENT_URI = "content://";
}
添加到Manifest中
ContentProvider将会被生成为类名$Provider
,在使用ContentProvider的其他App或本App中我们需要在AndroidManifest.xml
文件中声明:
<provider
android:authorities="com.raizlabs.android.dbflow.test.provider"
android:exported="true|false"
android:name=".provider.TestContentProvider$Provider"/>
android:exported
:设定改服务是否可以跨进程(App)使用,为true时其他应用才可以使用此服务。
注意,你必须有至少一个@TableEndpoint
以确保它能通过编译检测
对数据添加Endpoints
有两种方式定义@TableEndpoint
:
- 在
@ContentProvider
描述类中创建一个内部类。 - 在
@Table
类中指定content provider的类名
@TableEndpoint
:将ContentProvider
中的检索、删除和更新的操作映射到本地数据库。
一些建议:
- 如果使用
@ContentProvider
内部类作为@TableEndpoint
,其类名最好与被引用的表同名。 - 创建一个
public static final String ENDPOINT = "{tableName}"
属性,使之可以在其他地方被引用。 - 创建一个
buildUri()
方法(如下),方便创建URI
示例:
@TableEndpoint(ContentProviderModel.ENDPOINT)
public static class ContentProviderModel {
public static final String ENDPOINT = "ContentProviderModel";
private static Uri buildUri(String... paths) {
Uri.Builder builder = Uri.parse(BASE_CONTENT_URI + AUTHORITY).buildUpon();
for (String path : paths) {
builder.appendPath(path);
}
return builder.build();
}
@ContentUri(path = ContentProviderModel.ENDPOINT,
type = ContentUri.ContentType.VND_MULTIPLE + ENDPOINT)
public static Uri CONTENT_URI = buildUri(ENDPOINT);
}
或者对已有的数据表进行设置:
@TableEndpoint(name = ContentProviderModel.NAME, contentProviderName = "ContentDatabase")
@Table(database = ContentDatabase.class, tableName = ContentProviderModel.NAME)
public class ContentProviderModel extends BaseProviderModel<ContentProviderModel> {
public static final String NAME = "ContentProviderModel";
@ContentUri(path = NAME, type = ContentUri.ContentType.VND_MULTIPLE + NAME)
public static final Uri CONTENT_URI = ContentUtils.buildUri(ContentDatabase.AUTHORITY);
@Column
@PrimaryKey(autoincrement = true)
long id;
@Column
String notes;
@Column
String title;
@Override
public Uri getDeleteUri() {
return TestContentProvider.ContentProviderModel.CONTENT_URI;
}
@Override
public Uri getInsertUri() {
return TestContentProvider.ContentProviderModel.CONTENT_URI;
}
@Override
public Uri getUpdateUri() {
return TestContentProvider.ContentProviderModel.CONTENT_URI;
}
@Override
public Uri getQueryUri() {
return TestContentProvider.ContentProviderModel.CONTENT_URI;
}
}
之后的章节会更详细地介绍@ContentUri
的使用方法。
更方便地创建ContentProvider
这里还有两种更方便的方式将你的Model
改为支持ContentProvider,只需要继承下面两个类即可:
BaseProviderModel
: 重写了Model
中的所有方法使之可以用于ContentProvider
BaseSyncableProviderModel
:与上面相同,但它将会把数据的更新与本地的数据更新及时同步。
使用Content Provider
你可以通过ContentUtils
方便地使用ContentProvider
:
ContentProviderModel contentProviderModel = ...; // some instance
int count = ContentUtils.update(getContentResolver(), ContentProviderModel.CONTENT_URI, contentProviderModel);
Uri uri = ContentUtils.insert(getContentResolver(), ContentProviderModel.CONTENT_URI, contentProviderModel);
int count = ContentUtils.delete(getContentResolver(), someContentUri, contentProviderModel);
推荐:通过继承BaseSyncableProviderModel
来使本地数据库保持一致,除非使用BaseProviderModel
就足够了。
MyModel model = new MyModel();
model.id = 5;
model.load(); // queries the content provider
model.someProp = "Hello"
model.update(false); // runs an update on the CP
model.insert(false); // inserts the data into the CP
高级用法
通知方法
你可以通过定义@Notify
方法监听ContentProvider
中指定的操作,并通过返回Uri[]
来通知相应的ContentResolver
。
支持监听:
- Update
- Insert
- Delete
Example:
@Notify(method = Notify.Method.UPDATE,
paths = {}) // specify paths that will call this method when specified.
public static Uri[] onUpdate(Context context, Uri uri) {
return new Uri[] {
// return custom uris here
};
}
高级ContentUri
Path Segments
通过#
符号,你可以定义高级path
匹配:
path:
path = "Friends/#/#"
segments:
segments = {@PathSegment(segment = 1, column = "id"),
@PathSegment(segment = 2, column = "name")}
组合起来:
@ContentUri(type = ContentType.VND_MULTIPLE,
path = "Friends/#/#",
segments = {@PathSegment(segment = 1, column = "id"),
@PathSegment(segment = 2, column = "name")})
public static Uri withIdAndName(int id, String name) {
return buildUri(id, name);
}