首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >NullPointerException: uri - LoaderManager / SQLiteManager / ListView

NullPointerException: uri - LoaderManager / SQLiteManager / ListView
EN

Stack Overflow用户
提问于 2016-03-08 15:15:17
回答 1查看 996关注 0票数 1

在使用ListView和LoaderManager填充片段中的片段时,我会得到这个错误。如果我从适配器中删除SQLiteCursorLoader并直接填充,那么所有这些都能正常工作。如果我尝试一个自定义适配器,我会得到同样的错误。错误似乎是,mUri成员的CursorLoader从未填充并被保留为空,SQLiteCursorLoader从不调用设置mUri的CursorLoader上的构造函数。

代码语言:javascript
复制
public CursorLoader(Context context, Uri uri, String[] projection, String selection,
        String[] selectionArgs, String sortOrder) {
    super(context);
    mObserver = new ForceLoadContentObserver();
    mUri = uri;
    mProjection = projection;
    mSelection = selection;
    mSelectionArgs = selectionArgs;
    mSortOrder = sortOrder;
}

相反,它调用只传递上下文的构造函数的版本。

代码语言:javascript
复制
public CursorLoader(Context context) {
    super(context);
    mObserver = new ForceLoadContentObserver();
}

这是错误

代码语言:javascript
复制
03-08 15:00:36.906 2601-2683/com.overunitystudios.medbuddy E/AndroidRuntime: FATAL EXCEPTION: AsyncTask #1
                                                                             Process: com.overunitystudios.medbuddy, PID: 2601
                                                                             java.lang.RuntimeException: An error occurred while executing doInBackground()
                                                                                 at android.os.AsyncTask$3.done(AsyncTask.java:309)
                                                                                 at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:354)
                                                                                 at java.util.concurrent.FutureTask.setException(FutureTask.java:223)
                                                                                 at java.util.concurrent.FutureTask.run(FutureTask.java:242)
                                                                                 at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113)
                                                                                 at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588)
                                                                                 at java.lang.Thread.run(Thread.java:818)
                                                                              Caused by: java.lang.NullPointerException: uri
                                                                                 at com.android.internal.util.Preconditions.checkNotNull(Preconditions.java:60)
                                                                                 at android.content.ContentResolver.query(ContentResolver.java:474)
                                                                                 at android.content.CursorLoader.loadInBackground(CursorLoader.java:64)
                                                                                 at android.content.CursorLoader.loadInBackground(CursorLoader.java:56)
                                                                                 at android.content.AsyncTaskLoader.onLoadInBackground(AsyncTaskLoader.java:312)
                                                                                 at android.content.AsyncTaskLoader$LoadTask.doInBackground(AsyncTaskLoader.java:69)
                                                                                 at android.content.AsyncTaskLoader$LoadTask.doInBackground(AsyncTaskLoader.java:66)
                                                                                 at android.os.AsyncTask$2.call(AsyncTask.java:295)
                                                                                 at java.util.concurrent.FutureTask.run(FutureTask.java:237)
                                                                                 at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113) 
                                                                                 at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588) 
                                                                                 at java.lang.Thread.run(Thread.java:818) 

下面是包含ListView的片段的代码

代码语言:javascript
复制
public class fragment_medications extends Fragment  implements LoaderManager.LoaderCallbacks<Cursor> {

    private database_helper_medications dbHelper;
    private SimpleCursorAdapter listAdapter;
    private SQLLiteCursorLoader loader=null;

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        //return super.onCreateView(inflater, container, savedInstanceState);

        View view = inflater.inflate(R.layout.fragment_medications_layout, container,false);

        dbHelper = new database_helper_medications(getActivity());

        listAdapter = new SimpleCursorAdapter(getActivity(),R.layout.list_item_medications,null, new String[] {database_helper_medications.FIELD_MEDICATION}, new int[] {R.id.tvMedication},0);

        ListView lvMedications = (ListView) view.findViewById(R.id.lvMedications);
        lvMedications.setAdapter(listAdapter);

        return view;
    }

    @Override public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        getLoaderManager().initLoader(0, null, this);
    }

    //TODO: 03-08 00:16:48.563 3508-3516/com.overunitystudios.medbuddy W/SQLiteConnectionPool: A SQLiteConnection object for database '/data/user/0/com.overunitystudios.medbuddy/databases/medbuddy' was leaked!  Please fix your application to end transactions in progress properly and to close the database when it is no longer needed.

    @Override
    public void onDestroy() {
        super.onDestroy();
        if (dbHelper!=null) dbHelper.close();
    }

    @Override
    public Loader<Cursor> onCreateLoader(int id, Bundle args) {
        loader=new SQLLiteCursorLoader(getActivity(), dbHelper, dbHelper.DATABASE_SELECT_ALL, null);
        return(loader);
    }


    @Override
    public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
        this.loader=(SQLLiteCursorLoader)loader;
        listAdapter.changeCursor(data);
    }

    @Override
    public void onLoaderReset(Loader<Cursor> loader) {
        listAdapter.changeCursor(null);
    }

}

数据库助手

代码语言:javascript
复制
public class database_helper_medications extends SQLiteOpenHelper {

    private static final String DATABASE_NAME = "medbuddy";
    private static final String TABLE_NAME = "medications";
    private static final int DATABASE_VERSION = 1;

    public final static String FIELD_ID="_id"; //Changed table to use a column named "_id" instead of "id" as CursorAdapter must have an _id column in the table it is using.
    public final static String FIELD_MEDICATION="name";

    private SQLiteDatabase database;

    // Database creation sql statement
    private static final String DATABASE_CREATE = "create table if not exists " + TABLE_NAME + " ( " + FIELD_ID + " integer primary key," + FIELD_MEDICATION + " text not null);";
    public static final String DATABASE_SELECT_ALL = "select " + FIELD_ID + "," + FIELD_MEDICATION + " from " + TABLE_NAME + " order by " + FIELD_MEDICATION;

    public database_helper_medications(Context context) {
        super(context, DATABASE_NAME, null, DATABASE_VERSION);
        database = this.getWritableDatabase();
    }

    // Method is called during creation of the database
    @Override
    public void onCreate(SQLiteDatabase database) {
        database.execSQL(DATABASE_CREATE);
    }

    // Method is called during an upgrade of the database,
    @Override
    public void onUpgrade(SQLiteDatabase database,int oldVersion,int newVersion){
        database.execSQL("DROP TABLE IF EXISTS " + TABLE_NAME + "");
        onCreate(database);
    }

    public long createSingleRecord(Integer id, String medication){
        ContentValues values = new ContentValues();
        values.put(FIELD_ID, id);
        values.put(FIELD_MEDICATION, medication);
        return database.insert(TABLE_NAME, null, values);
    }

    public long createSingleRecord(String medication){
        ContentValues values = new ContentValues();
        //values.put(FIELD_ID, id); //We dont need to do this as it's marked autoincrement.
        values.put(FIELD_MEDICATION, medication);
        return database.insert(TABLE_NAME, null, values);
    }


    public Cursor selectAllRecords() {
        String[] cols = new String[] {FIELD_ID, FIELD_MEDICATION};
        Cursor mCursor = database.query(true, TABLE_NAME, cols,null, null, null, null, null, null);
        if (mCursor != null)
            mCursor.moveToFirst();

        return mCursor; // iterate to get each value.
    }

    public void DumpToLog()
    {
        Log.i("DumpToLog", DatabaseUtils.dumpCursorToString(selectAllRecords()));
    }
}

这里是SQLLiteCursorLoader (我重命名为流行的SQLiteCursorLoader)

代码语言:javascript
复制
public class SQLLiteCursorLoader extends CursorLoader
{

    SQLiteOpenHelper db=null;
    String rawQuery=null;
    String[] args=null;
    /**
     * Creates a fully-specified SQLiteCursorLoader. See
     * {@link SQLiteDatabase#rawQuery(SQLiteDatabase, String, String[])
     * SQLiteDatabase.rawQuery()} for documentation on the
     * meaning of the parameters. These will be passed as-is
     * to that call.
     */
    public SQLLiteCursorLoader(Context context, SQLiteOpenHelper db, String rawQuery, String[] args)
    {
        super(context);
        this.db=db;
        this.rawQuery=rawQuery;
        this.args=args;
    }

    /**
     * Runs on a worker thread and performs the actual
     * database query to retrieve the Cursor.
     */
    //@Override
    protected Cursor buildCursor() {
        return(db.getReadableDatabase().rawQuery(rawQuery, args));
    }

    /**
     * Writes a semi-user-readable roster of contents to
     * supplied output.
     */
    @Override
    public void dump(String prefix, FileDescriptor fd,PrintWriter writer, String[] args)
    {
        super.dump(prefix, fd, writer, args);
        writer.print(prefix);
        writer.print("rawQuery=");
        writer.println(rawQuery);
        writer.print(prefix);
        writer.print("args=");
        writer.println(Arrays.toString(args));
    }

    public void insert(String table, String nullColumnHack, ContentValues values)
    {
        buildInsertTask(this).execute(db, table, nullColumnHack, values);
    }

    public void update(String table, ContentValues values,String whereClause, String[] whereArgs)
    {
        buildUpdateTask(this).execute(db, table, values, whereClause,whereArgs);
    }

    public void replace(String table, String nullColumnHack,ContentValues values)
    {
        buildReplaceTask(this).execute(db, table, nullColumnHack, values);
    }

    public void delete(String table, String whereClause,String[] whereArgs)
    {
        buildDeleteTask(this).execute(db, table, whereClause, whereArgs);
    }

    public void execSQL(String sql, Object[] bindArgs)
    {
        buildExecSQLTask(this).execute(db, sql, bindArgs);
    }

    protected ContentChangingTask buildInsertTask(SQLLiteCursorLoader loader)
    {
        return(new InsertTask(loader));
    }

    protected ContentChangingTask buildUpdateTask(SQLLiteCursorLoader loader)
    {
        return(new UpdateTask(loader));
    }

    protected ContentChangingTask buildReplaceTask(SQLLiteCursorLoader loader)
    {
        return(new ReplaceTask(loader));
    }

    protected ContentChangingTask buildDeleteTask(SQLLiteCursorLoader loader)
    {
        return(new DeleteTask(loader));
    }

    protected ContentChangingTask buildExecSQLTask(SQLLiteCursorLoader loader)
    {
        return(new ExecSQLTask(loader));
    }

    protected static class InsertTask extends ContentChangingTask
    {
        InsertTask(SQLLiteCursorLoader loader)
        {
            super(loader);
        }

        @Override
        protected Void doInBackground(Object... params) {
            SQLiteOpenHelper db=(SQLiteOpenHelper)params[0];
            String table=(String)params[1];
            String nullColumnHack=(String)params[2];
            ContentValues values=(ContentValues)params[3];

            db.getWritableDatabase().insert(table, nullColumnHack, values);

            return(null);
        }
    }

    protected static class UpdateTask extends ContentChangingTask
    {
        UpdateTask(SQLLiteCursorLoader loader)
        {
            super(loader);
        }

        @Override
        protected Void doInBackground(Object... params) {
            SQLiteOpenHelper db=(SQLiteOpenHelper)params[0];
            String table=(String)params[1];
            ContentValues values=(ContentValues)params[2];
            String where=(String)params[3];
            String[] whereParams=(String[])params[4];

            db.getWritableDatabase().update(table, values, where, whereParams);

            return(null);
        }
    }

    protected static class ReplaceTask extends ContentChangingTask
    {
        ReplaceTask(SQLLiteCursorLoader loader)
        {
            super(loader);
        }

        @Override
        protected Void doInBackground(Object... params) {
            SQLiteOpenHelper db=(SQLiteOpenHelper)params[0];
            String table=(String)params[1];
            String nullColumnHack=(String)params[2];
            ContentValues values=(ContentValues)params[3];

            db.getWritableDatabase().replace(table, nullColumnHack, values);

            return(null);
        }
    }

    protected static class DeleteTask extends ContentChangingTask
    {
        DeleteTask(SQLLiteCursorLoader loader)
        {
            super(loader);
        }

        @Override
        protected Void doInBackground(Object... params) {
            SQLiteOpenHelper db=(SQLiteOpenHelper)params[0];
            String table=(String)params[1];
            String where=(String)params[2];
            String[] whereParams=(String[])params[3];

            db.getWritableDatabase().delete(table, where, whereParams);

            return(null);
        }
    }

    protected static class ExecSQLTask extends ContentChangingTask
    {
        ExecSQLTask(SQLLiteCursorLoader loader)
        {
            super(loader);
        }

        @Override
        protected Void doInBackground(Object... params) {
            SQLiteOpenHelper db=(SQLiteOpenHelper)params[0];
            String sql=(String)params[1];
            Object[] bindParams=(Object[])params[2];

            db.getWritableDatabase().execSQL(sql, bindParams);

            return(null);
        }
    }
}

我将不包括布局XML,正如我前面说过的,如果我直接从适配器填充并且不使用加载程序,它就能工作。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2016-03-08 16:02:20

CursorLoader API

公共CursorLoader (上下文) 在API 11中添加创建一个空的、未指定的CursorLoader。您必须遵循setSelection(String),,然后调用setUri(Uri)、等来指定要执行的查询。

因此,在自定义SQLLiteCursorLoader类中,必须在super(context);之后显式调用构造函数中的super(context);

更新

看看你在下面的评论中提到的github项目,我发现了一个不同之处。

你的

代码语言:javascript
复制
public class SQLLiteCursorLoader extends CursorLoader 

而github的

代码语言:javascript
复制
public class SQLiteCursorLoader extends AbstractCursorLoader

你猜怎么着,CursorLoader有一个方法(链接)

代码语言:javascript
复制
/* Runs on a worker thread */
@Override
public Cursor loadInBackground() {
    Cursor cursor = getContext().getContentResolver().query(mUri, mProjection, mSelection,
            mSelectionArgs, mSortOrder);
    if (cursor != null) {
        // Ensure the cursor window is filled
        cursor.getCount();
        registerContentObserver(cursor, mObserver);
    }
    return cursor;
}

它使用mUri,这就是它不能为null的原因,而AbstractCursorLoader (链接)中的等效方法是:

代码语言:javascript
复制
@Override
public Cursor loadInBackground() {
    Cursor cursor=buildCursor();

    if (cursor!=null) {
      // Ensure the cursor window is filled
      cursor.getCount();
    }

    return(cursor);
}

因此,如果您更正SQLLiteCursorLoader类中的继承(使其扩展AbstractCursorLoader),您最终将解决问题。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/35871133

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档