4

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

  • задач истории (к курсору 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: Cursor работает правильно, я проверил с помощью уникального ListView и не было никаких проблем с этим.

ответ

0

У меня такая же проблема в моем проекте.Кажется, что это проблема в 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 возвращает нуль в 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.
Для получения более подробной информации см. this commit.

1

Вам не нужно добавлять источники проекта 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) { 
     } 
    } 
} 
Смежные вопросы