{"action":"created","issue":{"url":"https://api.github.com/repos/Raizlabs/DBFlow/issues/134","repository_url":"https://api.github.com/repos/Raizlabs/DBFlow","labels_url":"https://api.github.com/repos/Raizlabs/DBFlow/issues/134/labels{/name}","comments_url":"https://api.github.com/repos/Raizlabs/DBFlow/issues/134/comments","events_url":"https://api.github.com/repos/Raizlabs/DBFlow/issues/134/events","html_url":"https://github.com/Raizlabs/DBFlow/issues/134","id":60333039,"number":134,"title":"DBFlowCursorLoader class.","user":{"login":"jiqimaogou","id":1407040,"avatar_url":"https://avatars.githubusercontent.com/u/1407040?v=3","gravatar_id":"","url":"https://api.github.com/users/jiqimaogou","html_url":"https://github.com/jiqimaogou","followers_url":"https://api.github.com/users/jiqimaogou/followers","following_url":"https://api.github.com/users/jiqimaogou/following{/other_user}","gists_url":"https://api.github.com/users/jiqimaogou/gists{/gist_id}","starred_url":"https://api.github.com/users/jiqimaogou/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jiqimaogou/subscriptions","organizations_url":"https://api.github.com/users/jiqimaogou/orgs","repos_url":"https://api.github.com/users/jiqimaogou/repos","events_url":"https://api.github.com/users/jiqimaogou/events{/privacy}","received_events_url":"https://api.github.com/users/jiqimaogou/received_events","type":"User","site_admin":false},"labels":[],"state":"closed","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":10,"created_at":"2015-03-09T11:59:38Z","updated_at":"2016-08-28T19:09:52Z","closed_at":"2015-04-14T18:38:38Z","body":"I write a ```CursorLoader``` which is using DBFlow.\r\n```\r\npackage me.johnczchen.frameworks.content;\r\n\r\nimport android.content.Context;\r\nimport android.database.Cursor;\r\nimport android.database.sqlite.SQLiteDatabase;\r\nimport android.net.Uri;\r\nimport android.support.v4.content.AsyncTaskLoader;\r\n\r\nimport com.raizlabs.android.dbflow.config.FlowManager;\r\nimport com.raizlabs.android.dbflow.runtime.FlowContentObserver;\r\nimport com.raizlabs.android.dbflow.structure.BaseModel;\r\nimport com.raizlabs.android.dbflow.structure.Model;\r\n\r\nimport java.io.FileDescriptor;\r\nimport java.io.PrintWriter;\r\nimport java.util.Arrays;\r\n\r\n/**\r\n * Static library support version of the framework's {@link android.content.CursorLoader}. Used to\r\n * write apps that run on platforms prior to Android 3.0.  When running on Android 3.0 or above,\r\n * this implementation is still used; it does not try to switch to the framework's implementation.\r\n * See the framework SDK documentation for a class overview.\r\n */\r\npublic class CursorLoader extends AsyncTaskLoader<Cursor> {\r\n    final ForceLoadContentObserver mObserver;\r\n    private Class<? extends Model> mModel;\r\n\r\n    SQLiteDatabase mDatabase;\r\n    String mSql;\r\n    String[] mSelectionArgs;\r\n    Cursor mCursor;\r\n\r\n    private final class ForceLoadContentObserver extends FlowContentObserver {\r\n        public ForceLoadContentObserver() {\r\n        }\r\n\r\n        @Override\r\n        public boolean deliverSelfNotifications() {\r\n            return true;\r\n        }\r\n\r\n        @Override\r\n        public void onChange(boolean selfChange) {\r\n            super.onChange(selfChange);\r\n            onContentChanged();\r\n        }\r\n\r\n        @Override\r\n        public void onChange(boolean selfChange, Uri uri) {\r\n            super.onChange(selfChange, uri);\r\n            onContentChanged();\r\n        }\r\n    }\r\n\r\n    /* Runs on a worker thread */\r\n    @Override\r\n    public Cursor loadInBackground() {\r\n        Cursor cursor = mDatabase.rawQuery(mSql, mSelectionArgs);\r\n        if (cursor != null) {\r\n            // Ensure the cursor window is filled\r\n            cursor.getCount();\r\n        }\r\n        return cursor;\r\n    }\r\n\r\n    /* Runs on the UI thread */\r\n    @Override\r\n    public void deliverResult(Cursor cursor) {\r\n        if (isReset()) {\r\n            // An async query came in while the loader is stopped\r\n            if (cursor != null) {\r\n                cursor.close();\r\n            }\r\n            return;\r\n        }\r\n        Cursor oldCursor = mCursor;\r\n        mCursor = cursor;\r\n\r\n        if (isStarted()) {\r\n            super.deliverResult(cursor);\r\n        }\r\n\r\n        if (oldCursor != null && oldCursor != cursor && !oldCursor.isClosed()) {\r\n            oldCursor.close();\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Creates an empty unspecified CursorLoader.  You must follow this with calls to {@link\r\n     * #setSql(String sql)}}, etc to specify the query to perform.\r\n     */\r\n    public CursorLoader(Context context) {\r\n        super(context);\r\n        mObserver = new ForceLoadContentObserver();\r\n    }\r\n\r\n    /**\r\n     * Creates a fully-specified CursorLoader.  See {@link android.content.ContentResolver#query(Uri,\r\n     * String[], String, String[], String) ContentResolver.query()} for documentation on the meaning\r\n     * of the parameters.  These will be passed as-is to that call.\r\n     */\r\n    public CursorLoader(Context context\r\n            , Class<? extends Model> model, String sql, String[] selectionArgs) {\r\n        super(context);\r\n        mDatabase = FlowManager.getDatabaseForTable(model).getWritableDatabase();\r\n        mModel = model;\r\n        mSql = sql;\r\n        mSelectionArgs = selectionArgs;\r\n        mObserver = new ForceLoadContentObserver();\r\n    }\r\n\r\n    /**\r\n     * Starts an asynchronous load of the contacts list data. When the result is ready the callbacks\r\n     * will be called on the UI thread. If a previous load has been completed and is still valid the\r\n     * result may be passed to the callbacks immediately.\r\n     * <p/>\r\n     * Must be called from the UI thread\r\n     */\r\n    @Override\r\n    protected void onStartLoading() {\r\n        if (mCursor != null) {\r\n            deliverResult(mCursor);\r\n        }\r\n        if (takeContentChanged() || mCursor == null) {\r\n            forceLoad();\r\n        }\r\n\r\n        mObserver.registerForContentChanges(getContext(), mModel);\r\n    }\r\n\r\n    /**\r\n     * Must be called from the UI thread\r\n     */\r\n    @Override\r\n    protected void onStopLoading() {\r\n        // Attempt to cancel the current load task if possible.\r\n        cancelLoad();\r\n    }\r\n\r\n    @Override\r\n    public void onCanceled(Cursor cursor) {\r\n        if (cursor != null && !cursor.isClosed()) {\r\n            cursor.close();\r\n        }\r\n        // mObserver.unregisterForContentChanges(getContext());\r\n    }\r\n\r\n    @Override\r\n    protected void onReset() {\r\n        super.onReset();\r\n\r\n        // Ensure the loader is stopped\r\n        onStopLoading();\r\n\r\n        if (mCursor != null && !mCursor.isClosed()) {\r\n            mCursor.close();\r\n        }\r\n        mCursor = null;\r\n\r\n        mObserver.unregisterForContentChanges(getContext());\r\n    }\r\n\r\n    public Class<? extends Model> getModel() {\r\n        return mModel;\r\n    }\r\n\r\n    public void registerForContentChanges(Class<? extends BaseModel> model) {\r\n        if (mModel == model) {\r\n            return;\r\n        }\r\n\r\n        if (mModel != null) {\r\n            mObserver.unregisterForContentChanges(getContext());\r\n        }\r\n\r\n        mModel = model;\r\n        mObserver.registerForContentChanges(getContext(), mModel);\r\n    }\r\n\r\n    public String getSql() {\r\n        return mSql;\r\n    }\r\n\r\n    public void setSql(String sql) {\r\n        this.mSql = sql;\r\n    }\r\n\r\n    public String[] getSelectionArgs() {\r\n        return mSelectionArgs;\r\n    }\r\n\r\n    public void setSelectionArgs(String[] selectionArgs) {\r\n        mSelectionArgs = selectionArgs;\r\n    }\r\n\r\n    @Override\r\n    public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {\r\n        super.dump(prefix, fd, writer, args);\r\n        writer.print(prefix);\r\n        writer.print(\"mModel=\");\r\n        writer.print(mModel);\r\n        writer.print(\"mSql=\");\r\n        writer.println(mSql);\r\n        writer.print(prefix);\r\n        writer.print(\"mSelectionArgs=\");\r\n        writer.println(Arrays.toString(mSelectionArgs));\r\n        writer.print(prefix);\r\n        writer.print(\"mCursor=\");\r\n        writer.println(mCursor);\r\n        writer.print(prefix); writer.print(\"mContentChanged=\"); writer.println(takeContentChanged());\r\n    }\r\n}\r\n```\r\n### how to use?\r\n```\r\n            @Override\r\n            public Loader<Cursor> onCreateLoader(int id, Bundle args) {\r\n                return new CursorLoader(getActivity(), MedicalRecord.class, new Select().from(MedicalRecord.class).getQuery(), null);\r\n            }\r\n````\r\ncan you add this to your repo? and I think ```ModelListLoader``` and ```SingleModelLoader``` would be nice too.\r\n\r\nI really like dbflow, and thank you.\r\n\r\n```ModelListLoader``` has a append member, if append is true, everytime loadfinish it will add model list to the exsiting list in the loader, else it will replace the list in the loader."},"comment":{"url":"https://api.github.com/repos/Raizlabs/DBFlow/issues/comments/242993090","html_url":"https://github.com/Raizlabs/DBFlow/issues/134#issuecomment-242993090","issue_url":"https://api.github.com/repos/Raizlabs/DBFlow/issues/134","id":242993090,"user":{"login":"roblav96","id":1457327,"avatar_url":"https://avatars.githubusercontent.com/u/1457327?v=3","gravatar_id":"","url":"https://api.github.com/users/roblav96","html_url":"https://github.com/roblav96","followers_url":"https://api.github.com/users/roblav96/followers","following_url":"https://api.github.com/users/roblav96/following{/other_user}","gists_url":"https://api.github.com/users/roblav96/gists{/gist_id}","starred_url":"https://api.github.com/users/roblav96/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/roblav96/subscriptions","organizations_url":"https://api.github.com/users/roblav96/orgs","repos_url":"https://api.github.com/users/roblav96/repos","events_url":"https://api.github.com/users/roblav96/events{/privacy}","received_events_url":"https://api.github.com/users/roblav96/received_events","type":"User","site_admin":false},"created_at":"2016-08-28T19:09:52Z","updated_at":"2016-08-28T19:09:52Z","body":"@hilljh82 Awesome! Thank you. I'll start playing around with it."}}
{"actor":{"display_login":"roblav96"}}