Ответ 1
который возвращает null
Возможно потому, что вы называете это слишком рано. Подождите, пока onFinishInflate()
. Вот пример проекта, демонстрирующий пользовательский View
доступ к его содержимому.
Прежде всего: да, я прочитал все другие темы по этой теме. И не только из этого сайта... (вы видите, я немного расстроен)
Большинство из них приходят с советом использовать 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
.
Затем я изменил свой пользовательский вид, чтобы расширить ViewGroup
вместо View
и изменил location_layout.xml
, чтобы TextView
был прямым дочерним элементом моего пользовательского представления, так что View.findViewById
должен работать как предполагаемый, Suprise: он ничего не решал.
Так что, черт возьми, я делаю неправильно?
Я буду благодарен за любые комментарии.
который возвращает null
Возможно потому, что вы называете это слишком рано. Подождите, пока onFinishInflate()
. Вот пример проекта, демонстрирующий пользовательский View
доступ к его содержимому.
Возможно, вы вызываете findViewById
перед вызовом setContentView
?
В этом случае попробуйте позвонить findViewById
ПОСЛЕ, вызвав setContentView
Убедитесь, что у вас нет нескольких версий макета для разных плотностей экрана. Однажды я столкнулся с этой проблемой при добавлении нового идентификатора в существующий макет, но забыл обновить версию hdpi. Если вы забудете обновить все версии файла макета, он будет работать для некоторых плотностей экрана, но не для других.
В моем случае у меня было 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);
Я заметил это после того, как приехал сюда, на сайт.
Помимо классических причин, упомянутых в другом месте:
setContentView()
до findViewById()
id
, который вы хотите, находится в представлении или макете, указанном в setContentView()
id
не случайно дублируется в разных макетахЕсть один, который я нашел для пользовательских представлений в стандартных макетах, что противоречит документации:
В теории вы можете создать собственное представление и добавить его в макет (см. здесь). Однако я обнаружил, что в таких ситуациях иногда атрибут id
работает для всех представлений в макете, кроме настраиваемых. Я использую следующее решение:
FrameLayout
теми же свойствами макета, что и для пользовательского представления. Дайте ему соответствующий id
, скажем frame_for_custom_view
.В onCreate
:
setContentView(R.layout.my_layout);
FrameView fv = findViewById(R.id.frame_for_custom_layout);
MyCustomView cv = new MyCustomView(context);
fv.addView(cv);
который помещает пользовательский вид в фрейм.
FindViewById может быть пустым, если вы вызываете неправильный суперконструктор в пользовательском представлении. Тег ID является частью attrs, поэтому, если вы игнорируете attrs, вы удаляете ID.
Это было бы неправильно
public CameraSurfaceView(Context context, AttributeSet attrs) {
super(context);
}
Это правильно.
public CameraSurfaceView(Context context, AttributeSet attrs) {
super(context,attrs);
}
@Override
protected void onStart() {
// use findViewById() here instead of in onCreate()
}
Ответ для тех, кто использует 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);
}
Я нашел здесь здесь.
Я новичок в Android/Eclipse, по ошибке я добавил материал UI в activity_main.xml
вместо fragment_main.xml
. Принял меня несколько часов, чтобы понять, что...
FWIW, я не вижу, чтобы кто-то решил это так же, как мне было нужно. Никаких жалоб во время компиляции, но я получал нулевой вид во время выполнения и вызывал вещи в правильном порядке. То есть, findViewById() после setContentView(). Проблема оказалась в том, что мое представление определено в content_main.xml, но в моем activity_main.xml мне не хватало этого одного утверждения:
<include layout="@layout/content_main" />
Когда я добавил, что для activity_main.xml, больше нет NullPointer.
В моем конкретном случае я пытался добавить нижний колонтитул в ListView. Следующий вызов в onCreate() возвращал значение null.
TextView footerView = (TextView) placesListView.findViewById(R.id.footer);
Изменив это, чтобы раздуть представление нижнего колонтитула вместо того, чтобы найти его по идентификатору, была решена эта проблема.
View footerView = ((LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE)).inflate(R.layout.footer_view, null, false);
В моем случае ничего подобного нет, никаких решений не было. Я предполагаю, что мой взгляд был слишком глубоким в иерархии компоновки. Я переместил его на один уровень, и он больше не был нулевым.
В моем случае я использовал ExpandableListView, и я установил android:transcriptMode="normal"
. Это привело к тому, что несколько детей в расширяемой группе исчезли, и я использовал исключение NULL, когда когда-либо использовал прокрутку списка.
Для меня у меня было два xml-макета для одной и той же активности - один в портретном режиме и один в ландшафте. Конечно, я изменил идентификатор объекта в ландшафтном xml, но забыл сделать такое же изменение в портретной версии. Убедитесь, что если вы изменили один, вы сделаете то же самое с другим xml или вы не получите сообщение об ошибке, пока не запустите/отлаживаете его, и он не сможет найти идентификатор, который вы не изменили. О, глупые ошибки, почему ты так меня наказываешь?
Задайте содержимое активности из ресурса макета.
т.е. setContentView(R.layout.basicXml)
;.
У меня была такая же проблема. Я использовал стороннюю библиотеку, которая позволяет переопределить их адаптер для GridView и указать собственный макет для каждой ячейки GridView.
Наконец я понял, что происходит. Eclipse все еще использовал XML файл библиотеки для каждой ячейки в GridView, хотя он не дал никаких указаний на это. В моем пользовательском адаптере он указал, что он использует ресурс xml из моего собственного проекта, хотя во время выполнения он не был.
Так что я сделал, чтобы убедиться, что мои собственные макеты xml и идентификаторы отличаются от тех, которые все еще сидят в библиотеке, очистили проект, а затем начали читать правильные пользовательские макеты, которые были в моем проекте.
Короче говоря, будьте осторожны, если вы переопределяете сторонний адаптер библиотеки и указываете свой собственный макет xml для использования адаптером. Если ваш макет внутри вашего проекта имеет то же имя файла, что и в библиотеке, вы можете столкнуться с действительно сложной ошибкой!
В дополнение к вышеуказанным решениям вы убедитесь, что
tools:context=".TakeMultipleImages"
в макете такое же значение в файле mainfest.xml: android:name=".TakeMultipleImages"
для одного и того же элемента активности.
это происходит при использовании копирования и вставки для создания новой активности.
У меня та же проблема, но я думаю, что ее стоит поделиться с вами, ребята. Если вам нужно findViewById в пользовательском макете, например:
public class MiniPlayerControllBar extends LinearLayout {
//code
}
вы не можете получить представление в конструкторе.
Вы должны вызвать findViewById после того, как просмотр завышен.
Их метод можно переопределить onFinishInflate
Просто хотел бросить здесь свой конкретный случай. Может помочь кому-то по очереди.
Я использовал эту директиву в своем Android-интерфейсе Android следующим образом:
Родительский вид:
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:tag="home_phone"
android:background="@color/colorPrimary">
...
<include
layout="@layout/retry_button"
android:visibility="gone" />
Детский вид (retry_button):
<com.foo.RetryButton
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/retry"
android:layout_gravity="center"
android:orientation="vertical"
android:layout_width="100dp"
android:layout_height="140dp">
.findViewById(R.id.retry) всегда возвращает null. Но, если я переместил идентификатор из дочернего представления в тег include, он начал работать.
Фиксированный родительский элемент:
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:tag="home_phone"
android:background="@color/colorPrimary">
...
<include
layout="@layout/retry_button"
android:id="@+id/retry"
android:visibility="gone" />
Исправлено:
<com.foo.RetryButton
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_gravity="center"
android:orientation="vertical"
android:layout_width="100dp"
android:layout_height="140dp">
В моем случае я раздул макет, но дочерние представления возвращали значение null. Первоначально у меня было это:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_history);
footerView = ((LayoutInflater) getApplicationContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE)).inflate(R.layout.listview_footer, null, false);
pbSpinner = (ProgressBar) findViewById(R.id.pbListviewFooter);
tvText = (TextView) findViewById(R.id.tvListviewFooter);
...
}
Однако, когда я изменил его на следующее, он работал:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_history);
footerView = ((LayoutInflater) getApplicationContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE)).inflate(R.layout.listview_footer, null, false);
pbSpinner = (ProgressBar) footerView.findViewById(R.id.pbListviewFooter);
tvText = (TextView) footerView.findViewById(R.id.tvListviewFooter);
...
}
Ключ должен был специально ссылаться на уже раздутый макет, чтобы получить дочерние представления. То есть, добавьте footerView
:
Я пробовал все выше, ничего не работает. Поэтому мне пришлось сделать мой ImageView static public static ImageView texture;
, а затем texture = (ImageView) findViewById(R.id.texture_back);
, я не думаю, что это хороший подход, хотя но это действительно сработало для моего случая:)
По моему опыту, похоже, что это также может произойти, когда ваш код вызывается после OnDestroyView (когда фрагмент находится в фоновом стеке.) Если вы обновляете пользовательский интерфейс на входе от BroadCastReceiver, вы должны проверить, в этом случае.
ОГРАНИЧИВАЙТЕ СРОК!! (который содержит идентификатор)
В моем случае findViewById() возвратил null, потому что макет, в котором был написан элемент, не был завышен...
Eg. fragment_layout.xml
<ListView
android:id="@+id/listview">
findViewById (R.id.listview) возвращает null, потому что я не сделал inflater.inflate(R.layout.fragment_layout,...,...); перед этим.
Надеюсь, что этот ответ поможет некоторым из вас.
Мое решение состояло в том, чтобы просто очистить проект.
findViewById также может возвращать значение null, если вы находитесь внутри фрагмента. Как описано здесь: findViewById in Fragment
Вы должны вызвать getView(), чтобы вернуть верхний уровень просмотра внутри фрагмента. Затем вы можете найти элементы макета (кнопки, текстовые изображения и т.д.)
В моем случае findViewById вернул null, когда я переместил вызов из родительского объекта в объект адаптера, созданный родителем. После безуспешных попыток, перечисленных здесь, я переместил findViewById обратно в родительский объект и передал результат в качестве параметра во время создания объекта адаптера. Например, я сделал это в родительском объекте:
Spinner hdSpinner = (Spinner)view.findViewById(R.id.accountsSpinner);
Затем я передал hdSpinner в качестве параметра при создании объекта адаптера:
mTransactionAdapter = new TransactionAdapter(getActivity(),
R.layout.transactions_list_item, null, from, to, 0, hdSpinner);
Сбой произошел из-за того, что одно из полей в идентификаторе моей активности совпадало с идентификатором в другой активности. Я исправил это, дав уникальный идентификатор.
В моем поле ввода пароля loginActivity.xml идентификатор был "пароль". В своей регистрационной активности я просто исправил это, указав идентификатор r_password, после чего он вернул ненулевой объект:
password = (EditText)findViewById(R.id.r_password);