findViewByID возвращает ноль - PullRequest
233 голосов
/ 16 июля 2010

Прежде всего: да, я читаю все остальные темы по этой теме.И не только с этого сайта ... (видите, я немного расстроен)

Большинство из них приходят с рекомендацией использовать android:id вместо просто id в файле XML.Я сделал.

От других я узнал, что View.findViewById работает не так, как Activity.findViewById.Я тоже с этим справился.

В моем location_layout.xml я использую:

<FrameLayout .... >
    <some.package.MyCustomView ... />

    <LinearLayout ... >
        <TextView ...
            android:id="@+id/txtLat" />
        ...
    </LinearLayout>
</FrameLayout>

В своей деятельности я делаю:

...
setContentView( R.layout.location_layout );

и в моем собственном представлениикласс:

... 
TextView tv = (TextView) findViewById( R.id.txtLat );

, который возвращает null. При этом моя активность работает нормально. Так что, возможно, это из-за различий Activity.findViewById и View.findViewById.Поэтому я сохранил контекст, переданный конструктору обычного представления, и попытался:

...
TextView tv = (TextView) ((Activity) context).findViewById( R.id.txtLat );

, который также возвратил null.

Затем я изменил свой пользовательский вид, чтобы вместо него расширить ViewGroupView и изменил location_layout.xml, чтобы TextView был прямым потомком моего пользовательского представления, чтобы View.findViewById работал так, как предполагалось.Сюрприз: это ничего не решило.

Так какого чёрта я делаю не так?

Буду благодарен за любые комментарии.

Ответы [ 28 ]

251 голосов
/ 16 июля 2010

, который возвращает ноль

Возможно, потому что вы звоните слишком рано. Подождите, пока onFinishInflate(). Вот пример проекта , демонстрирующий пользовательский View доступ к его содержимому.

138 голосов
/ 17 ноября 2011

Возможно, вы звоните findViewById, прежде чем позвонить setContentView?Если это так, попробуйте позвонить findViewById ПОСЛЕ , позвонив setContentView

96 голосов
/ 05 ноября 2011

Убедитесь, что у вас нет нескольких версий макета для разных плотностей экрана.Я столкнулся с этой проблемой один раз при добавлении нового идентификатора в существующий макет, но забыл обновить версию hdpi.Если вы забудете обновить все версии файла макета, он будет работать для некоторых плотностей экрана, но не для других.

15 голосов
/ 14 января 2013

В моем случае в моем проекте было 2 актива, main.xml и main2.xml. С самого начала main2 была копией main, и все работало хорошо, пока я не добавил новый TextView к main2, поэтому R.id.textview1 стал доступен для остальной части приложения. Затем я попытался получить его стандартным вызовом:

TextView tv = (TextView) findViewById( R.id.textview1 );

и оно всегда было нулевым. Оказалось, что в конструкторе onCreate я создавал не main2, а другой. Я имел:

setContentView(R.layout.main);

вместо

setContentView(R.layout.main2);

Я заметил это после того, как приехал сюда, на сайт.

13 голосов
/ 02 июня 2015

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

Это было бы неправильно

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

Это правильно

public CameraSurfaceView(Context context, AttributeSet attrs) {
        super(context,attrs);
}
13 голосов
/ 20 декабря 2014

Наряду с классическими причинами, упомянутыми в другом месте:

  • Убедитесь, что вы звонили setContentView() до findViewById()
  • Убедитесь, что нужный номер id находится ввид или макет, который вы дали setContentView()
  • Убедитесь, что id случайно не продублирован в разных макетах

Я нашел один для пользовательскоговиды в стандартных макетах, что противоречит документации:

Теоретически вы можете создать собственный вид и добавить его в макет ( см. здесь ).Однако я обнаружил, что в таких ситуациях иногда атрибут id работает для всех представлений в макете, кроме пользовательских.Решение, которое я использую:

  1. Замените каждое настраиваемое представление на FrameLayout с теми же свойствами макета, которые вы хотели бы иметь в настраиваемом представлении.Дайте ему соответствующий id, скажем frame_for_custom_view.
  2. In onCreate:

    setContentView(R.layout.my_layout);
    FrameView fv = findViewById(R.id.frame_for_custom_layout);
    MyCustomView cv = new MyCustomView(context);
    fv.addView(cv);
    

    , который помещает пользовательский вид в рамку.

8 голосов
/ 18 июня 2014
    @Override
protected void onStart() {
         // use findViewById() here instead of in onCreate()
    }
6 голосов
/ 24 января 2012

Ответ для тех, кто использует ExpandableListView и сталкивается с этим вопросом на основе его названия.

У меня была эта ошибка при попытке работать с TextViews в моем дочернем и групповом представлениях как часть реализации ExpandableListView.

Вы можете использовать что-то вроде следующего в ваших реализациях методов getChildView () и getGroupView ().

        if (convertView == null) {
            LayoutInflater inflater =  (LayoutInflater) myContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            convertView = inflater.inflate(R.layout.child_layout, null);
        }

Я нашел это здесь .

5 голосов
/ 22 апреля 2014

Я довольно новичок в Android / Eclipse, по ошибке я добавил пользовательский интерфейс в activity_main.xml вместо fragment_main.xml.Мне понадобилось несколько часов, чтобы понять это ...

4 голосов
/ 09 июля 2016

FWIW, я не вижу, чтобы кто-то решал это так же, как мне было нужно.Никаких жалоб во время компиляции, но я получал нулевое представление во время выполнения и вызывал вещи в правильном порядке.То есть findViewById () после setContentView ().Проблема оказалась в том, что мое представление определено в content_main.xml, но в моем activity_main.xml мне не хватало одного утверждения:

<include layout="@layout/content_main" />

Когда я добавил это в activity_main.xml, больше не было NullPointer.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...