如果我的“联系人”中有任何更新,我该如何更新本地SQLite数据库

时间:2016-04-07 05:30:40

标签: android sqlite contentobserver

我正在创建一个Android应用程序,我有一个本地SQLite数据库来存储从联系人列表中选择的用户详细信息。我想在手机通讯录中有任何更新时更新我的​​SQLite数据库。我使用了内容观察器,但由于我是Android开发的新手,任何人都可以帮助我使用ContentObserver以及我可以遵循的方法来更新我的本地数据库。

1 个答案:

答案 0 :(得分:2)

ContentObserver是一个没有抽象方法的抽象类。它的两个onChange()方法在没有任何逻辑的情况下实现。而且,每当发生变化时都会调用它们,你必须覆盖它们。

由于Google最近添加了两个重载的onChange()方法中的一个,就像API级别16一样,此方法的默认行为是调用另一个较旧的方法。

这是正常实现的样子:

class MyObserver extends ContentObserver {
 public MyObserver(Handler handler) {
  super(handler);
}

 @Override
 public void onChange(boolean selfChange) {
  this.onChange(selfChange, null);
 }      

  @Override
  public void onChange(boolean selfChange, Uri uri) {
  // do s.th.
  // depending on the handler you might be on the UI
  // thread, so be cautious!
 }
}

上述代码有些重要。您必须知道的第一件事是,第二种方法仅适用于API级别16以上。这就是我添加SuppressLint注释的原因。代码在旧设备上运行良好,但在这种情况下,Android显然总是调用旧代码。因此,您的代码不应该依赖URI才能正常工作。

还要注意构造函数中的Handler参数。此处理程序用于提供onChange()方法。因此,如果您在UI线程上创建了Handler,那么也将在UI线程上调用onChange()方法。在这种情况下,请避免在此方法中查询ContentProvider。而是使用AsyncTask或Loader。

如果将null值传递给构造函数,Android会立即调用onChange()方法 - 无论当前使用的线程如何。我认为最好在创建ContentObserver对象时始终使用处理程序。

注册您的内容观察者以收听更改

要注册ContentObserver子类,您只需调用ContentResolver的registerContentObserver()方法:

getContentResolver().registerContentObserver(SOME_URI,true,yourObserver);

需要三个参数。第一个是要收听的URI。我将在下一节中更详细地介绍URI。

第二个参数指示对以给定URI开头的URI的所有更改是应该触发方法调用还是仅更改为这一个URI。这对于说明具有许多后代的ContactsContract URI来说非常方便。但它也可能是有害的,因为导致方法调用的实际变化对你来说更加模糊。

第三个参数是ContentObserver实现的实例。

您可以观察的URI

正如我对内容提供者的介绍所述,内容URI可以是基于目录的,也可以是基于身份的。

这两种URI类型都可以用于您的内容观察者。如果你有一个详细信息屏幕,你将为观察者使用基于id的URI,当你使用数据列表时,基于目录的URI更合适。

但这并不总是有效。例如,即使您正在侦听更具体的URI,ContactsContract也会在更改任何联系人时始终触发更改。这取决于内容提供商的正确实施。我已经为ContactsContract提供商提交了错误报告。如果您同意,请投票支持此问题。

为应用编写内容提供商时,请注意通知正确的URI。只有这样,这里描述的反馈机制才有效。这对您的观察者来说非常重要 - 或者如果提供者也是为您的客户的观察者导出的。这对装载机也很重要。请参阅我的帖子,了解如何编写内容提供商以了解有关此内容的更多信息。

注意:如果您使用装载程序,则无需自行收听更改。在这种情况下,Android注册ContentObserver并触发您的LoaderCallbacks onLoadFinished()方法以进行任何更改。

不要忘记取消注册您的内容观察者

当您注册了内容观察者时,您还有责任取消注册。否则你会创建一个内存泄漏,你的Activity永远不会被垃圾收集。

要取消注册,请调用ContentResolver的unregisterContentObserver()方法:

getContentResolver().
  unregisterContentObserver(yourObserver);