NPE: CursorTreeAdapter$MyCursorHelper.changeCursor(Cursor, boolean)'для пустой ссылки на объект

Я пытаюсь получить данные из моей базы данных в разных курсорах и показать их в ExpandableListView, разделенных по группам. Как следующее:

  • История задач (до курсора 0)
    • История 1
    • История 2
  • Географические задачи (до курсора 1)
    • География 1
    • География 2
  • Задачи на иностранном языке (до курсора 2)
    • Иностранный язык 1
    • Иностранный язык 2

Я пытаюсь сделать это с помощью CursorTreeAdapter, так как у меня есть вся моя информация в базе данных, и она может управлять различными курсорами и правильно отображать информацию в ExpandableListView.

Проблема, которую я получаю, состоит в том, что я получаю NPE в какой-то момент моего кода, но я не могу проверить, где он отлаживается, потому что он напрямую переключается на другой файл, не зная, что происходит.

Когда я отлаживаю в методе CursorTreeAdapter::setChildrenCursor, просто когда я вхожу в

childrenCursorHelper.changeCursor(childrenCursor, false);

это терпит неудачу, поэтому я не знаю, что происходит внутри этого метода.

Мой код следующий:

MtMainActivity.java

public class MtMainActivity extends AppCompatActivity implements LoaderManager.LoaderCallbacks<Cursor> {

    @InjectView(R.id.elvTaskList)
    protected ExpandableListView elvTaskList;
    private TaskCursorAdapter taskListAdapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        taskListAdapter = new TaskCursorAdapter(null, this);
        elvTaskList.setAdapter(taskListAdapter);
        getSupportLoaderManager().initLoader(MtLoaders.HISTORY_TASK, null, this);
    }

    @Override
    public Loader<Cursor> onCreateLoader(int id, Bundle args) {
        switch (id) {
            case MtLoaders.HISTORY_TASK:
                return mtLoaderFactory.createHistoryTaskLoader();
        }
    }

    @Override
    public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
        switch (loader.getId()) {
            case MtLoaders.HISTORY_TASK:
                taskListAdapter.setChildrenCursor(0, cursor);
        }
    }

    @Override
    public void onLoaderReset(Loader<Cursor> loader) {
        switch (loader.getId()) {
            case MtLoaders.HISTORY_TASK:
                taskListAdapter.setChildrenCursor(0, null);
        }
    }

TaskCursorAdapter.java

public class TaskCursorAdapter extends CursorTreeAdapter {

    private final Cursor cursor;

    public TaskCursorAdapter(Cursor cursor, Context context) {
        super(cursor, context);
        this.cursor = cursor;
    }

    @Override
    protected Cursor getChildrenCursor(Cursor groupCursor) {
        return cursor;
    }

    @Override
    protected View newGroupView(Context context, Cursor cursor, boolean isExpanded, ViewGroup parent) {
        final LayoutInflater layoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        final TextView tvHeader = (TextView) layoutInflater.inflate(R.layout.mt_task_item_subtitle, parent, false);
        tvHeader.setText(">> Insert name here <<");
        return tvHeader;
    }

    @Override
    protected void bindGroupView(View view, Context context, Cursor cursor, boolean isExpanded) { /* nothing */ }

    @Override
    protected View newChildView(Context context, Cursor cursor, boolean isLastChild, ViewGroup parent) {
        final LayoutInflater layoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        final View view = layoutInflater.inflate(R.layout.mt_task_item, parent, false);

        return view;
    }

    @Override
    protected void bindChildView(View view, Context context, Cursor cursor, boolean isLastChild) { /* nothing */ }
}

ошибка

E/AndroidRuntime﹕ FATAL EXCEPTION: main
Process: project.android, PID: 11592
java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.CursorTreeAdapter$MyCursorHelper.changeCursor(android.database.Cursor, boolean)' on a null object reference
        at android.widget.CursorTreeAdapter.setChildrenCursor(CursorTreeAdapter.java:164)
        at project.android.ui.MtMainActivity.onLoadFinished(MtMainActivity.java:215)
        at project.android.ui.MtMainActivity.onLoadFinished(MtMainActivity.java:29)
        at android.support.v4.app.LoaderManagerImpl$LoaderInfo.callOnLoadFinished(LoaderManager.java:427)
        at android.support.v4.app.LoaderManagerImpl$LoaderInfo.onLoadComplete(LoaderManager.java:395)
        at android.support.v4.content.Loader.deliverResult(Loader.java:104)
        at android.support.v4.content.AsyncTaskLoader.dispatchOnLoadComplete(AsyncTaskLoader.java:223)
        at android.support.v4.content.AsyncTaskLoader$LoadTask.onPostExecute(AsyncTaskLoader.java:61)
        at android.support.v4.content.ModernAsyncTask.finish(ModernAsyncTask.java:461)
        at android.support.v4.content.ModernAsyncTask.access$500(ModernAsyncTask.java:47)
        at android.support.v4.content.ModernAsyncTask$InternalHandler.handleMessage(ModernAsyncTask.java:474)
        at android.os.Handler.dispatchMessage(Handler.java:102)
        at android.os.Looper.loop(Looper.java:135)
        at android.app.ActivityThread.main(ActivityThread.java:5221)
        at java.lang.reflect.Method.invoke(Native Method)
        at java.lang.reflect.Method.invoke(Method.java:372)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:899)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:694)

PS: Курсор работает правильно, я проверил, используя уникальный ListView и не было никаких проблем с этим.

2 ответа

У меня та же проблема в моем проекте. Кажется, это проблема в CursorTreeAdapter:

at android.widget.CursorTreeAdapter.setChildrenCursor(CursorTreeAdapter.java:164)

Посмотрите на этот метод внутри Android-источников:

    public void setChildrenCursor(int groupPosition, Cursor childrenCursor) {

    /*
     * Don't request a cursor from the subclass, instead we will be setting
     * the cursor ourselves.
     */
    MyCursorHelper childrenCursorHelper = getChildrenCursorHelper(groupPosition, false);

    /*
     * Don't release any cursor since we know exactly what data is changing
     * (this cursor, which is still valid).
     */
    childrenCursorHelper.changeCursor(childrenCursor, false);
}

В некоторых случаях getChildrenCursorHelper возвращает значение null в childrenCursorHelper. Я получаю это обычно после изменения конфигурации (например, поворот экрана).

Чтобы решить эту проблему, я добавляю источники CursorFilter + CursorTreeAdapter в свой проект, затем добавляем нулевую проверку в childrenCursorHelper

    public void setChildrenCursor(int groupPosition, Cursor childrenCursor) {

    /*
     * Don't request a cursor from the subclass, instead we will be setting
     * the cursor ourselves.
     */
    MyCursorHelper childrenCursorHelper = getChildrenCursorHelper(groupPosition, false);

    /*
     * Don't release any cursor since we know exactly what data is changing
     * (this cursor, which is still valid).
     */
    if (childrenCursorHelper != null)
        childrenCursorHelper.changeCursor(childrenCursor, false);
}

и, наконец, расширить мой адаптер из фиксированного CursorTreeAdapter.
Смотрите этот коммит для деталей.

Вам не нужно добавлять источники CursorTreeAdapter в проект.

Просто переопределите setChildrenCursor:

public class MyAdapter extends CursorTreeAdapter {

    @Override
    public void setChildrenCursor(int groupPosition, Cursor childrenCursor) {
        try {
            Method getChildrenCursorHelper = CursorTreeAdapter.class.getDeclaredMethod("getChildrenCursorHelper", int.class, boolean.class);
            getChildrenCursorHelper.setAccessible(true);
            Object childrenCursorHelper = getChildrenCursorHelper.invoke(this, groupPosition, false);
            if (childrenCursorHelper != null) {
                Method changeCursor = childrenCursorHelper.getClass().getDeclaredMethod("changeCursor", Cursor.class, boolean.class);
                changeCursor.setAccessible(true);
                changeCursor.invoke(childrenCursorHelper, childrenCursor, false);
            }
        } catch (IllegalAccessException e) {
        } catch (InvocationTargetException e) {
        } catch (NoSuchMethodException e) {
        }
    }
}
Другие вопросы по тегам