getActivity()。findViewById返回null,从片段onActivityCreated调用

时间:2013-08-01 20:51:17

标签: android android-fragments android-activity android-xml

我关注contacts provider lesson on retrieving contacts并使用片段显示它们。作为参考,我已将API级别设置为16(Android 4.1)。

除了一些值得注意的例外,我大部分都遵循了本教程。例如,我从mypackage.R而不是android.R导入。

我的问题出在我onActivityCreated的{​​{1}}处理程序中:

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无效。

我的父活动是eclipse创建的默认活动。对此,我做了两件事:

  1. findViewById替换为import android.app.Activity,以阻止android.support.v4.app.FragmentActivity发生的情况。
  2. 将我的片段导入XML。
  3. 我的ClasscastException看起来像这样:

    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>
    

    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"/> 没有找到我的观点,我做错了什么?

    我尝试过的事情(其中大部分是对几乎看起来像这个问题重复的问题的接受答案):

    • 阅读我逐字复制和粘贴的文件。
    • 按照建议in this question尝试findViewById。这也会返回null。
    • 使用getView().findViewById()代替this answer建议。这不会返回null;相反,它导致findViewById(R.id.contacts_list_view);导致ClassCastException无法转换为android.support.v4.app.NoSaveStateFrameLayout
    • 我读到有时创建的片段回调在附加到活动之前发生。所以,我将处理程序添加到android.widget.ListView方法中,如下所示:

      onAttach

      你猜对了 - 仍然是空的。

    所以在这一点上我有点失落。我有两个问题:

    1. 我做错了什么(如果我没有提供足够的信息,请在评论中请求其他信息)?
    2. 是否最好将适配器设置保留在@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); } 或教程所说的位置。

4 个答案:

答案 0 :(得分:11)

我按照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说:

  

视图ID在整个树中不一定是唯一的,但最好确保它们在您正在搜索的树的部分内至少是唯一的。

所以,我将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所示,树是这样的: hierarchyviewer sc 因此,如果findViewById传递视图的根元素,就像在that post中一样,它将返回NoSaveStateFrameLayout,而不是您想要的子ListView

答案 1 :(得分:2)

getActivity().findViewById()Activity的视图层次结构中查找您提供的ID作为参数。可能ListView由您的片段的onCreateView返回。如果要在片段视图层次结构上执行findViewById,则必须调用getView().findViewById()。在这种情况下,由于您要延长ListFragment,以检索ListView,与ListActivity一样,您必须使用getListView();ListActivity的另一个类比是xml文件(ListView

android:id="@android:id/list"的id

答案 2 :(得分:1)

请注意,ListFragment有一个getListView()方法可以返回ListView窗口小部件实例。

开发人员文档:ListFragment.getListView

答案 3 :(得分:0)

@theme提出了一个解决方案,但是为了使用android的内部列表视图,这是另一种方式。因为在你的&#34; contacts_list_view.xml&#34;使用android的内部列表视图和id = @android:id / list提交你的文件。在您的代码中,您可以使用findViewById(android.R.id.list)引用列表视图,因此您的onActivityCreated将是这样的:

public void onActivityCreated(Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);
    mContactsList = (ListView) getActivity().findViewById(android.R.id.list);//(R.layout.fragment_contact_list);
    mCursorAdapter = new SimpleCursorAdapter(getActivity(), R.layout.contact_item_list,null, FROM_COLUMNS, TO_IDS, 0);
    mContactsList.setAdapter(mCursorAdapter);
    mContactsList.setOnItemClickListener(this);
    getLoaderManager().initLoader(0,null,this);
}

希望它有所帮助,Android开发人员指南包含这样的&#34; bug&#34;这样我们就可以熟悉api。