getActivity().findViewById возвращает значение null, вызываемое из фрагмента onActivityCreated

я после contacts provider урок по извлечению контактов и отображение их с помощью фрагментов. Для справки, я установил уровень API на 16 (Android 4.1).

я в основном следовал этому руководству до буквы, за несколькими заметными исключениями. Например, я импортирую из 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 равно null, что означает findViewById не получилось.

моя родительская активность по умолчанию создана eclipse. Для этого я сделал две вещи:--27-->

  1. заменить import android.app.Activity С android.support.v4.app.FragmentActivity предупреждения ClasscastException это произойдет, если вы этого не сделаете.
  2. импортировал мой фрагмент в 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>

соответствующая деятельность, на всякий случай:

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 не найти на мой взгляд?

вещи, которые я пробовал (большинство из них-принятые ответы на вопросы, которые почти похожи на дубликат этого):

  • чтение документа, который я скопировал и вставил из слова в слово.
  • пытается getView().findViewById() как было предложено в этом вопросе. Это также возвращает null.
  • используя findViewById(R.id.contacts_list_view); вместо этого, как полагают ответ. Это не возвращает null; вместо этого он вызывает ClassCastException в этой android.support.v4.app.NoSaveStateFrameLayout не может быть приведен к android.widget.ListView.
  • я читал, что иногда обратный вызов фрагмента для создания происходит до присоединения к действию. Итак, я добавил обработчик в 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);
    }
    

    вы догадались - все равно null.

так что в этот момент я немного потерялся. У меня два вопроса:--27-->

  1. что я делаю неправильно (пожалуйста, запросите дополнительную информацию в комментариях, если я не предоставил достаточно)?
  2. предпочтительнее оставить настройку адаптера в onAttach, или где говорится в учебнике.

4 ответов


Я следую учебнику по 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 в качестве аргумента.

на Посмотреть | ссылка на Android говорит :

идентификаторы просмотра не должны быть уникальными во всем дереве, но рекомендуется убедиться, что они по крайней мере уникальны внутри части дерева вы ищете.

Итак, я изменил 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 обратного вызова).

  • об исключении cast: As hierarchyviewer показывает, дерево выглядит так: hierarchyviewer sc так что если вы findViewById передача корневого элемента представления, как в этот пост, он вернется NoSaveStateFrameLayout, который не является ребенком ListView вы хотите.

getActivity().findViewById() ищет идентификатор в качестве параметра в иерархии видов Activity. Наверное ListView возвращается onCreateView ваш фрагмент. Если вы хотите выполнить findViewById в иерархии представлений фрагментов вы должны вызвать getView().findViewById(). В этом случае, так как вы расширяете ListFragment, чтобы получить ListView, а ListActivity, вы должны использовать getListView(); еще одна аналогия с ListActivity идентификатор ListView внутри xml-файла (android:id="@android:id/list")


отметим, что ListFragment есть getListView() метод, чтобы возвратить ListView экземпляра виджета.

разработчик документы: ListFragment.getListView


@theme предложить решение, но для того, чтобы использовать внутренний listview android вот еще один способ. Потому что в вашем " contacts_list_view.xml " файл вы используете внутренний listview android с id=@android:id/list - ... И в вашем коде вы можете обратиться к списку с помощью findViewById (android.R.id.список), поэтому ваш 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 содержит такую "ошибку", чтобы мы могли быть знакомы с api.