我正在关注contacts provider lesson on retrieving contacts并使用 fragment 显示它们。作为引用,我将API级别设置为16(Android 4.1)。

我主要按照本教程进行介绍,但有一些值得注意的异常(exception)。例如,我从mypackage.R而不是android.R导入。

我的问题是在onActivityCreated中的ListContactsFragment处理程序中:

public void onActivityCreated(Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);
    // Initializes the loader
    getLoaderManager().initLoader(0, null, this);
    // Gets the ListView from the View list of the parent activity

    View mContactsListView =
                    getActivity().findViewById(R.layout.contacts_list_view);
    mContactsList = (ListView) mContactsListView;

    // Gets a CursorAdapter
    mCursorAdapter = new SimpleCursorAdapter(
            getActivity(),
            R.layout.contacts_list_item,
            null,
            FROM_COLUMNS, TO_IDS,
            0);
    // Sets the adapter for the ListView
    mContactsList.setAdapter(mCursorAdapter);

    // Set the item click listener to be the current fragment.
    mContactsList.setOnItemClickListener(this);
}
View mContactsListView为空,表示findViewById不起作用。

我的父 Activity 是eclipse创建的默认 Activity 。为此,我做了两件事:
  • import android.app.Activity替换为android.support.v4.app.FragmentActivity,以防止如果不这样做就发生ClasscastException
  • 将我的 fragment 导入XML。

  • 我的activity_list_contacts.xml看起来像这样:
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:paddingBottom="@dimen/activity_vertical_margin"
        android:paddingLeft="@dimen/activity_horizontal_margin"
        android:paddingRight="@dimen/activity_horizontal_margin"
        android:paddingTop="@dimen/activity_vertical_margin"
        tools:context=".ListContactsActivity" >
    
        <fragment android:name="mypackage.ListContactsFragment"
                  android:id="@+id/contacts_list_view"
                  android:layout_width="match_parent"
                  android:layout_height="match_parent" />
    
    </RelativeLayout>
    

    匹配 Activity ,以防万一:
    public class ListContactsActivity extends FragmentActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_list_contacts);
        }
    
        @Override
        public boolean onCreateOptionsMenu(Menu menu) {
            // Inflate the menu; this adds items to the action bar if it is present.
            getMenuInflater().inflate(R.menu.list_contacts, menu);
            return true;
        }
    }
    

    contacts_list_view.xml:
    <?xml version="1.0" encoding="utf-8"?>
    <ListView xmlns:android="http://schemas.android.com/apk/res/android"
              android:id="@android:id/list"
              android:layout_width="match_parent"
              android:layout_height="match_parent"/>
    

    所以我的问题是,对于findViewById找不到我的 View ,我做错了什么?

    我尝试过的事情(这些问题中的大多数都是可以接受的答案,几乎看起来像是与此问题的重复):
  • 逐字阅读我复制并粘贴的文档。
  • 尝试将getView().findViewById()作为建议的in this question。这也将返回null。
  • 使用findViewById(R.id.contacts_list_view);代替this answer建议。这不会返回null;它不会返回null。相反,它导致ClassCastException,因为android.support.v4.app.NoSaveStateFrameLayout无法转换为android.widget.ListView
  • 我读到,有时将用于创建的 fragment 回调发生在将其附加到 Activity 之前。因此,我将处理程序添加到onAttach方法中,如下所示:
    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
    
        View mContactsListView = activity.findViewById(R.id.contacts_list_view);
        mContactsList = (ListView) mContactsListView;
    
        // Gets a CursorAdapter
        mCursorAdapter = new SimpleCursorAdapter(
                getActivity(),
                R.layout.contacts_list_item,
                null,
                FROM_COLUMNS, TO_IDS,
                0);
        // Sets the adapter for the ListView
        mContactsList.setAdapter(mCursorAdapter);
    
        // Set the item click listener to be the current fragment.
        mContactsList.setOnItemClickListener(this);
    }
    

    您猜对了-仍然为空。

  • 所以在这一点上我有点迷茫。我有两个问题:
  • 我在做什么错(如果我没有提供足够的信息,请在注释中请求其他信息)?
  • 是否最好将适配器设置保留在onAttach或本教程说的地方。
  • 最佳答案

    我遵循developer.android.com上的教程,遇到了同样的问题。

    最后,我注意到这一部分:

    // Gets the ListView from the View list of the parent activity
        mContactsList = (ListView) getActivity().findViewById(R.layout.contact_list_view);
    

    似乎试图找到View,但是将Layout id传递为参数。

    View | android reference说:



    因此,我将ListView id中的contacts_list_view.xml更改为唯一的:
    <?xml version="1.0" encoding="utf-8"?>
    <ListView ...
    android:id="@+id/contacts_listview_a_unique_id_here"
    ... />
    

    然后尝试通过以下方式找到它:
            mContactsList = (ListView) getActivity().findViewById(R.id.contacts_listview_a_unique_id_here);
    

    并且可以正常工作(在onActivityCreated回调中)。
  • 关于强制转换异常:
    hierarchyviewer所示,树是这样的:

    因此,如果findViewById传递了 View 的根元素,例如that post,它将返回NoSaveStateFrameLayout,而不是您想要的子ListView
  • 10-07 19:27
    查看更多