Конфликт идентификаторов извлекаемых ресурсов Android?

#android #resources #android-activity #zxing

#Android #Ресурсы #android-активность #zxing

Вопрос:

Я настроил проект / android ZXing 1.7 в качестве библиотеки, на которую ссылается мой основной проект приложения для Android. В качестве быстрого теста / подтверждения концепции я использовал CaptureActivity таким же образом, как описано здесь: http://damianflannery.wordpress.com/2011/06/13/integrate-zxing-barcod

В основном все работает хорошо, я могу запустить CaptureActivity и получить отсканированные данные в моей активности, которая ее запустила. Однако я получаю какое-то действительно странное поведение, которое, я думаю, может быть связано с конфликтом идентификаторов ресурсов между моим проектом и проектом / android ZXing. Это потребует некоторых объяснений, поэтому, пожалуйста, потерпите меня…

Я запускаю CaptureActivity с помощью этого кода:

 Button scanBtn = (Button)findViewById(R.id.mainmenu_btn_scan); 
scanBtn.setOnClickListener( 
    new View.OnClickListener() 
{ 
    public void onClick(View v) 
    { 
        Intent i = new Intent("com.google.zxing.client.android.SCAN"); 
        i.putExtra("SCAN_MODE", "QR_CODE_MODE"); 
        startActivityForResult(i, SCAN_CODE); 
    } 
}); 
  

mainmenu_btn_scan определяется в menu.xml:

 <LinearLayout android:id="@ id/mainmenu_view" style="@style/MainMenu" xmlns:android="http://schemas.android.com/apk/res/android">
    ...
    <Button android:id="@ id/mainmenu_btn_scan" 
                    android:drawableTop="@drawable/btn_scan_drawable" 
                    style="@style/MainMenuButton" 
                    android:text="Scan"/>
    ... 
</LinearLayout> 
  

btn_scan_drawable.xml находится в /drawable и является drawable селектором:

 <selector xmlns:android="http://schemas.android.com/apk/res/android"> 
    <item android:drawable="@drawable/scan_btn_pressed" android:state_focused="true" android:state_pressed="true" /> 
    ...
</selector>
  

Проблема заключается в следующем: когда я держу телефон в горизонтальной
ориентации и запускаю CaptureActivity, я вижу, что
изображение scan_btn_pressed растягивается по экрану, а другая его копия также
растягивается на «Поместите штрих-код внутри текста прямоугольника видоискателя
…». Это происходит только тогда, когда я запускаю действие во времяудерживая
телефон в альбомной ориентации.

Я обнаружил, что если я заменю

 android:drawableTop="@drawable/btn_scan_drawable" 
  

с

 android:drawableTop="@drawable/scan_btn_pressed"
  

Проблема исчезает, и все работает отлично, но я хочу заставить его работать с селектором (и понять, почему возникает проблема). Как объект рисования из
пользовательского интерфейса моего действия может таинственным образом отображаться в другом действии? Я новичок в разработке Android, но я весь день гуглил и работал над этой проблемой, и, похоже, я не могу понять, почему это происходит, кроме некоторых расплывчатых ссылок на конфликты идентификаторов ресурсов в документах Android.

Примечание: я использую CaptureActivity только в качестве быстрого прототипа / подтверждения концепции. Я буду реализовывать свою собственную деятельность, используя библиотеку ZXing для конечного приложения.

Ответ №1:

Хорошо, похоже, что платформа Android имеет несколько недостатков при использовании библиотечных проектов. Я заметил, что класс R моего проекта и класс R проекта библиотеки ZXing повсеместно конфликтуют, например

 public static final class id {
    ...
    public static final int mainmenu_btn_scan=0x7f070028;
    ...
  

И в классе R проекта библиотеки:

 public static final class id {
    ...
    public static final int share_app_button=0x7f070028;
    ...
  

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

Эта отличная статья дала решение: http://blog.blackmoonit.com/2010/12/android-sharing-resources-in-eclipse.html

В CaptureActivity (действие, которое я вызывал в библиотеке) я заменил

 viewfinderView = (ViewfinderView) findViewById(R.id.viewfinder_view);
  

С помощью этого

 viewfinderView = (ViewfinderView) findViewById(
    getResources().getIdentifier("viewfinder_view", "id", getPackageName()) );
  

Это устранило проблему, хотя мне нужно будет просмотреть и заменить все прямые ссылки на идентификаторы на getIndentifier(), чтобы убедиться, что других конфликтов нет. Не идеальное решение. Похоже, что должно быть какое-то довольно простое расширение для инструмента aapt, чтобы гарантировать, что идентификаторы между R-классами не конфликтуют.

Смотрите здесь для получения дополнительной информации: http://devmaze.wordpress.com/2011/05/22/android-application-android-libraries-and-jar-libraries /

Комментарии:

1. Я думаю, что это обходное решение — вы также можете просто импортировать правильный R или использовать свой.package.R.id.viewfinder_view для дифференциации. Это скорее вопрос импорта Java. Это также подчеркивает проблему повторного использования проекта, который не предназначен для копирования, а не как проект библиотеки.

2. Я так не думаю, реальная проблема заключается в том, что в идентификаторах в классах R есть коллизии. com.somelib.R.share_app_button == com.myapp.R.mainmenu_btn_scan используется правильный файл R, но из-за коллизий и правил приоритета ресурсов Android,идентификаторы файлов библиотеки R в конечном итоге ссылаются на ресурсы в моем приложении.

3. @SeanOwen: конфликт идентификаторов ресурсов возникает из-за того, что нескольким ресурсам в разных проектах сопоставляется одно и то же целочисленное значение идентификатора. Не имеет значения, указываете ли вы в своем Java-коде имя пакета или нет — они сопоставляются с одним и тем же значением. Когда среде выполнения Android присваивается целочисленное значение идентификатора для поиска чего-либо, у нее нет информации, которая помогла бы разрешить конфликт, и поэтому она может следовать только предопределенным правилам приоритета ресурсов, которые во многих случаях приводят к неправильному результату.

Ответ №2:

использовать project->clean.. для регенерации R класса