Book Image

Instant Android Fragmentation Management How-to

By : Gianluca Pacchiella
Book Image

Instant Android Fragmentation Management How-to

By: Gianluca Pacchiella

Overview of this book

There are currently 7 different versions of operating systems for Android. A growing issue is fragmentation. With the number of Android users and the variety of versions available, Android fragmentation is a huge problem. This little book is the solution. Instant Android Fragmentation Management How-to is a step-by-step guide to writing applications that can run on all devices starting from Android 1.6. With simple solutions for complex problems, this book will walk you through the biggest issues facing Android developers today.This book will take you through the newest features in the latest version of Android, and shows you how to utilize them in the older versions using the compatibility library. This practical guide allows you to focus on  creating the best application possible without worrying about compatibility.All the heavy lifting is done for you. Using user interface, adapting your application will work perfectly on any Android operating system. Asynchronous data management will also allow your applications to run smoothly on any device.Everything you need to run your app on any version of Android is right here.
Table of Contents (7 chapters)
Instant Android Fragmentation Management How-to
Credits
About the Author
About the Reviewers
www.PacktPub.com
Preface

ActionBar (Should know)


One thing not addressed by the compatibility package is ActionBar, a new UI pattern introduced from Google in the Honeycomb platform. Since this is a very important element for integration with the Android ecosystem, some alternatives are born, the first one from Google itself, as a simple code sample named ActionBar Compatibility that you can find in the sample/ directory of the Android SDK.

We will follow a different approach, using a famous open source project, ActionBarSherlock.

Getting ready

The code for this library is not available from SDK, so we need to download it from its website (http://actionbarsherlock.com/).

You can also download it from the github repository of the author; once the archive has been downloaded, you can extract it to a directory of your choice.

How to do it...

Let's include ActionBarSherlock as a library in Eclipse and then create a simple project using it:

  1. Open Eclipse and create a new project to import the source files that you can find in the libraries/ directory of the ActionBarSherlock source code. This can be done by selecting File | New | Other....

  2. Open the project where you want to use the library (otherwise create a new one).

  3. Tell Eclipse to use the ActionBarSherlock library by selecting the project from the Package explorer and then selecting Project | Property from the main menu. A dialog will show up. Now add the library from the Android section:

  4. In the file containing the main Activity of your project, import the required classes:

    import com.actionbarsherlock.app.SherlockFragmentActivity;
    import com.actionbarsherlock.app.SherlockFragment;
    import com.actionbarsherlock.app.ActionBar;
    import com.actionbarsherlock.view.Menu;
    import com.actionbarsherlock.view.MenuItem;
    import com.actionbarsherlock.view.MenuInflater;
  5. Implement the Activity class where the ActionBar will be used, extending SherlockFragmentActivity:

    public class ActionBarActivity extends SherlockFragmentActivity {
        …
    }
  6. In the onCreate() method of the Activity, configure the ActionBar:

        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.main);
    
            // if you wan to configure something
            // about ActionBar use this instance
            ActionBar ab = getSupportActionBar();
        }
  7. Add the required the following code snippet in order to create the menu options:

        @Override
        public boolean onCreateOptionsMenu(Menu menu) {
            MenuInflater inflater = getSupportMenuInflater();
            inflater.inflate(R.menu.main, menu);
    
            return true;
        }
  8. Implement onOptionsItemSelected() of the Activity class with the desired behavior (here we have shown only a simple toast notification):

      @Override
      public boolean onOptionsItemSelected(MenuItem item) {
          switch (item.getItemId()) {
            default:
                Toast.makeText(this, "Hi!", 1000).show();
            }
    
          return super.onOptionsItemSelected(item);
        }
  9. Define which menu options you want in the related XML file located at res/menu/main.xml:

    <?xml version="1.0" encoding="utf-8"?>
    <menu xmlns:android="http://schemas.android.com/apk/res/android">
        <item android:id="@+id/first"
              android:title="First"
              android:showAsAction="ifRoom"/>
        <item android:id="@+id/second"
              android:title="Second"
              android:showAsAction="ifRoom"/>
    </menu>

How it works...

Using this external library, we permit our application to have an implementation of the ActionBar UI pattern. ActionBarSherlock re-implements most of the core classes that you can find in the normal Android framework. One simple rule to remember is to prepend the word Sherlock to any of the interested classes.

Since it can be tricky remembering which classes belong to this library, let me list these classes:

  • com.actionbarsherlock.ActionBarSherlock

  • com.actionbarsherlock.app.ActionBar

  • com.actionbarsherlock.app.SherlockActivity

  • com.actionbarsherlock.app.SherlockDialogFragment

  • com.actionbarsherlock.app.SherlockExpandableListActivity

  • com.actionbarsherlock.app.SherlockFragment

  • com.actionbarsherlock.app.SherlockFragmentActivity

  • com.actionbarsherlock.app.SherlockListActivity

  • com.actionbarsherlock.app.SherlockListFragment

  • com.actionbarsherlock.app.SherlockPreferenceActivity

  • com.actionbarsherlock.view.ActionMode

  • com.actionbarsherlock.view.ActionProvider

  • com.actionbarsherlock.view.CollapsibleActionView

  • com.actionbarsherlock.view.Menu

  • com.actionbarsherlock.view.MenuInflater

  • com.actionbarsherlock.view.MenuItem

  • com.actionbarsherlock.view.SubMenu

  • com.actionbarsherlock.view.Window

  • com.actionbarsherlock.widget.ActivityChooserModel

  • com.actionbarsherlock.widget.ActivityChooserView

  • com.actionbarsherlock.widget.ShareActionProvider

If some problem occurs, remember to double-check whether you have used the correct class and not imported the one from the Support Library or the original framework.

This library tries hard to maintain an API compatibility with the original ActionBar. The only difference to remember is to substitute getActionBar() with getSupportActionBar() and to use getSupportMenuInflater() instead of getMenuInflater().

ActionBarSherlock is built on top of the Support Library, so in order to obtain FragmentManager, you must use the getSupportFragmentManager() function.

There's more...

Now let's talk about some other options, or possibly some pieces of general information that are relevant to this task.

The ActionBar is not only a bar, a visual element, but it's also the gate to a bunch of new UI functionalities; in the following sections, we'll show some of these functionalities and how to use it.

Home button

From the start, the Android platform has made available a Back button with which one can step back during the navigation between activity and applications. To allow a more structured navigation, the Up button was introduced to permit a user to create a new task from an activity that does not belong to the original task that created it (it's not completely true, since if the original application is the same, no tasks are created).

For example, we start a news reader and then we choose a specific news item that we want to share with our friends by sending it via e-mail; in order to do so, we launch an Email application that is started in the same task of the news reader. If the Email application has an Up button, clicking on it will start a new task with the home Activity of the Email application.

What we obtain with the Up button is a hierarchical navigation inside the active application. Obviously, the Up button should not be present in the main Activity because there is no upward navigation there.

In order to enable the Up button in our code, simply activate it by using the following code line:

actionbarinstance.setDisplayHomeAsUpEnabled(true);

We can now write the code that will handle the click on the icon on the left-hand side of the ActionBar. This code is as follows:

@Override
public boolean onOptionsItemSelected(MenuItem item) {
  switch (item.getItemId()) {

    case android.R.id.home:

    Intent intent = new Intent(this, MyOwnActivity.class);
    intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
    startActivity(intent);

    return true;

    default:
    return super.onOptionsItemSelected(item);

  }
}

Remember only that the Up button is represented on the ActionBar with a widget having android.R.id.home as an identifier.

Action view

Another UI pattern from the ActionBar is the action view. It is possible to associate a particular widget to an action item. A widget here is, a visual element that can be expanded to occupy all the available space of the ActionBar; in the following code, we will implement a fake search entry—initially on the ActionBar there is only the Search button:

After selecting this element, it will appear expanded, as shown in the following screenshot:

  1. Import the required classes:

    import com.actionbarsherlock.view.MenuItem;
    import com.actionbarsherlock.view.MenuInflater;
    import android.widget.EditText;
  2. Implement the method of the Activity class used to create the menu:

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
      MenuInflater inflater = getSupportMenuInflater();
      inflater.inflate(R.menu.main, menu);
    
      MenuItem menuItem = menu.findItem(R.id.search);
      menuItem.setOnActionExpandListener(new MenuItem.OnActionExpandListener() {
        @Override
        public boolean onMenuItemActionCollapse(MenuItem item) {
          return true;
        }
    
        @Override
        public boolean onMenuItemActionExpand(MenuItem item) {
          return true;
        }
      });
      EditText fakeSearchView = (EditText)menuItem.getActionView();
    
      return true;
    }
  3. Define the XML file for the menu with an action view:

    <?xml version="1.0" encoding="utf-8"?>
    <menu xmlns:android="http://schemas.android.com/apk/res/android">
      <item android:id="@+id/search"
        android:title="Search"
        android:showAsAction="always|collapseActionView"
         android:actionLayout="@layout/action_view"
        />
    </menu>
  4. Define the layout for the action view into a file placed in res/layout/action_view.xml:

    <?xml version="1.0" encoding="utf-8"?>
    <EditText xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:hint="Search"/>

This example mimics the example from the Android documentation where the SearchView class is used instead. This class is not available with ActionBarSherlock, but is planned to be included (maybe) in future releases.

For further information about this issue, please follow the discussion on the github project page at https://github.com/JakeWharton/ActionBarSherlock/issues/70.

ShareActionProvider

An extension to the concept of action view is the action provider—a widget that not only controls its appearance, but also extends its controls. An action provider available with the Android framework is ShareActionProvider that allows us to easily share the contents showing a menu with some share target in it.

Since we are interested in maintaining backward compatibility using ActionBarSherlock, here are the steps necessary to implement this:

  1. Import the required classes:

    import com.actionbarsherlock.widget.ShareActionProvider;
    import android.content.Intent;
  2. Attach an Intent to the action provider:

      public boolean onCreateOptionsMenu(Menu menu) {
        // remember to use getSupportMenuInflater()
        MenuInflater inflater = getSupportMenuInflater();
        inflater.inflate(R.menu.main, menu);
     
        ShareActionProvider sap = (ShareActionProvider)menu.findItem(R.id.share).getActionProvider();
        // be cautious about the parameter otherwise the
        // menu can be empty
        Intent intent = new Intent(Intent.ACTION_SEND);
        intent.setType("text/plain");
        sap.setShareIntent(intent);
    
        return true;
      }
  3. Define the XML file:

    <?xml version="1.0" encoding="utf-8"?>
    <menu xmlns:android=" http://schemas.android.com/apk/res/android">
        <item android:id="@+id/share"
          android:title="Share"
          android:showAsAction="always"
          android:actionProviderClass="com.actionbarsherlock.widget.ShareActionProvider" />
    </menu>

In the following screenshot, you can see how the menu item appears:

Contextual ActionBar

The necessity to make simple and quick actions on specific elements such as list items (for example, removing a contact) or copying some selected text into the clipboard, makes the employ of the contextual action bar useful. The appearance of the bar changes so that it can show the specific menu item for the action desired.

Now, let's see how to add a contextual action bar with two action items to your application:

  1. Import all the necessary libraries:

    import com.actionbarsherlock.app.SherlockFragmentActivity;
    import com.actionbarsherlock.view.ActionMode;
  2. Implement the Callback interface of the ActionMode class; it will manage the lifecycle of the contextual menu:

    private ActionMode.Callback mActionModeCallback = new ActionMode.Callback() {
    
        // Called after startActionMode()
        @Override
        public boolean onCreateActionMode(ActionMode mode, Menu menu) {
        // Inflate a menu resource providing context menu items
        MenuInflater inflater = mode.getMenuInflater();
        inflater.inflate(R.menu.context_menu, menu);
        return true;
      }
    
      // Called each time the action mode is shown. Always called after onCreateActionMode, but
      // may be called multiple times if the mode is invalidated.
      @Override
      public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
        return false; // Return false if nothing is done
      }
    
      // Called when the user selects a contextual menu item
      @Override
      public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
        switch (item.getItemId()) {
          case R.id.action_1:
          mode.finish(); // Action picked, so close the CAB
          return true;
          default:
          return false;
        }
      }
    
      // Called when the user exits the action mode
      @Override
      public void onDestroyActionMode(ActionMode mode) {
      }
    };
  3. Attach a listener to the desired element that will activate the action mode (in this example, we attach it to the click event on a list item):

      getListView().setOnItemClickListener(new AdapterView.OnItemClickListener() {
        @Override
        public void onItemClick(AdapterView<?>parent, View view, int position, long id) {
          if (mActionMode != null) {
            return;
          }
    
        // Start the CAB using the ActionMode.Callback defined above
        ActionBarActivity.this.startActionMode(mActionModeCallback);
        view.setSelected(true);
        }
      });
  4. In an XML file, define the contextual menu layout such as a normal menu:

    <?xml version="1.0" encoding="utf-8"?>
    <menu xmlns:android="http://schemas.android.com/apk/res/android">
        <item android:id="@+id/action_1"
              android:title="Action 1" />
        <item android:id="@+id/action_2"
              android:title="Action 2" />
    </menu>

The following screenshot shows how the contextual menu will appear:

Remember that the OK button (the button at the very left of the bar) simply dismisses the contextual action bar and the system adds it for you.

The obvious extension of this mechanism is the possibility to select multiple elements and to act on it. This exists and it possibly started from Honeycomb, using the MultiChoiceModeListener interface that belongs to the AbsListView class. The only problem is that it is not available with ActionBarSherlock, so as hinted from the original Android documentation, it is better to fall back to a floating contextual menu.

ViewPagerIndicator

Let's explain how to create a more interesting visual layout for your application, for example, one UI pattern that we see all the time is the "swipey-tabs" one, used in the Android Market.

This UI pattern allows the user to switch between sections of the application, simply swiping left/right and having the title on the tab following the swipe motion (for more technical information about this design, I advise you to read the post from an Android Market designer at http://www.pushing-pixels.org/2011/08/11/android-tips-and-tricks-swipey-tabs.html).

In order to do this, we need to download another library from the web page of its project, located at http://viewpagerindicator.com/.

The steps required to add this library to our project are the same as those shown at the start of this section. Only keep in mind that the path to the library is where you have extracted it.

Now, we are ready to add ViewPageIndicator to your application:

  1. Import the correct classes:

    import com.actionbarsherlock.app.SherlockFragmentActivity;
    import com.actionbarsherlock.app.ActionBar;
    import android.support.v4.view.ViewPager;
    import com.viewpagerindicator.TitlePageIndicator;
  2. Create an Activity class subclassing SherlockFragmentActivity and implementing the TabListener interface:

    public class ActionBarActivity extends SherlockFragmentActivity implements ActionBar.TabListener {
    …
    }
  3. Implement the onCreate() method where we set the layout and configure the ActionBar; since we are creating a tab-driven application, we have to set NAVIGATION_MODE_TABS as the navigation mode:

      @Override
      public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
    
        ActionBar ab = getSupportActionBar();
        ab.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
    
        ViewPager pager = (ViewPager)findViewById(R.id.pager);
        pager.setAdapter(new TabsAdapter(getSupportFragmentManager()));
    
        //Bind the title indicator to the adapter
        TitlePageIndicator titleIndicator = (TitlePageIndicator)findViewById(R.id.titles);
        titleIndicator.setViewPager(pager);
      }
  4. Create a subclass of the FragmentPageAdapter class that will bind each tab to a specific fragment (here we have used a unique fragment class called DummyFragment, not implemented, that simply shows a simple text):

      public class TabsAdapter extends FragmentPagerAdapter {
        public TabsAdapter(FragmentManager fm) {
          super(fm);
        }
    
        @Override
        public Fragment getItem(int position) {
          return new DummyFragment();
        }
    
        @Override
        public int getCount() {
          return 3;
        }
    
        @Override
        public CharSequence getPageTitle(int position) {
          return "Page " + position;
        }
    
      }
  5. Implement the TabListener interface in the Activity class that reacts to the events that will happen on tabs:

      /*
      * TabListener interface's methods
      */
      public void onTabReselected(ActionBar.Tab tab, FragmentTransaction ft) {
      // User selected the already selected tab. Usually do nothing.
      }
    
      public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction ft) {
      }
    
      public void onTabSelected(ActionBar.Tab tab, FragmentTransaction ft) {
      }
  6. Define a layout with TitlePageIndicator (double-check that the fully qualified name used as the tag is correctly entered):

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="vertical"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        >
        <com.viewpagerindicator.TitlePageIndicator
            android:id="@+id/titles"
            android:layout_height="wrap_content"
            android:layout_width="fill_parent" />
    <android.support.v4.view.ViewPager
        android:id="@+id/pager"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        />
    </LinearLayout>

What we obtain is an application where the various Fragments served from the ViewPager class are inserted, one for each tab, and the TitlePagerIndicator class furnishes us with a visual effect when the transition between tabs happens. The following screenshot shows how the tab part appears in our application (obviously, it is not possible to show the animation on paper):