Как использовать повторяющиеся идентификаторы в разных макетах?

У меня есть два разных макета для двух разных видов деятельности. В каждом из этих макетов есть кнопка с одним и тем же идентификатором: "@+ id/btnOK". Когда я устанавливаю свойство для одной из этих кнопок программно, я получаю NullPointerException. Но когда я меняю один из идентификаторов, все в порядке.

Действительно ли это, что мы не можем иметь повторяющиеся идентификаторы в разных макетах в android?

Ответ 1

В разделе "Дублирующие идентификаторы в макетах", извлеченном из разработчиков Android

Определение идентификаторов для объектов просмотра важно при создании RelativeLayout. В относительной компоновке представления sibling могут определять их компоновку относительно другого представления sibling, на которое ссылается уникальный идентификатор.

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

Это означает, что разные макеты могут объявлять идентичные идентификаторы, но это не лучшая практика.

Ответ 2

Я предполагаю, что в классе R.java возникнет проблема, так как этот класс будет иметь общедоступные статические элементы, соответствующие каждому View id.

Чтобы работать, класс R.java должен был бы переименовать некоторые из этих идентификаторов, а затем как вы их найдете?

Ответ 3

У вас могут быть одинаковые идентификаторы, но они должны быть в разных макетах. Тот же макет не может обрабатывать повторяющиеся идентификаторы. Я взял два макета, так как вы имели кнопки, имеющие "btn". Я вызываю Activity2 с newxml.xml из Activity1 с main.xml.

Вот мой код:

main.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <Button
        android:id="@+id/btn"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Next" />

</LinearLayout>

Activity1:

setContentView(R.layout.main);

Button button=(Button) findViewById(R.id.btn);
button.setOnClickListener(new OnClickListener() {

        @Override
        public void onClick(View v) {
            Intent intent=new Intent(Activity1.this,Activity2.class);
            startActivity(intent);
        }
    });

newxml:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <Button 
        android:id="@+id/btn"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Previous"/>

</LinearLayout>

деятельности2:

setContentView(R.layout.newxml);

Button button=(Button) findViewById(R.id.btn);
button.setOnClickListener(new OnClickListener() {

    @Override
    public void onClick(View v) {
        finish();
    }
});

Ответ 4

Я решил проблему, но я не нашел причины. В моем файле манифеста один из видов деятельности имел "android: label =" @string/app_name ". Я удалил его и установил для своего основного действия.

Предыдущий манифест:

<activity android:name=".ui.ActLogin">
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
</activity>
<activity android:name=".ui.ActTest" android:label="@string/app_name">
</activity>

Новый манифест:

<activity android:label="@string/app_name" android:name=".ui.ActLogin">
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
</activity>
<activity android:name=".ui.ActTest">
</activity>

Кто-нибудь знает причину?

Ответ 5

Для меня вполне нормально (и иногда вполне естественно) использовать дубликаты идентификаторов, если вы делаете это правильно: вместо Activity.findViewById() которая всегда возвращает первое совпадающее представление, используйте ViewGroup.findViewById() (ViewGroup может быть LinearLayout, FrameLayout т.д.), FrameLayout возвращает представление в группе представлений.

Чтобы избежать появления ворса:

  1. (Предпочитается) Поместите содержимое ViewGroup в отдельный макет XML и используйте

      <include layout="@layout/myLayout" android:id="@+id/specificId" />
    

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

  2. Отключите предупреждение Lint для проекта, сняв флажок "Дублировать идентификаторы в одном макете" в *Settings/Editor/Inspections*