我正在尝试从不同游标中的数据库中获取数据,并将其显示在由组分隔的ExpandableListView中。如下所示:
我正在尝试使用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进行检查,没有问题。
答案 0 :(得分:1)
我的项目中有同样的问题。好像,这是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 源添加到我的项目中,然后将null检查添加到 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 :(得分:1)
You don't need to add CursorTreeAdapter sources to the project.
Just override 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) {
}
}
}