ListFragment:CursorAdapter中的findViewById返回null

时间:2012-08-01 20:39:21

标签: android android-fragments listactivity android-cursoradapter findviewbyid

我编写了以下类来创建包含自定义列表行的列表视图。我为项目使用 Android支持库v4 ,并使用ActionBarSherlock库为旧设备集成操作栏。

public class CustomListActivity extends SherlockFragmentActivity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        setTheme(R.style.Sherlock___Theme_DarkActionBar);
        super.onCreate(savedInstanceState);
        setContentView(R.layout.fragment_list);
    }
}

...

public class ListFragment extends SherlockListFragment implements LoaderCallbacks<Cursor> {
    private Activity mActivity;
    private CursorAdapter mAdapter;
    // Query parameter as members ...
    private String mFromColumns;

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        setEmptyText("No data to display");
        mActivity = getActivity();
        // Query parameters are stored in members here ...
        mFromColumns = { "_id", "name" };
        mAdapter = new CustomCursorAdapter(mActivity, null, 0);
        setListAdapter(mAdapter);
        getLoaderManager().initLoader(0, null, this);
    }

    @Override
    public Loader<Cursor> onCreateLoader(int id, Bundle extras) {
        return new CursorLoader(mActivity, mUri, mFromColumns, mSelection, mSelectionArgs, sortOrder);
    }

    @Override
    public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
        mAdapter.swapCursor(cursor);
    }

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

...

public class CustomCursorAdapter extends CursorAdapter {
    private LayoutInflater mInflater;

    public CustomCursorAdapter(Context context, Cursor cursor, int flags) {
        super(context, cursor, flags);
        mInflater = LayoutInflater.from(context);
    }

    @Override
    public void bindView(View view, Context context, Cursor cursor) {
        TextView listItem = (TextView)view.findViewById(R.id.name);
//      TextView listItem = (TextView)view.findViewById(android.R.id.text1);
        String text = cursor.getString(cursor.getColumnIndex("name"));
        listItem.setText(text);
    }

    @Override
    public View newView(Context context, Cursor cursor, ViewGroup parent) {
        return mInflater.inflate(R.layout.list_item, parent, false);
//      return mInflater.inflate(android.R.layout.simple_list_item_1, parent, false);
    }
}

当我使用框架提供的列表项和布局(CustomCursorAdapter中的未注释行)时,列表视图成功加载并显示数据行。但是,当我交换行以使用我的自定义布局和列表项时,findViewById会返回null。这是xml文件。

fragment_list.xml

<?xml version="1.0" encoding="utf-8"?>
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
    android:name="com.example.app.fragment.ListFragment"
    android:id="@+id/list_fragment"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

</fragment>

list_item.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent" 
    android:layout_height="fill_parent" >
    <TextView 
        android:id="@+id/name"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content">
    </TextView>
</LinearLayout>

我很确定,问题是我如何链接xml文件或它们是如何构建的。我希望你能看到错误。实际上,我不明白list_item.xml如何用作列表视图的行布局。我设置为fragment_list.xml的唯一参考是setContentView(R.layout.fragment_list);。此xml文件不包含任何容器元素,例如<ListView android:id="@android:id/list" />(我在其他设置中看到过)。

此外:

我想知道是否仍然建议在CursorAdapter中使用 ViewHolder 模式,或者是否已经内置此行为。我在其他示例中多次看到它,但是那些继承自BaseAdapterSimpleCursorAdapter


经验教训:

当我尝试解决问题时,我在某些时候对XML文件进行了正确的设置。但是另一件事阻碍了我把事情弄得一团糟。以下是您需要注意的事项 如果要在行布局中显示多个信息,请务必在fromColumn的{​​{1}}参数中包含关联的列名称。否则,您将遇到异常:

CursorLoader

fromColumns中的每个列名...

java.lang.IllegalStateException: get field slot from row 0 col -1 failed

...与你要求光标的内容有关。 <{1}}列必须使用游标作为迭代器。

String[] fromColumns = { "_id", "name", "comments" }

1 个答案:

答案 0 :(得分:2)

您的代码适用于我(在我更改行注释时)。唯一的事情是:我已将公共空构造函数添加到ListFragment

仍然建议ViewHolder使用CursorAdapter模式。

public void bindView(View view, Context context, Cursor cursor) {
    ViewHolder holder = (ViewHolder) view.getTag();
    if (holder == null) {
        holder = new ViewHolder();
        holder.name = (TextView) view.findViewById(R.id.name);

        view.setTag(holder);
    }

    String text = cursor.getString(cursor.getColumnIndex("name"));
    holder.name.setText(text);
}

private static class ViewHolder {
    TextView name;
}