ContentProvider提供的对数据库批量操作的方法和对数据库变化监控的方法
来源:互联网 发布:sql update 更新多行 编辑:程序博客网 时间:2024/05/16 10:43
最近项目中用到了数据批量入库和监控数据库变化的需求,整理总结如下:
1.批量操作数据库的方法
1)ContentProvider中提供了批量处理数据的方法applyBatch,Android源码在ContentProvider.java中实现如下:
@Override public ContentProviderResult[] applyBatch(String callingPkg, ArrayList<ContentProviderOperation> operations) throws OperationApplicationException { int numOperations = operations.size(); final int[] userIds = new int[numOperations]; for (int i = 0; i < numOperations; i++) { ContentProviderOperation operation = operations.get(i); Uri uri = operation.getUri(); validateIncomingUri(uri); userIds[i] = getUserIdFromUri(uri); if (userIds[i] != UserHandle.USER_CURRENT) { // Removing the user id from the uri. operation = new ContentProviderOperation(operation, true); operations.set(i, operation); } if (operation.isReadOperation()) { if (enforceReadPermission(callingPkg, uri, null) != AppOpsManager.MODE_ALLOWED) { throw new OperationApplicationException("App op not allowed", 0); } } if (operation.isWriteOperation()) { if (enforceWritePermission(callingPkg, uri, null) != AppOpsManager.MODE_ALLOWED) { throw new OperationApplicationException("App op not allowed", 0); } } } final String original = setCallingPackage(callingPkg); try {//<span style="font-family: Arial, Helvetica, sans-serif;">ContentProvider</span><span style="font-family: 宋体;">不同的子对象类型的方法调用是在这里进行分发的</span> <span style="color:#3333ff;">ContentProviderResult[] results = ContentProvider.this.applyBatch(operations);</span> if (results != null) { for (int i = 0; i < results.length ; i++) { if (userIds[i] != UserHandle.USER_CURRENT) { // Adding the userId to the uri. results[i] = new ContentProviderResult(results[i], userIds[i]); } } } return results; } finally { setCallingPackage(original); } }
那么,如何使用该方法呢?我们仍然以Android源码中对通讯录的操作为例来讲。
应用端使用ContentProvider提供的applyBatch来进行批量处理,那么applyBatch是怎么使用的呢?以通讯录中联系人批量入库为例(下面这段代码是在自己项目中使用时从网上一位仁兄那里看到的,结果上来就能用上):
public static void batchInsertContacts(Context context, List<Contact> contactList) throws RemoteException, OperationApplicationException { ArrayList<ContentProviderOperation> ops = new ArrayList<>(); int rawContactInsertIndex = 0; for (Contact contact : contactList) { rawContactInsertIndex = ops.size(); // 有了它才能给真正的实现批量添加 ops.add(ContentProviderOperation.newInsert(ContactsContract.RawContacts.CONTENT_URI) .withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, null) .withValue(ContactsContract.RawContacts.ACCOUNT_NAME, null) .withYieldAllowed(true).build()); // 添加姓名 ops.add(ContentProviderOperation .newInsert( android.provider.ContactsContract.Data.CONTENT_URI) .withValueBackReference(ContactsContract.Contacts.Data.RAW_CONTACT_ID, rawContactInsertIndex) .withValue(ContactsContract.Contacts.Data.MIMETYPE, ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE) .withValue(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, contact.getName()) .withYieldAllowed(true).build()); // 添加号码 ops.add(ContentProviderOperation .newInsert( android.provider.ContactsContract.Data.CONTENT_URI) .withValueBackReference(ContactsContract.Contacts.Data.RAW_CONTACT_ID, rawContactInsertIndex) .withValue(ContactsContract.Contacts.Data.MIMETYPE, ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE) .withValue(ContactsContract.CommonDataKinds.Phone.NUMBER, contact.getPhone()) .withValue(ContactsContract.CommonDataKinds.Phone.TYPE, ContactsContract.CommonDataKinds.Phone.TYPE_MOBILE) .withValue(ContactsContract.CommonDataKinds.Phone.LABEL, "").withYieldAllowed(true).build()); } //这里调用了applyBatch,是真正批量入库所在 context.getContentResolver() .applyBatch(ContactsContract.AUTHORITY, ops);}
2)那么在这里调用了applyBatch之后的代码流程究竟是怎样的呢?
下面是我打印的一段代码调用栈:
I/ContactsProvider( 2736): java.lang.RuntimeException: startTransactionI/ContactsProvider( 2736): at com.android.providers.contacts.AbstractContactsProvider.startTransaction(AbstractContactsProvider.java:254)I/ContactsProvider( 2736): at com.android.providers.contacts.AbstractContactsProvider.insert(AbstractContactsProvider.java:134)I/ContactsProvider( 2736): at com.android.providers.contacts.ContactsProvider2.insert(ContactsProvider2.java:2166)I/ContactsProvider( 2736): at android.content.<span style="color:#3333ff;">ContentProviderOperation.apply</span>(ContentProviderOperation.java:240)//这里判断具体的操作类型TYPE_INSERT、TYPE_DELETE、TYPE_UPDATE、TYPE_ASSERTI/ContactsProvider( 2736): at com.android.providers.contacts.AbstractContactsProvider.applyBatch(AbstractContactsProvider.java:237)I/ContactsProvider( 2736): at com.android.providers.contacts.<span style="color:#6633ff;">ContactsProvider2.applyBatch</span>(ContactsProvider2.java:2321)I/ContactsProvider( 2736): at android.content.ContentProvider$Transport.applyBatch(ContentProvider.java:288)//首先调用到ContentProvider中的applyBatch,然后根据子类对象类型进行分发,在这里因为是Contacts所以会分发到ContactsProvider2中去I/ContactsProvider( 2736): at android.content.ContentProviderNative.onTransact(ContentProviderNative.java:192)I/ContactsProvider( 2736): at android.os.Binder.execTransact(Binder.java:446)结合源码分析上边调用栈中的类,会发现原来AbstractContactsProvider类继承了ContentProvider,而ContactsProvider2继承了AbstractContactsProvider,在ContactsProvider2中的applyBatch调用了其父类的applyBatch。然后根据ContentProviderOperation.apply来判断其操作类型为insert,接着调用了AbstractContactsProvider中的insert方法,从而实现了通讯录的批量入库操作。
3)从上边通讯录入库的流程,我们可以总结出具体业务实现批量入库的方法。其实很简单,只要在对应的业务类中继承ContentProvider并实现applyBatch方法就可以了。当然也得有自己操作数据库的insert、delete、update方法的实现。
2.监控数据库的方法
ContentProvider提供了ContentObserver这么一个抽象类来帮助我们监控数据库的变化。使用该类的地方只需要继承该类来操作就可以了。
以Android源码中CallLogFragment中的代码为例说明使用方法:
1)继承ContentObserver来创建类,这种类一般都是私有的,因为它只在本地使用,属于类中定义的类
private class CustomContentObserver extends ContentObserver {//该类继承了ContentObserver public CustomContentObserver() { super(mHandler); } @Override public void onChange(boolean selfChange) {//onChange方法被调用,说明监控的数据库发生了变化,是我们可以进行具体业务处理的地方 mRefreshDataRequired = true; } }
2)用新定义的类来创建一个对象
private final ContentObserver mCallLogObserver = new CustomContentObserver();//这个是定义的监控对象,用它来监控数据库变化
3)注册该对象监控的URI
@Override public void onCreate(Bundle state) { super.onCreate(state);....................... getActivity().getContentResolver().registerContentObserver(CallLog.CONTENT_URI, true, mCallLogObserver);//第一个参数是要监控的数据库表的URI也就是被监控对象;第二个参数设置为true,如果注册监听的URI为content://111,那么URI为content://111/222的数据改变也会触发该监听器;第三个参数是我们上边创建的监听器
4)进行去注册操作
@Override public void onDestroy() { super.onDestroy(); ............................ getActivity().getContentResolver().unregisterContentObserver(mCallLogObserver);//程序结束的时候一定要进行去注册监听器 }
5)实际上经过上边的注册流程之后,只要监听的数据库发生了变化,上边实现的onChange都能监控到。这是因为,只要数据发生变化,ContentResolver中的notifyChange就会被调用
public void notifyChange(Uri uri, ContentObserver observer) { notifyChange(uri, observer, true /* sync to network */); }
监控具体数据库变化的完整流程就是这样。
- ContentProvider提供的对数据库批量操作的方法和对数据库变化监控的方法
- Hibernate提供的类和方法对数据库查询
- ibatis对MySQL数据库的批量操作
- SSH之继承HibernateDaoSupport对数据库的操作和不继承HibernateDaoSupport对数据库的操作的方法
- Hibernate提供的操作数据库的方法使用和比较
- Hibernate提供的操作数据库的方法使用和比较
- 对数据库的操作
- ibatis对oracle数据库的批量更新和批量插入的操作
- ibatis对oracle数据库的批量更新和批量插入的操作
- 对数据库的操作(代码风格及方法)
- 用JavaScript对MySQL数据库进行操作的方法
- spring对数据库的简单操作及方法
- 通过pdo的query()方法对数据库进行操作
- SSM之Mybatis对数据库的查询以及批量操作
- JAVA对MYSQL数据库进行批量操作,addBatch(),executeBatch()方法
- JAVA对MYSQL数据库进行批量操作,addBatch(),executeBatch()方法
- Java对各种数据库的链接方法
- Nagios监控数据库的方法
- wget 网页爬虫,网页抓取工具
- GitHub Tips (很实用,值得收藏)
- altium designer 制作元器件封装库
- matlab AHP层次分析法求权重
- delphi 控件大全(确实很全)
- ContentProvider提供的对数据库批量操作的方法和对数据库变化监控的方法
- Qt学习之十四:event() 与eventFilter()
- Longest Substring with At Least K Repeating Characters
- 关于KVM中处理外部中断的处理代码
- Angular2学习指南
- 关于NVDIMM和测试模块的内核编译
- GHost win7(2016.05)版本安装后,清除流氓软件的过程
- 公有云通用管理接口 Cloud Infrastructure Common Management Interface - CICMI
- 小白日记10:kali渗透测试之端口扫描-UDP、TCP、僵尸扫描、隐蔽扫描