ITKeyword,专注技术干货聚合推荐

注册 | 登录

android - CursorLoader usage without ContentProvider

itPublisher 分享于

2021腾讯云限时秒杀,爆款1核2G云服务器298元/3年!(领取2860元代金券),
地址https://cloud.tencent.com/act/cps/redirect?redirect=1062

2021阿里云最低价产品入口+领取代金券(老用户3折起),
入口地址https://www.aliyun.com/minisite/goods

推荐:深入源码解析Android中Loader、AsyncTaskLoader、CursorLoader、LoaderManager

如果对Loader、AsyncTaskLoader、CursorLoader、LoaderManager等概念不明白或不知道如何使用Loader机制,可参见博文Android中Loader及LoaderManager的使用(附源

up vote 104 down vote favorite 99 Android SDK documentation says that startManagingCursor() method is depracated: This method is deprecated. Use the new CursorLoader class with LoaderManager instead; this is also available on older platforms through the Android compatibility package. This method allows the activity to take care of managing the given Cursor's lifecycle for you based on the activity's lifecycle. That is, when the activity is stopped it will automatically call deactivate() on the given Cursor, and when it is later restarted it will call requery() for you. When the activity is destroyed, all managed Cursors will be closed automatically. If you are targeting HONEYCOMB or later, consider instead using LoaderManager instead, available via getLoaderManager() So I would like to use CursorLoader. But how can I use it with custom CursorAdapter and without ContentProvider, when I needs URI in constructor of CursorLoader? android cursor android-cursorloader android-loadermanager android-contentprovider
  |
  this question edited Jun 24 '16 at 7:42 asked Aug 24 '11 at 21:26 sealskej 3,818 9 41 59      @Alex Lockwood why we are using CursorAdapter without ContentProvider please suggest me stackoverflow.com/questions/20419278/… –  user2567369 Dec 6 '13 at 8:59      why we are using CursorAdapter without ContentProvider please suggest me stackoverflow.com/questions/20419278/… –  user2567369 Dec 6 '13 at 8:59



 |  5 Answers

up vote 152 down vote ---Accepted---Accepted---Accepted---

I wrote a simple CursorLoader that does not need a content provider: import android.content.Context;

import android.database.Cursor;

import android.support.v4.content.AsyncTaskLoader;

/**

* Used to write apps that run on platforms prior to Android 3.0. When running

* on Android 3.0 or above, this implementation is still used; it does not try

* to switch to the framework's implementation. See the framework SDK

* documentation for a class overview.

*

* This was based on the CursorLoader class

*/

public abstract class SimpleCursorLoader extends AsyncTaskLoader<Cursor> {

private Cursor mCursor;

public SimpleCursorLoader(Context context) {

super(context);

}

/* Runs on a worker thread */

@Override

public abstract Cursor loadInBackground();

/* Runs on the UI thread */

@Override

public void deliverResult(Cursor cursor) {

if (isReset()) {

// An async query came in while the loader is stopped

if (cursor != null) {

cursor.close();

}

return;

}

Cursor oldCursor = mCursor;

mCursor = cursor;

if (isStarted()) {

super.deliverResult(cursor);

}

if (oldCursor != null && oldCursor != cursor && !oldCursor.isClosed()) {

oldCursor.close();

}

}

/**

* Starts an asynchronous load of the contacts list data. When the result is ready the callbacks

* will be called on the UI thread. If a previous load has been completed and is still valid

* the result may be passed to the callbacks immediately.

* <p/>

* Must be called from the UI thread

*/

@Override

protected void onStartLoading() {

if (mCursor != null) {

deliverResult(mCursor);

}

if (takeContentChanged() || mCursor == null) {

forceLoad();

}

}

/**

* Must be called from the UI thread

*/

@Override

protected void onStopLoading() {

// Attempt to cancel the current load task if possible.

cancelLoad();

}

@Override

public void onCanceled(Cursor cursor) {

if (cursor != null && !cursor.isClosed()) {

cursor.close();

}

}

@Override

protected void onReset() {

super.onReset();

// Ensure the loader is stopped

onStopLoading();

if (mCursor != null && !mCursor.isClosed()) {

mCursor.close();

}

mCursor = null;

}

}

It only needs the AsyncTaskLoader class. Either the one in Android 3.0 or higher, or the one that comes with the compatibility package. I also wrote a ListLoader which is compatible with the LoadManager and is used to retrieve a generic java.util.List collection.
  |
  this answer edited Sep 22 '13 at 18:38 answered Sep 14 '11 at 20:07 Cristian 149k 48 313 247 13   Found a nice code example that uses this - bitbucket.org/ssutee/418496_mobileapp/src/fc5ee705a2fd/demo/‌​… - found it very useful ! –  Shushu May 20 '12 at 21:17      @Cristian Thanks for the example. What is the license associated with your class. How can it be reused? –  codinguser May 26 '12 at 9:37 2   License is Apache 2.0; you can reuse it where/when ever you want. Let me know if you have any
 ments. –  Cristian May 26 '12 at 15:35 14   Great stuff! Users should be aware of one limitation, which is that it has no mechanism to refresh on data changes (as Loaders are supposed to do) –  emmby Jun 21 '12 at 21:44 1   @Jadeye here you have man: ListLoader and SupportListLoader –  Cristian Sep 22 '13 at 18:37  |  show 4 more comments up vote 22 down vote Write your own loader that uses your database class instead of a content provider. The easiest way is just to take the source of the CursorLoader class from the compatibility library, and replace provider queries with queries to your own db helper class.
  |
  this answer answered Aug 25 '11 at 2:54 Nikolay Elenkov 44k 6 68 73 2

推荐:Android 的 ContentProvider

开发自己应用的ContentProvider(ContentProvider是个抽象类,继承时,必须实现抽象方法) 1构造CONTENT_URI CONTENT_URI="content://" + AUTHORITY + "/diaries

  +1 for resourcefulness :) –  Alex Gittemeier Jan 21 '13 at 19:55 1   This is is the easiest way in my opinion. In my app I created a CursorLoader descendat to manage a SQLite cursor, appart from the constructor I only needed to override the loadInBackground method to replace the provider query with my cursor query –  Jose_GD Oct 2 '14 at 23:11

 |  up vote 14 down vote The SimpleCursorLoader is a simple solution, however it doesn't support updating the loader when the data changes. CommonsWare has a loaderex library that adds a SQLiteCursorLoader and supports re-query on data changes. https://github.com/commonsguy/cwac-loaderex
  |
  this answer answered Jun 22 '12 at 17:58 emmby 57.1k 50 151 210 2   However, to make use of the automatic re-querying, you need to use the same loader for the UI as well as for the updates, limiting its usability for background services. –  ge0rg Oct 8 '12 at 15:29

 |  up vote 12 down vote A third option would be to simply override loadInBackground: public class CustomCursorLoader extends CursorLoader {

private final ForceLoadContentObserver mObserver = new ForceLoadContentObserver();

@Override

public Cursor loadInBackground() {

Cursor cursor = ... // get your cursor from wherever you like

if (cursor != null) {

// Ensure the cursor window is filled

cursor.getCount();

cursor.registerContentObserver(mObserver);

}

return cursor;

}

};

This will also take care of re-querying your cursor when the database changes. Only caveat: You'll have to define another observer, since Google in it's infinite wisdom decided to make theirs package private. If you put the class into the same package as the original one (or the compat one) you can actually use the original observer. The observer is a very lightweight object and isn't used anywhere else, so this doesn't make much of a difference.
  |
  this answer edited Jun 28 '12 at 18:24 answered Jun 28 '12 at 17:16 Timo Ohr 7,479 2 22 18      My observation in quick testing is that registerContentObserver will only be called against the cursor if the cursor is targeted to a Content Provider. Can you confirm/deny this? –  Nick Campion Dec 19 '12 at 3:35 1   It doesn't necessarily have to be a ContentProvider. But the cursor needs to be registered to a notification uri (setNotificationUri), and it then needs to be notified by someone (usually a ContentProvider, but can be anything) by calling ContentResolver.notifyChange. –  Timo Ohr Dec 20 '12 at 11:48 4   Yeah. on your CustomLoader's loadInBackground() , before return the cursor, say cursor.setNotificationUri(getContext().getContentResolver(), uri); the uri may just from random String like Uri.parse("content://query_slot1"). Seem like it don't care the uri really exist or not. And once I done operation on DB. Say getContentResolver().notifyChange(uri, null); would do the trick. Then I may create few "query uri slot" in a contant file for app with small number of query. I test insert the DB record in runtime and it seems work but I still doubt it is good practice onit. Any suggestion? –  Yeung Aug 16 '13 at 4:53      I'm using this method with @Yeung 's suggestion and everything works, including automatic reloading of the cursor on database update. –  DavidH Apr 24 '15 at 17:29      doesnt need it any unregisterContentObserver? –  GPack Apr 7 '16 at 10:21



 |  up vote 1 down vote The third option proposed by Timo Ohr, together with the comments by Yeung, provide the simplest answer (Occam's razor). Below is an example of a complete class that works for me. There are two rules for using this class. Extend this abstract class and implement methods getCursor() and getContentUri(). Any time that the underlying database changes (e.g., after an insert or delete), make sure to call getContentResolver().notifyChange(myUri, null);

where myUri is the same one returned from your implementation of method getContentUri(). Here is the code for the class that I used: package com.example.project;

import android.content.Context;

import android.database.Cursor;

import android.content.CursorLoader;

import android.content.Loader;

public abstract class AbstractCustomCursorLoader extends CursorLoader

{

private final Loader.ForceLoadContentObserver mObserver = new Loader.ForceLoadContentObserver();

public AbstractCustomCursorLoader(Context context)

{

super(context);

}

@Override

public Cursor loadInBackground()

{

Cursor cursor = getCursor();

if (cursor != null)

{

// Ensure the cursor window is filled

cursor.getCount();

cursor.registerContentObserver(mObserver);

}

cursor.setNotificationUri(getContext().getContentResolver(), getContentUri());

return cursor;

}

protected abstract Cursor getCursor();

protected abstract Uri getContentUri();

}


  |
  this answer answered Mar 4 at 23:20 John Moore 83 8



 | 

推荐:Android ContentProvider

内容提供者(content provider)使一个应用程序的指定数据集提供给其他应用程序。这些数据可以存储在文件系统中、在一个SQLite数据库、或以任何其他合理的方式。

up vote 104 down vote favorite 99 Android SDK documentation says that startManagingCursor() method is depracated: This method is deprecated. Use the new CursorLoader class with Loa

相关阅读排行


相关内容推荐

最新文章

×

×

请激活账号

为了能正常使用评论、编辑功能及以后陆续为用户提供的其他产品,请激活账号。

您的注册邮箱: 修改

重新发送激活邮件 进入我的邮箱

如果您没有收到激活邮件,请注意检查垃圾箱。