1. 程式人生 > >Migrating from ActionBarSherlock to ActionBarCompat

Migrating from ActionBarSherlock to ActionBarCompat

In July 2013 Google announced ActionBarCompat as part of its support library package. This library makes it easy to use the Action Bar that have to support older devices. Many have waited for this to happen ever since the Action Bar was introduced with Honeycomb.

I, though, didn't expect that to happen. After all the Action Bar was announced long ago and we had ActionBarSherlock. So why all off a sudden?

I have written multiple posts about ActionBarSherlock on this blog prior to this announcement. Those posts still get a lot of attention and search hits. But while the basic concepts still apply, any ActionBarSherloc specific parts are kind of deprecated 🙂

I strongly believe that you should use ActionBarCompat for all new projects

that want to support older devices. It also might make sense to migrate existing projects. So read on to learn why you should migrate or use ActionBarCompat right away and how to migrate existing projects.

Why you should prefer ActionBarCompat over ActionBarSherlock

There are many reasons why you should prefer ActionbarCompat over ActionbarSherlock.

First of all this project is by Google, is part of the Support Library and thus likely will support new Action Bar related stuff at the same time Google releases them with stock Android.

Another good reason and a proof for the previous point is that ActionBarCompat supports the Navigation Drawer pattern right out of the box, while ActionBarSherlock does not. Thus if you want to add this drawer to an existing project/app you should migrate.

The last and not least reason is, that the creator of ActionBarSherlock, Jake Wharton, announced on Google+ that further development of ActionBarSherlock has been stopped. ActionBarSherlock 4.4 is the last release and might get bug fixes - but there won't be any new features:

While there may be a dot release or two in the coming weeks, version 4.4 is shaping up to be The Last Releaseâ„¢.

This is the entire purpose of the library. It has been designed for this use case specifically. It has been deprecated from inception with the intention that you could some day throw it away.

Sample project

To showcase how the migration works, I have migrated the sample project ActionViews to ActionBarCompat. This sample project shows how to use the Action Bar with older devices and as a special case how to use ActionViews within your Action Bar. You can find more information about ActionViews on my older post. While originally written with ActionBarSherlock in mind, you can easily transfer those code samples to ActionBarSherlock. The next sections show you how to adapt the code snippets to move from ActionBarSherlock to ActionBarCompat.

Of course you have to integrate ActionBarCompat in the IDE of your choice. I do not cover this here. Gabriele Mariotti has written an excellent post covering the IDE integration of ActionBarCompat. I originally developed this project using Eclipse - which is why I occasionally refer to Eclipse specific shortcuts or why I include an Eclipse dialog later on. But the core of this post is independent of the IDE you want to use.

How to proceed

So I assume that you have removed ActionBarSherlock from the ActionViews project and added ActionBarCompat instead. After that your project should be plagued with errors. Which is not too surpising. In the next sections I will take you through all the steps needed to get the project deployable again.

I start with the resources and deal with code changes later on. Android's Development Tools only generate a new R.java file when the resources are error-free. And without a correct R file your Java sources won't compile properly. Thus I prefer to fix resources first.

Changing the style

The first thing to do, is to correct the style. I have used an ActionBarSherlock style previously. This style has to change to the proper ActionBarCompat style. And as with ActionBarSherlock you have to use an ActionBarCompat style, otherwise you'll get a RuntimeException at app start.

Change the style with the name AppBaseTheme to use Theme.AppCompat.Light.DarkActionBar as its parent:


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

Since you might forget this step in future projects - at least I'm prone to initially forget this step - here's the Exception that you will see in logcat in that case. Having seen it here might help you to remember what to do about it.


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)

The dev tools will highlight the attribute android:textIsSelectable somewhere up in the file after you save it. That's because the minimum API level of the project is SDK 7 and the attribute has only been introduced with SDK 11. You can safely ignore this. If you clean your project after some more fixes, this marker will disappear. You won't get any problems with lower versions despite this.

Fixing the menu definitions

The next step is to correct the menu definition files. Older Android versions don't know about the Action Bar and thus do not support those new xml attributes for the Action Bar. So you have to change all attributes with the name android:showAsAction, android:actionViewClass, android:actionProviderClass, or android:actionLayout. The fix is easy. Simply change the namespace from android to app and add this namespace.

For example for the file menu_fragment_expandable.xml the new xml looks like this:


<?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>

I make the namespace known to the parser in line 3. I use this namespace for the Action Bar specific attributes in lines 6 and 8. This way ActionBarCompat can read those attributes and provide the correct appearance of the menu items.

Fixing the Searchview to use

Have a look at the menu_fragment_search.xml file. Neither your IDE nor Android's Lint checker will flag this file as incorrect. Yet it is.


<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>

Obviously line 7 won't work any longer. Instead of Sherlock's SearchView you have to use the SearchView of the ActionBarCompat library. You now have to use the class android.support.v7.widget.SearchView. The updated file should look like this:


<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>

Should you forget this step in a project of yours, you are going to see an exception in 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)

Whenever you migrate an existing project, I suggest you run a search over all sources - especially the resources. Search for "sherlock" to find out, if you've missed any references. Another good candidate for problems is be the manifest file if you previously used ActionBarSherlock styles directly within it.

If you have corrected all menu files, you are done with the resources. Select Project -> Clean to clean the actionviews project and get rid of the android:textIsSelectable error marker. The Android Dev Tools generate a new R.java file and it's time to have a look at the Java sources.

Fixing fragments

I'm going to show you first how to fix fragments and later on how to fix activities.

Substituting SherlockDialogFragment with DialogFragment

The first and most simple one to fix is the AboutFragment. You have to fix the inheritance since this class inherits from an ActionBarSherlock class which you want to migrate away from. Simply substitute SherlockDialogFragment with DialogFragment and the AboutFragment is fine. Of course you have to correct the imports by hitting Ctrl-O.

Note: Eclipse asks you whether to use an import from stock Android or from the support library. Whenever eclipse offers you this alternative, you always have to use the imports of the support library:

Select the support library versions whenever this choice is presented to you
Select the support library versions whenever this choice is presented to you

Substitute SherlockListFragment with ListFragment

Next up is the SearchFragment. It inherits from SherlockListFragment. Replace this with the stock ListFragment and hit Ctrl-O.

Replace getSherlockActivity() with getActivity()

Two red markers remain - both for the method call to get an activity object. Simply replace getSherlockActivity() with getActivity() and the code is fine again.

Substitute SherlockFragment with Fragment

Now to those other fragments that make up the beef of the sample. Those fragments all inherit from the base class DemoBaseFragment. Again you have to change the type of the super class. Replace SherlockFragment with the stock Fragment class of the support library. Afterwards hit Ctrl-O and change the getSherlockActivity() calls to getActivity() calls as mentioned above.

For the four remaining fragments change the imports first. ActionBarCompat needs no special Menu or MenuItem objects like ActionBarSherlock did. Thus two of the four fragments are immediately correct after fixing the imports. Those other two are a tiny bit more involved.

Use MenuItemCompat for ActionViews and ActionProviders

The problem is with ActionViews - the core content of the sample app. ActionBarCompat uses plain Menu objects. But those do not know of ActionViews prior to API level 11. So ActionBarCompat uses a helper class named MenuItemCompat to deal with ActionViews and ActionProviders.

Instead of calling getActionView() on a MenuItem object you have to use MenuItemCompat.getActionView(). For example the new way to get hold of the ActionView in the SearchViewFragment looks like this:


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

The same applies to setting an ActionView. The PlaceholderActionViewFragment for example uses the following lines:


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

For ActionProviders you would have to do the same - just with different method names of course.

Fixing activities

As with fragments you have to change the super classes for the activities as well. The actionviews project uses one base activity for all activities within the project. This class obviously is the starting point for changes to activities.

Replace SherlockFragmentActivity with ActionBarActivity

Changing the super class for activities is slightly different to the changes you applied to fragments in the previous steps. With fragments you simply change them to stock fragments of the support library. With activities on the other hand you have to use a super class of the ActionBarCompat library.

Open BaseActivity and change the super class from SherlockFragmentActivity to ActionBarActivity.

Replace getSupportMenuInflater() with getMenuInflater()

One problem remains after fixing the imports. The first problem is the call to getSupportMenuInflater(). Simply replace it with getMenuInflater() instead.

Replace Sherlock layout IDs

The next activity you are going to fix is the ActionViewActivity. After fixing all imports there are still two red markers left. Those are for sherlock specific layout resources.

First replace R.layout.sherlock_spinner_item with android.R.layout.simple_spinner_item. Next replace sherlock_spinnner_dropdown_item with R.layout.support_simple_spinner_dropdown_item. Edit: Thanks to George for his correction of my original recommendation (see his comment below).

The respective lines should look like this after you applied those changes:


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

For the two remaining activities, which I didn't cover yet, you simply have to fix the imports to make them compile again. After that your project should contain no more errrors and should build fine.

Lessons learned

After reading this post you should be able to migrate an existing project which is based on ActionBarSherlock to ActionBarCompat. You have seen good reasons of why to do this and the steps to follow to get your project running again.

There are other great posts about ActionBarCompat out there. Mark Allison wrote a series about ActionBarCompat and Antonio Leiva also has a three part series on ActionBarCompat. The last post also covers migrating from ActionBarSherlock. And Gabriele Mariotti also has multiple posts about ActionBarCompat. We all use different approaches - so look for the post style you like the most. If you feel important parts are missing here, have a look at these other posts.

Till next time. Happy Coding - and Happy Migrating!

相關推薦

Migrating from ActionBarSherlock to ActionBarCompat

In July 2013 Google announced ActionBarCompat as part of its support library package. This library makes it easy to u

ActionBarCompat (Part 3): Migrating from ActionBarSherlock

After learning some basic rules to work with ActionBarCompat, you will probably need to migrate some apps from ActionBarSherlock to ActionBarCompat,

Migrating from Underscore to Lodash

Modernizing the front-end stack The core Dropbox web application is 10 years old and used by millions of users per day. Hundreds of front-end engineers

Migrating from SQLite to MySQL

I recently needed to convert a web2py-based CRM app hosted on an Apache server with a SQLite backend to MySQL. Below are the steps that worked for me. I

Glide V4 框架新特性(Migrating from v3 to v4)

Android Glide4 非同步圖片框架 不瞭解官方推舉使用Glide框架,可以先閱讀Glide框架介紹. Glide v4版本前幾天新發布,一些新特性也需要學習下。 從V3到V4遷移,改變的行為和配置如下: Options Reques

Migrating from RabbitMQ to Amazon MQ

This post is courtesy of Sam Dengler, AWS Solutions Architect. Message brokers can be used to solve a number of needs in enterprise archit

Migrating from Spring 3 to Spring 4 - org.springframework.scheduling.quartz.CronTriggerBean

can EDA utils jobdetail data- found ble ever OS I‘m trying to migrate from spring 3.0.5 to spring 4.1.X . Spring 3 has Class named as "or

Migrating from Backbone.js to React.js without losing it

Migrating from Backbone.js to React.js without losing itIn this article I will share our experience as a team of migrating from old code and libraries to s

Beginning Python From Novice to Professional (9) - Socket

gethost code track eth true get ont content socket Socket 小型server: #!/usr/bin/env python import socket s = socket.socket() host = sock

修改python原文件中的fromto字段

python email from to1down votefavorite1Here‘s an excerpt from the code I‘m using. I‘m looping through the part that adds the email; my problem is rather th

[POJ2762]Going from u to v or from v to u?

str for digi tchar har add size ins sta 題目大意: 判斷一個有向圖是否弱連通。 思路: Tarjan縮點。然後判斷原圖是否是一條鏈。 考慮鏈的特性:有且僅有一點入度為0,有且僅有一點出度為0。 因此縮點後直接判斷入度為

Codeforces 849C From Y to Y

組成 scan amp force 簡單 ces ret 最大 log 自古C題比B題簡單。 構造題。 我們發現合並一個相同的字母組成的字符串,個數為n,它的代價是(n*(n-1))/2,也就是0+1+...+n-1。 所以我們每次取最大的n,使得k-n>=0,減一下

【推導】【貪心】Codeforces Round #431 (Div. 1) A. From Y to Y

aaa return 最大的 tchar 題意 spa 必須 puts clu 題意:讓你構造一個只包含小寫字母的可重集,每次可以取兩個元素,將它們合並,合並的代價是這兩個元素各自的從‘a’到‘z’出現的次數之積的和。 給你K,你構造的可重集必須滿足將所有元素合而為一以後,

CodeForces - 848A From Y to Y (找規律)

nbsp 得到 串合並 memset include scan ret spa 可能 http://codeforces.com/problemset/problem/848/A 題目大意:剛開始集合裏面都是單字符可認為是字符串,然後讓你去合並任意兩個串合並要消耗∑c=

A little issue in Mathematical Thought from Ancient to Modern Times, Vol. 3

enc classes 技術 min member put clas hat 技術分享 At P985 of the book, says But there are cuts that are not determined by rational numbers. I

from NEU to the society

過多 美的 進入 視野 neu 第一天 起航 成長 尊重 今天,正式的登上了我註冊已久的博客園,最初註冊園子得出發點是記錄生活點滴和學習工作的心得的,那就不忘初心,從頭開始吧。 從校園到工作,從東北到南方 我們畢業啦 誰說畢業遙遙無期,轉眼就要各奔東西。 是的,2017.1

3D Computer Grapihcs Using OpenGL - 07 Passing Data from Vertex to Fragment Shader

vertex 一致性 表示 變量 width src log 兩個 image 上節的最後我們實現了兩個綠色的三角形,而綠色是直接在Fragment Shader中指定的。 這節我們將為這兩個三角形進行更加自由的著色——五個頂點各自使用不同的顏色。 要實現這個目的,我們分兩

Python伊始——From Boring to Amazing

為什麽 難解 family 語言 pan 並不是 專業 目的 關於 先來談一下關於Python編程語言的淺薄認知,“一門編程課,僅此而已”這是我幾個月前對這門應用技術的認識。 如今看來,卻不只是“僅此而已”,作為今年年初被加入計算機二級考試科目的這門技術,或許並不是它表面上

Loading Data From Oracle To Hive By ODI 12c

ODI Oracle Hive 本文描述如何通過ODI將Oracle表數據同步到Hive。1、準備工作在hadoop集群的各個節點分別安裝Oracle Big Data Connectors,具體的組件如下圖所示:這裏只需安裝Oracle Loader For Hadoop(oraloader)以

Set the Round Robin IOPS limit from 1000 to 1

iopshttps://kb.vmware.com/s/article/2069356 http://www.enterprisedaddy.com/2017/02/set-round-robin-iops-limit-default-1000-1-using-powercli/ 1,Query the pa