FindViewById() возвращает null для настраиваемого компонента в макете XML, а не для других компонентов - программирование
Подтвердить что ты не робот

FindViewById() возвращает null для настраиваемого компонента в макете XML, а не для других компонентов

У меня есть res/layout/main.xml, включая эти элементы и другие:

<some.package.MyCustomView android:id="@+id/foo" (some other params) />
<TextView android:id="@+id/boring" (some other params) />

В моей работе onCreate я делаю это:

setContentView(R.layout.main);
TextView boring = (TextView) findViewById(R.id.boring);
// ...find other elements...
MyCustomView foo = (MyCustomView) findViewById(R.id.foo);
if (foo == null) { Log.d(TAG, "epic fail"); }

Другие элементы найдены успешно, но foo возвращается в нуль. MyCustomView имеет конструктор MyCustomView(Context c, AttributeSet a), а Log.d(...) в конце этого конструктора успешно появляется в logcat как раз перед "эпическим сбоем".

Почему foo null?

4b9b3361

Ответ 1

Потому что в конструкторе у меня был super(context) вместо super(context, attrs).

Имеет смысл, если вы не передадите атрибуты, такие как идентификатор, то представление не будет иметь идентификатора и, следовательно, не будет найдено с использованием этого идентификатора.: -)

Ответ 2

У меня была та же проблема. Моя ошибка заключалась в следующем: я написал

        LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        View layout=inflater.inflate(R.layout.dlg_show_info, null);
        alertDlgShowInfo.setView(layout);
        TableRow trowDesc=(TableRow)findViewById(R.id.trowDesc);

и поскольку я использовал надуватель для "загрузки" представления из файла XML, последняя строка была неправильной. Чтобы решить эту проблему, мне пришлось написать:

TableRow trowDesc=(TableRow)layout.findViewById(R.id.trowDesc);

Я написал свое решение, если у кого-то такая же проблема.

Ответ 3

Похоже, есть множество причин. Я просто использовал "Clean..." в Eclipse, чтобы решить аналогичную проблему. (FindViewByID работал раньше и по какой-то причине начал возвращать null.)

Ответ 4

У меня такая же проблема, потому что в моем пользовательском представлении я переопределял конструктор, но вызывал суперконтрактор с параметром attrs. Это скопировать пасту)

Моя предыдущая версия конструктора:

    public TabsAndFilterRelativeLayout(Context context, AttributeSet attrs) {
            super(context);
}

Теперь у меня есть:

    public TabsAndFilterRelativeLayout(Context context, AttributeSet attrs) {
            super(context, attrs);}

И это работает!

Ответ 5

Такая же проблема, но другое решение: я не звонил

setContentView(R.layout.main)

ПЕРЕД Я попытался найти представление, как указано здесь

Ответ 6

Если у вас несколько версий макета (в зависимости от плотности экрана, версии SDK), убедитесь, что все они включают элемент, который вы ищете.

Ответ 7

В моем случае findViewById возвращал значение null, потому что мой пользовательский вид выглядел примерно так в основном XML:

        <com.gerfmarquez.seekbar.VerticalSeekBar  
            android:id="@+id/verticalSeekBar"
            android:layout_width="wrap_content" 
            android:layout_height="fill_parent" 
            />

и я узнал, что когда я добавил материал xmlns, он работал следующим образом:

        <com.gerfmarquez.seekbar.VerticalSeekBar  
            xmlns:android="http://schemas.android.com/apk/res/android"
            android:id="@+id/verticalSeekBar"
            android:layout_width="wrap_content" 
            android:layout_height="fill_parent" 
            />

Ответ 8

Убедитесь, что оператор setContentView(R.layout.main) вызывается перед оператором findViewById(...);

Ответ 9

Для меня проблема была решена, когда я добавил папку res в Source в пути сборки Java в настройках проекта.

Ответ 10

Я столкнулся с тем же вопросом некоторое время назад, когда добавил пользовательский вид через макет XML и затем попытался подключить обратный вызов в другом месте приложения...

Я создал пользовательский вид и добавил его в свой "layout_main.xml"

public class MUIComponent extends SurfaceView implements SurfaceHolder.Callback {
    public MUIComponent (Context context, AttributeSet attrs ) {
        super ( context, attrs );
    }
    // ..
}

И в основном мероприятии я хотел добавить некоторые обратные вызовы и получить ссылки на элементы пользовательского интерфейса из XML.

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // ...

        MUIInitializer muiInit = new MUIInitializer();
        muiInit.setupCallbacks(this);
        muiInit.intializeFields(this);
    }       
}

Инициатор не делал ничего необычного, но любые изменения, которые он пытался сделать для пользовательского представления (MUIComponent) или другие нестандартные элементы пользовательского интерфейса просто не появлялись в приложении.

public class MUIInitializer {

    // ...

    public void setupCallbacks ( Activity mainAct ) {


        // This does NOT work properly
        // - The object instance returned is technically an instance of my "MUICompnent" view
        //   but it is a *different* instance than the instance created and shown in the UI screen
        // - Callbacks never get triggered, changes don't appear on UI, etc.
        MUIComponent badInst = (MUIComponent) mainAct.findViewById(R.id.MUIComponent_TESTSURF);


        // ...
        // This works properly

        LayoutInflater inflater = (LayoutInflater) mainAct.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        View inflatedLayout = inflater.inflate ( R.layout.activity_main, null );

        MUIComponent goodInst = (MUIComponent) inflatedLayout.findViewById(R.id.MUIComponent_TESTSURF);


        // Add callbacks
        // ...
    }

}

Разница между "badInst" и "goodInst" заключается в следующем:

  • badInst использует Activity findViewByID
  • goodInst раздувает макет и использует раздутый макет для поиска

Ответ 11

Это случилось со мной с пользовательским компонентом для Wear, но это общий совет. Если вы используете Stub (например, я использовал WatchViewStub), вы не можете просто поместить вызов findViewById() в любом месте. Сначала необходимо завысить все внутри заглушки, что происходит не только после setContentView(). Таким образом, вы должны написать что-то вроде этого, чтобы дождаться, когда это произойдет:

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_wear);
    final WatchViewStub stub = (WatchViewStub) findViewById(R.id.watch_view_stub);
    stub.setOnLayoutInflatedListener(new WatchViewStub.OnLayoutInflatedListener() {
        @Override
        public void onLayoutInflated(WatchViewStub stub) {
            myCustomViewInst = (MyCustomView) findViewById(R.id.my_custom_view);
            ...

Ответ 12

Моя проблема была опечаткой. Я написал android.id (точка) вместо android:id.: P

По-видимому, в моем настраиваемом компоненте xml нет синтаксической проверки.: (

Ответ 13

Имела ту же проблему.

У меня был макет с несколькими детьми. Из конструктора одного из них я пытался получить ссылку (используя context.findViewById) другому ребенку. Он не работал, потому что второй ребенок был дополнительно определен в макете.

Я решил это следующим образом:

setContentView(R.layout.main);
MyView first = findViewById(R.layout.first_child);
first.setSecondView(findViewById(R.layout.second_child));

Это сработало бы, если бы порядок детей был противоположным, но я думаю, что это обычно должно быть сделано, как указано выше.

Ответ 14

Метод findViewById() иногда возвращает null, когда корень макета не имеет атрибута android:id. Мастер Eclipse для генерации XML файла макета автоматически не генерирует атрибут android:id для корневого элемента.

Ответ 15

В моем случае представление было в родительском NOT в представлении, в котором я пытался его вызвать. Поэтому в дочернем представлении мне пришлось вызвать:

RelativeLayout relLayout = (RelativeLayout) this.getParent();
View view1 = relLayout.findViewById(R.id.id_relative_layout_search);

Ответ 16

"Чистый" вариант работал у меня.

В моем случае основная причина заключается в том, что исходный код находится в общем сетевом ресурсе, а моя рабочая станция и файловый сервер не были синхронизированы правильно и дрейфовали на 5 секунд. Временные метки файлов, созданных Eclipse, в прошлом (потому что они назначены файловым сервером) w.r.t. часы рабочей станции, заставляя Eclipse некорректно определять зависимости между сгенерированными и исходными файлами. В этом случае работает "чистый", потому что он заставляет полную перестройку вместо инкрементной сборки, которая зависит от неправильных временных меток.

Как только я исправил настройки NTP на своей рабочей станции, проблема никогда не возникала снова. Без правильных настроек NTP это произойдет каждые несколько часов, так как часы дрейфуют быстро.

Ответ 17

Чтобы добавить еще одну тривиальную ошибку в ответы:

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

Ответ 18

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