Статьи

Миграция с ActionBarSherlock на ActionBarCompat

В июле 2013 года Google анонсировала ActionBarCompat как часть своего пакета поддержки библиотеки. Эта библиотека облегчает использование панели действий, которая должна поддерживать старые устройства. Многие ждали, что это произойдет с тех пор, как была представлена ​​панель действий с Honeycomb.

Я, однако, не ожидал, что это произойдет. В конце концов, Action Bar был анонсирован давно, и у нас был ActionBarSherlock. Так почему же вдруг?

Я написал несколько сообщений о ActionBarSherlock в этом блоге до этого объявления. Эти посты по-прежнему привлекают много внимания и поисковых запросов. Но в то время как основные понятия все еще применяются, любые специфические части ActionBarSherloc устарели

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

Почему вы должны предпочитать ActionBarCompat вместо ActionBarSherlock

Есть много причин, почему вы должны предпочесть ActionbarCompat, а не ActionbarSherlock.

Прежде всего, этот проект от Google, является частью библиотеки поддержки и, таким образом, вероятно, будет поддерживать новые вещи, связанные с Action Bar, в то же время Google выпускает их со стандартным Android.

Еще одна веская причина и доказательство предыдущего пункта заключается в том, что ActionBarCompat поддерживает шаблон «Ящик навигации» прямо из коробки, а ActionBarSherlock — нет. Таким образом, если вы хотите добавить этот ящик в существующий проект / приложение, вы должны выполнить миграцию.

Последняя и не в последнюю очередь причина заключается в том, что создатель ActionBarSherlock Джейк Уортон объявил в Google+, что дальнейшее развитие ActionBarSherlock остановлено . ActionBarSherlock 4.4 является последним выпуском и может получить исправления ошибок, но новых функций не будет:

Несмотря на то, что в ближайшие недели может появиться один или несколько выпусков, версия 4.4 станет последней версией ™.

Он тоже не слишком огорчен.  Смотрите эту цитату, которую Джейк Уортон написал в своем блоге о том, что ActionBarSherlock должен быть в конечном итоге отброшен :

Это вся цель библиотеки. Он был специально разработан для этого случая использования. Он устарел с самого начала с намерением, что когда-нибудь вы сможете его выбросить.

Пример проекта

Чтобы продемонстрировать, как работает миграция, я перенес пример ActionViews проекта в ActionBarCompat. В этом примере проекта показано, как использовать панель действий со старыми устройствами и, в качестве особого случая, как использовать ActionView в вашей панели действий. Вы можете найти больше информации о ActionViews в моем предыдущем посте. Первоначально написанный с учетом ActionBarSherlock, вы можете легко перенести эти примеры кода в ActionBarSherlock. В следующих разделах показано, как адаптировать фрагменты кода для перехода от ActionBarSherlock к ActionBarCompat.

Вы можете найти пример проекта ActionViews на bitbucket . Если вам нравится, вы можете увидеть все изменения, необходимые для миграции ActionBarCompat, просмотрев фиксацию .

Конечно, вы должны интегрировать ActionBarCompat в IDE по вашему выбору. Я не освещаю это здесь. Габриэле Мариотти написала отличную статью, рассказывающую об интеграции интегрированной среды разработки ActionBarCompat . Первоначально я разработал этот проект с использованием Eclipse — вот почему я иногда ссылаюсь на специальные ярлыки Eclipse или почему позже я включаю диалог Eclipse. Но суть этого поста не зависит от IDE, которую вы хотите использовать.

Как поступить

Поэтому я предполагаю, что вы удалили ActionBarSherlock из проекта ActionViews и вместо этого добавили ActionBarCompat. После этого ваш проект должен быть подвержен ошибкам. Что не слишком удивительно. В следующих разделах я проведу вас через все шаги, необходимые для повторного развертывания проекта.

Я начну с ресурсов и позже займусь изменениями кода. Инструменты разработки Android генерируют новый R.javaфайл только тогда, когда ресурсы безошибочны. А без правильного Rфайла ваши исходные коды Java не будут компилироваться должным образом. Поэтому я предпочитаю сначала исправить ресурсы.

Смена стиля

Первое, что нужно сделать, это исправить стиль. Я использовал стиль ActionBarSherlock ранее. Этот стиль должен измениться на правильный стиль ActionBarCompat. Как и в случае с ActionBarSherlock, вы должны использовать стиль ActionBarCompat , в противном случае вы получите RuntimeException при запуске приложения.

Измените стиль с именем, AppBaseThemeчтобы использовать Theme.AppCompat.Light.DarkActionBarего в качестве родителя:

<style name="AppBaseTheme" 
      parent="@style/Theme.AppCompat.Light.DarkActionBar">
   <!-- nothing API level dependent yet -->
</style>

Поскольку вы можете забыть об этом шаге в будущих проектах — по крайней мере, я склонен изначально забывать этот шаг — вот исключение, которое вы увидите в logcat в этом случае. Увидев это здесь, вы можете вспомнить, что с этим делать.

E/AndroidRuntime( 1413): Caused by: java.lang.IllegalStateException: You need to use a Theme.AppCompat theme (or descendant) with this activity.
E/AndroidRuntime( 1413): 	at android.support.v7.app.ActionBarActivityDelegate.onCreate(ActionBarActivityDelegate.java:111)
E/AndroidRuntime( 1413): 	at android.support.v7.app.ActionBarActivityDelegateICS.onCreate(ActionBarActivityDelegateICS.java:58)
E/AndroidRuntime( 1413): 	at android.support.v7.app.ActionBarActivity.onCreate(ActionBarActivity.java:98)
E/AndroidRuntime( 1413): 	at com.grokkingandroid.sampleapp.samples.actionbar.actionviews.BaseActivity.onCreate(BaseActivity.java:30)

Инструменты разработчика подсвечивают атрибут android:textIsSelectableгде-то в файле после его сохранения. Это связано с тем, что минимальный уровень API проекта — SDK 7, а атрибут введен только в SDK 11. Вы можете смело игнорировать это. Если вы очистите свой проект после еще нескольких исправлений, этот маркер исчезнет. У вас не будет проблем с более низкими версиями, несмотря на это.

Исправление определений меню

Следующим шагом является исправление файлов определений меню. Старые версии Android не знают о панели действий и, следовательно, не поддерживают эти новые атрибуты xml для панели действий. Таким образом , вы должны изменить все атрибуты с именем android:showAsAction, android:actionViewClass, android:actionProviderClass, илиandroid:actionLayout . Исправить легко. Просто измените пространство имен с androidна appи добавьте это пространство имен.

Например, для файла menu_fragment_expandable.xmlновый XML выглядит так:

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <item
        android:id=
           "@+id/actionViewLayout"
        app:actionLayout=
           "@layout/expandable_actionview_edittext"
        android:icon=
           "@drawable/ic_action_add_inverse"
        app:showAsAction=
           "ifRoom|collapseActionView"
        android:title=
           "@string/add_item"/>
</menu>

Я делаю пространство имен известным парсеру в строке 3. Я использую это пространство имен для определенных атрибутов панели действий в строках 6 и 8. Таким образом, ActionBarCompat может читать эти атрибуты и обеспечивать правильный внешний вид пунктов меню.

Исправление Searchview для использования

Взгляните на файл menu_fragment_search.xml. Ни ваша IDE, ни Android Lint Checker не пометят этот файл как неправильный. Все же это так.

<menu xmlns:android="http://schemas.android.com/apk/res/android"
   xmlns:app="http://schemas.android.com/apk/res-auto">
   <item
      android:id=
         "@+id/searchView"
      app:actionViewClass=
         "com.actionbarsherlock.widget.SearchView"
      android:icon=
         "@drawable/ic_action_search_inverse"
      app:showAsAction=
         "ifRoom|collapseActionView"
      android:title=
         "@string/search"/>
</menu>

Очевидно, строка 7 больше не будет работать. Вместо Шерлока SearchViewвы должны использовать SearchViewбиблиотеку ActionBarCompat. Теперь вы должны использовать класс android.support.v7.widget.SearchView. Обновленный файл должен выглядеть следующим образом:

<menu xmlns:android="http://schemas.android.com/apk/res/android"
   xmlns:app="http://schemas.android.com/apk/res-auto">
   <item
      android:id=
         "@+id/searchView"
      app:actionViewClass=
         "android.support.v7.widget.SearchView"
      android:icon=
         "@drawable/ic_action_search_inverse"
      app:showAsAction=
         "ifRoom|collapseActionView"
      android:title=
         "@string/search"/>
</menu>

Если вы забудете об этом шаге в своем проекте, вы увидите исключение в logcat:

W/SupportMenuInflater( 1308): Cannot instantiate class: com.actionbarsherlock.widget.SearchView
W/SupportMenuInflater( 1308): java.lang.ClassNotFoundException: Didn't find class "com.actionbarsherlock.widget.SearchView" on path: DexPathList[[zip file "/data/app/com.grokkingandroid.sampleapp.samples.actionbar.actionviews-2.apk"],nativeLibraryDirectories=[/data/app-lib/com.grokkingandroid.sampleapp.samples.actionbar.actionviews-2, /system/lib]]
W/SupportMenuInflater( 1308): 	at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:56)
W/SupportMenuInflater( 1308): 	at java.lang.ClassLoader.loadClass(ClassLoader.java:497)
W/SupportMenuInflater( 1308): 	at java.lang.ClassLoader.loadClass(ClassLoader.java:457)
W/SupportMenuInflater( 1308): 	at android.support.v7.internal.view.SupportMenuInflater$MenuState.newInstance(SupportMenuInflater.java:480)
W/SupportMenuInflater( 1308): 	at android.support.v7.internal.view.SupportMenuInflater$MenuState.setItem(SupportMenuInflater.java:441)
W/SupportMenuInflater( 1308): 	at android.support.v7.internal.view.SupportMenuInflater$MenuState.addItem(SupportMenuInflater.java:462)
W/SupportMenuInflater( 1308): 	at android.support.v7.internal.view.SupportMenuInflater.parseMenu(SupportMenuInflater.java:196)
W/SupportMenuInflater( 1308): 	at android.support.v7.internal.view.SupportMenuInflater.inflate(SupportMenuInflater.java:118)
W/SupportMenuInflater( 1308): 	at com.grokkingandroid.sampleapp.samples.actionbar.actionviews.SearchViewFragment.onCreateOptionsMenu(SearchViewFragment.java:40)

Всякий раз, когда вы переносите существующий проект, я предлагаю вам выполнить поиск по всем источникам, особенно по ресурсам. Ищите «Шерлок», чтобы узнать, пропустили ли вы какие-либо ссылки. Другим хорошим кандидатом для решения проблем является файл манифеста, если вы ранее использовали стили ActionBarSherlock непосредственно внутри него.

Если вы исправили все файлы меню, вы закончили с ресурсами. Выберите Project -> Clean, чтобы очистить проект actionviews и избавиться от android:textIsSelectableмаркера ошибки. Инструменты разработчика Android генерируют новый R.javaфайл, и пришло время взглянуть на источники Java.

Исправление фрагментов

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

Подставляя SherlockDialogFragment с DialogFragment

Первый и самый простой способ исправить это AboutFragment. Вы должны исправить наследование, так как этот класс наследует от класса ActionBarSherlock, из которого вы хотите перенести. Просто замените SherlockDialogFragmentнаDialogFragment и все в AboutFragmentпорядке. Конечно, вы должны исправить импорт, нажав Ctrl-O.

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

Замените SherlockListFragment на ListFragment

Далее идет SearchFragment. Это наследуется от SherlockListFragment. Замените это запасом ListFragmentи нажмите Ctrl-O.

Замените getSherlockActivity () на getActivity ()

Остаются два красных маркера — оба для вызова метода, чтобы получить объект активности. Просто замените getSherlockActivity()на, getActivity()и код снова в порядке.

Заменить ШерлокФрагмент Фрагментом

Теперь о тех других фрагментах, из которых состоит говядина образца. Все эти фрагменты наследуются от базового класса DemoBaseFragment. Снова вы должны изменить тип суперкласса. Замените классом SherlockFragmentзапаса Fragmentбиблиотеки поддержки. Затем нажмите Ctrl-O и измените getSherlockActivity()вызовы на getActivity()вызовы, как указано выше.

Для четырех оставшихся фрагментов сначала измените импорт. ActionBarCompat не нуждается ни в каких специальных объектах Menuили MenuItemобъектах, как в ActionBarSherlock. Таким образом, два из четырех фрагментов сразу корректны после исправления импорта. Эти двое чуть более вовлечены.

Используйте MenuItemCompat для ActionViews и ActionProviders

Проблема в ActionViews — основном содержании примера приложения. ActionBarCompat использует простые объекты меню. Но те не знают о ActionView до уровня API 11. Поэтому ActionBarCompat использует вспомогательный класс, названный MenuItemCompatдля работы с ActionViews и ActionProviders .

Вместо вызова getActionView()объекта MenuItem вы должны использовать MenuItemCompat.getActionView(). Например, новый способ получить ActionView SearchViewFragmentвыглядит следующим образом:

SearchView searchView = 
      (SearchView)MenuItemCompat.getActionView(item);

То же самое относится и к настройке ActionView. PlaceholderActionViewFragment, Например , используются следующие строки:

MenuItemCompat.setActionView(
      PlaceholderActionViewFragment.this.mProgress, 
      R.layout.actionview_progress);

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

Исправление деятельности

Как и в случае с фрагментами, вы должны поменять суперклассы на действия. Проект actionviews использует одно базовое действие для всех действий в рамках проекта. Этот класс, очевидно, является отправной точкой для изменений в деятельности.

Замените SherlockFragmentActivity на ActionBarActivity

Изменение суперкласса для действий немного отличается от изменений, которые вы применили к фрагментам на предыдущих шагах. С фрагментами вы просто меняете их на стандартные фрагменты библиотеки поддержки. С действиями, с другой стороны, вы должны использовать супер класс библиотеки ActionBarCompat.

Откройте BaseActivityи измените суперкласс с SherlockFragmentActivityна ActionBarActivity.

Замените getSupportMenuInflater () на getMenuInflater ()

Одна проблема остается после исправления импорта. Первая проблема — это вызов getSupportMenuInflater(). Просто замените его getMenuInflater()вместо этого.

Заменить идентификаторы макета Шерлока

Следующее действие, которое вы собираетесь исправить, — это ActionViewActivity. После исправления всего импорта осталось еще два красных маркера. Они предназначены для конкретных ресурсов макета шерлока.

Сначала замените R.layout.sherlock_spinner_itemна android.R.layout.simple_spinner_item. Далее замените sherlock_spinnner_dropdown_itemнаandroid.R.layout.simple_spinner_dropdown_item .

Соответствующие строки должны выглядеть следующим образом после применения этих изменений:

ArrayAdapter<CharSequence> spinnerAdapter = 
      ArrayAdapter.createFromResource(
            getSupportActionBar().getThemedContext(), 
            resId, 
            android.R.layout.simple_spinner_item);
spinnerAdapter.setDropDownViewResource(
      android.R.layout.simple_spinner_dropdown_item);

Для двух оставшихся действий, которые я еще не рассмотрел, вам просто нужно исправить импорт, чтобы он снова компилировался. После этого ваш проект не должен содержать больше ошибок и должен нормально работать.

Уроки выучены

Прочитав этот пост, вы сможете перенести существующий проект, основанный на ActionBarSherlock, в ActionBarCompat. Вы видели веские причины, почему это необходимо сделать, и шаги, которые необходимо выполнить, чтобы ваш проект снова заработал.

Есть и другие отличные посты о ActionBarCompat. Марк Эллисон написал серию о ActionBarCompat, а Антонио Лейва также выпустил серию из трех частей о ActionBarCompat . В последнем посте также рассказывается о миграции с ActionBarSherlock . И у Габриэле Мариотти также есть много сообщений о ActionBarCompat . Мы все используем разные подходы — так что ищите стиль поста, который вам нравится больше всего. Если вы чувствуете, что здесь отсутствуют важные части, взгляните на эти посты.

До следующего раза. Удачного кодирования — и счастливой миграции!