program story

ContentProvider없이 CursorLoader 사용

inputbox 2020. 8. 7. 08:24
반응형

ContentProvider없이 CursorLoader 사용


Android SDK 설명서에 따르면 startManagingCursor()메서드가 더 이상 사용되지 않습니다.

이 방법은 더 이상 사용되지 않습니다. 대신 LoaderManager와 함께 새 CursorLoader 클래스를 사용하십시오. Android 호환성 패키지를 통해 이전 플랫폼에서도 사용할 수 있습니다. 이 방법을 사용하면 활동이 활동의 ​​수명주기를 기반으로 지정된 커서의 수명주기를 관리 할 수 ​​있습니다. 즉, 활동이 중지되면 주어진 Cursor에서 자동으로 deactivate ()를 호출하고 나중에 다시 시작할 때 requery ()를 호출합니다. 활동이 파괴되면 모든 관리 커서가 자동으로 닫힙니다. HONEYCOMB 이상을 대상으로하는 경우 대신 getLoaderManager ()를 통해 사용할 수있는 LoaderManager를 사용하는 것이 좋습니다.

그래서 저는 CursorLoader. 하지만 생성자에서 URI가 필요할 때 사용자 지정 CursorAdapter및 사용하지 않고 어떻게 사용할 수 있습니까?ContentProviderCursorLoader


콘텐츠 공급자가 필요없는 간단한 CursorLoader작성했습니다 .

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;
    }
}

AsyncTaskLoader수업 만 필요합니다 . Android 3.0 이상 또는 호환성 패키지와 함께 제공되는 것입니다.

나는 또한와ListLoader 호환되는을 썼으며LoadManager 일반 java.util.List컬렉션 을 검색하는 데 사용됩니다 .


콘텐츠 공급자 대신 데이터베이스 클래스를 사용하는 고유 한 로더를 작성하십시오. 가장 쉬운 방법은 CursorLoader호환성 라이브러리에서 클래스 의 소스를 가져 와서 공급자 쿼리를 자신의 db 도우미 클래스에 대한 쿼리로 바꾸는 것입니다.


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


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.


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.

  1. Extend this abstract class and implement methods getCursor() and getContentUri().
  2. 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();
  }

참고URL : https://stackoverflow.com/questions/7182485/cursorloader-usage-without-contentprovider

반응형