Android Programming Module 4
Android Programming Module 4
ANDROID MENUS
The key class in Android menu support is android.view.Menu. Every
activity in Android is associated with one menu object of this type. The menu
object then contains a number of menu items and submenus. Menu items are
represented by android.view.MenuItem. Submenus are represented by
android.view.SubMenu.
A Menu object contains a set of menu items. A menu item carries the
following attributes:
Name: A string title
Menu item ID: An integer
Group ID: An integer representing which group this item should be part of
Sort order: An integer identifying the order of this menu item when it is
displayed in the menu.
The name and menu item ID attributes are self explanatory. We can
group menu items together by assigning each one a group ID. Multiple menu
items that carry the same group ID are considered part of the same group. The
sort-order attribute demands a bit of coverage. If one menu item carries an order
number of 4 and another menu item carries a order number of 6, the first menu
item will appear above the second menu item in the menu. Some of these menu
item sort-ordernumber ranges are reserved for certain kinds of menus. These
are called menu categories. The available menu categories are as follows:
CREATING MENUS
In the Android SDK, we don’t need to create a menu object
from scratch. Because an activity is associated with a single menu,
Android creates this single menu for that activity and passes it to the
onCreateOptionsMenu() callback method of the activity class. (As the
name of the method indicates, menus in Android are also known as
options menus). Starting with 3.0, this method is called as part of
activity creation. This change is due to the fact that the action bar is
always present in an activity. A menu item that we create in this method
for the options menu may sit in an action bar. Because an action bar is
always visible (unlike the options menu), the action bar must know
its menu items from the beginning. So Android cannot wait until the user
opens an options menu to call the onCreateOptionsMenu() method. This
callback menu setup method allows us to populate the single passed-
in menu with a set of menu items (see Listing 7–1).
b) Through Listeners
A listener implies object creation and a registry of the listener. So this is the
overhead that the performance refers to in the first sentence of this paragraph.
However, we may choose to give more importance to reuse and clarity, in which
case listeners provide flexibility. This approach is a two-step process. In the first
step, we implement the OnMenuClickListener interface. Then, we take an
instance of this implementation and pass it to the menu item. When the menu
item is clicked, the menu item calls the onMenuItemClick() method of the
OnMenuClickListener interface.
Listing 7–5. Using a Listener as a Callback for a Menu Item Click
//Step 1
public class MyResponse implements OnMenuClickListener
{
//some local variable to work on
//...
//Some constructors
@override
boolean onMenuItemClick(MenuItem item)
{
//do our thing
return true;
}
}
//Step 2
MyResponse myResponse = new MyResponse(...);
menuItem.setOnMenuItemClickListener(myResponse);
...
The onMenuItemClick() method is called when the menu item has been invoked.
This code executes as soon as the menu item is clicked, even before the
onOptionsItemSelected() method is called. If onMenuItemClick() returns true, no
other callbacks are executed—including the onOptionsItemSelected() callback
method. This means that the listener code takes precedence over the
onOptionsItemSelected() method.
c) Using Intent
We can also associate a menu item with an intent by using the MenuItem’s
method setIntent(intent). By default, a menu item has no intent associated with
it. But when an intent is associated with a menu item, and nothing else handles
the menu item, then the default behavior is to invoke the intent using
startActivity(intent).
ICON MENU
Android supports not only text but also images or icons as part of its
menu repertoire. We can use icons to represent menu items instead of and in
addition to text. Note a few limitations when it comes to using icon menus.
1) we can’t use icon menus for expanded menus. This restriction may be
lifted in the future, depending on device size and SDK support. Larger
devices may allow this functionality, whereas smaller devices may keep the
restriction.
2) Icon menu items do not support menu item check marks.
3) If the text in an icon menu item is too long, it’s truncated after a certain
number of characters, depending on the size of the display. (This last
limitation applies to text based menu items also).
SUB MENU
A Menu object can have multiple SubMenu objects. Each SubMenu
object is added to the Menu object through a call to the Menu.addSubMenu()
method. We add menu items to a submenu the same way that we add menu
items to a menu. This is because SubMenu is also derived from a Menu object.
However, we cannot add additional submenus to a submenu.
}
NOTE: SubMenu, as a subclass of the Menu object, continues to carry the
addSubMenu() method. The compiler won’t complain if we add a submenu to
another submenu, but we’ll get a runtime exception if we try to do it.
CONTEXT MENU
In Windows applications, for example, we can access a context menu
by right-clicking a UI element. Android supports the same idea of context menus
through an action called a long click. A long click is a mouse click held down
slightly longer than usual on any Android view. On handheld devices such as
cell phones, mouse clicks are implemented in a number of ways, depending on
the navigation mechanism. If our phone has a wheel to move the cursor, a press
of the wheel serves as the mouse click. Or if the device has a touch pad, a tap or
a press is equivalent to a mouse click. Or we might have a set of arrow buttons
for movement and a selection button in the middle; clicking that button is
equivalent to clicking the mouse. Regardless of how a mouse click is
implemented on our device, if we hold the mouse click a bit longer, we realize
the long click.
Although a context menu is owned by a view, the method to populate
context menus resides in the Activity class. This method is called
activity.onCreateContextMenu(), and its role resembles that of the
activity.onCreateOptionsMenu() method. This callback method also carries with
it (as an argument to the method) the view for which the context menu items are
to be populated. The steps to implement a context menu:
DYNAMIC MENUS
If we want to create dynamic menus, use the onPrepareOptionsMenu()
method that Android provides on an activity class. This method resembles
onCreateOptionsMenu() except that it is called every time a menu is invoked. We
should use onPrepareOptionsMenu() if we want to disable some menu items or
menu groups based on what we are displaying. For 3.0 and above, we have to
explicitly call a new provisioned method called invalidateOptionsMenu(), which in
turn invokes the onPrepareOptionsMenu(). We can call this method any time
something changes in our application state that would require a change to the
menu.
POPUP MENUS
SDK 4.0 enhanced this slightly by adding a couple of utility methods
(for example, PopupMenu.inflate) to the PopupMenu class. A pop-up menu can be
invoked against any view in response to a UI event. An example of a UI event is a
button click or a click on an image view. Figure 7–4 shows a pop-up menu
invoked against a view.
To create a pop-up menu like the one in Figure 7–4, start with a regular XML
menu file as shown in Listing 7–18.
Listing 7–18. A Sample XML File for a Pop-up Menu
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<!-- This group uses the default category. -->
<group android:id="@+id/menuGroup_Popup">
<item android:id="@+id/popup_menu_1"
android:title="Menu 1" />
<item android:id="@+id/popup_menu_2"
android:title="Menu 2" />
</group>
</menu>
FRAGMENTS IN ANDROID
A fragment is a piece of activity which enable more modular activity
design. It will not be wrong if we say a fragment is a kind of sub-activity. A
fragment has its own layout and behavior with life cycle. We can add or remove
fragments in an activity while the activity is running. We can combine multiple
fragments in a single activity to build a multi-plane UI. A fragment can be used
in multiple activities. A fragment can implement a behavior that has no user
interface component. Fragments were added to the android version HoneyComb
with API 11.0
STRUCTURE OF FRAGMENT
A fragment is like a sub-activity: it has a fairly specific purpose and
almost always displays a user interface. But where an activity is sub-classed
below Context, a fragment is extended from Object in package android.app. A
fragment is not an extension of Activity. A fragment can have a view hierarchy to
engage with a user. It can be created (inflated) from an XML layout specification
or created in code. A fragment has a bundle that serves as its initialization
arguments.
PERSISTENCE OF FRAGMENTS
When we play with this sample application, make sure we rotate the
device (pressing Ctrl+F11 rotates the device in the emulator). We will see that
the device rotates, and the fragments rotate right along with it. If we watch the
LogCat messages, we will see a lot of them for this application. During a device
rotation, pay careful attention to the messages about fragments; not only does
the activity get destroyed and recreated, but the fragments do also.
FragmentOther fragOther =
(FragmentOther)getFragmentManager().findFragmentByTag(“other”);
fragOther.callCustomMethod( arg1, arg2 );
In Listing 8–12, the current fragment has direct knowledge of the class of the
other fragment and also which methods exist on that class. This may be okay
because these fragments are part of one application, and it can be easier to
simply accept the fact that some fragments will know about other fragments.
STARTACTIVITY() AND SETTARGETFRAGMENT()
A feature of fragments that is very much like activities is the ability
of a fragment to stat an activity. Fragment has a startActivity() method and
startActivityForResult() method. These work just like the ones for activities;
when a result is passed back, it will cause the onActivityResult() callback to fire
on the fragment that started the activity. There’s another communication
mechanism we should know about. When one fragment wants to start another
fragment, there is a feature that lets the calling fragment set its identity with the
called fragment. The following example of what it might look like.
Listing 8–13. Fragment-to-Target-Fragment Setup
With these few lines, we’ve created a new CalledFragment object, set
the target fragment on the called fragment to the current fragment, and added
the called fragment to the fragment manager and activity using a fragment
transaction. When the called fragment starts to run, it will be able to call
getTargetFragment(), which will return a reference to the calling fragment. With
this reference, the called fragment could invoke methods on the calling fragment
or even access view components directly. For example, the called fragment could
set text in the UI of the calling fragment directly.
Listing 8–14. Target Fragment-to-Fragment Communication
TextView tv = (TextView)
getTargetFragment().getView().findViewById(R.id.text1);
tv.setText(“Set from the called fragment”);
This also means our application has the ability to dismiss the dialog
from code, which is powerful. If the dialog is displaying a busy message because
our application is doing something, as soon as our application has completed
that task, it can dismiss the dialog from code.
DIALOG FRAGMENTS
The use of dialog fragments is to present a simple alert dialog and a
custom dialog that is used to collect prompt text. Dialog-related functionality
uses a class called DialogFragment. A DialogFragment is derived from the class
Fragment and behaves much like a fragment. We will then use the
DialogFragment as the base class for our dialogs. Once we have a derived dialog
from this class such as
public class MyDialogFragment extends DialogFragment { ... }
The makeText() method in Listing 9–10 can take not only an activity
but any context object, such as the one passed to a broadcast receiver or a
service, for example. This extends the use of Toast outside of activities.
Title area: The Title area displays the title for the action bar.
Tabs area: The Tabs area is where the action bar paints the list of tabs
specified. The content of this area is variable. If the action bar navigation
mode is tabs, then tabs are shown here. If the mode is listnavigation mode,
then a navigable list of drop-down items is shown. In standard mode, this
area is ignored and left empty.
Action Icon area: Following the Tabs area, the Action Icon area shows
some of the option menu items as icons. We see how to choose which
option menus are displayed as action icons in the example later.
Menu Icon area: Last is the Menu Icon area. It is a single standard menu
icon. When we click this menu icon, we see the expanded menu. This
expanded menu looks different or shows up in a different location
depending on the size of the Android device. We can also attach a search
view as if it is an action icon of the menu.
Figure 10–1 shows a typical action bar in tabbed navigation mode.
DebugActivity.java: Base class activity that allows for a debug text view as
shown in Figure 10-1 (Listing 10-2)
BaseActionBarActivity.java: Derived from DebugActivity and allows for
common navigation (such as responding to common actions including
switching between the three activities) (Listing 10-3)
IReportBack.java: An interface that works as a communication vehicle
between the debug activity and the various listeners of the action bar
(Listing 10-1)
BaseListener.java: Base listener class that works with the DebugActivity
and the various actions that gets invoked from the action bar. Acts as a
base class for both tab listeners and list navigation listeners (Listing 10-4)
TabNavigationActionBarActivity.java: inherits from
BaseActionBarActivity.java and configures the action bar as a tabbed
action bar. Most of the code pertaining to the tabbed action bar is in this
class (Listing 10-6)
TabListener.java: Required to add a tab to the tabbed action bar. This
where we respond to tab clicks. In our case this simply logs a message to
the debug view through the BaseListener (Listing 10-5)
AndroidManifest.xml: Where activities are defined to be invoked (Listing
10-13)
Layout/main.xml: Layout file for the DebugActivity. Because all the three
status bar activities inherit this base DebugActivity, they all share this
layout file (Listing 10-7)
menu/menu.xml: A set of menu items to test the menu interaction with
the action bar. The menu file is also shared across all the derived status
bar activities (Listing 10-9)
TABBED LISTENER
Before we are able to work with a tabbed action bar, we need a
tabbed listener. A tabbed listener allows we to respond to the click events on the
tabs. We derive our tabbed listener from a base listener that allows we to log tab
actions. Listing 10–4 shows the base listener that uses the IReportBack for
logging.
Listing 10–4. A Common Listener for Action Bar Enabled Activities
//BaseListener.java
package com.androidbook.actionbar;
//Use CTRL-SHIFT-O to import dependencies
public class BaseListener
{
protected IReportBack mReportTo;
protected Context mContext;
public BaseListener(Context ctx, IReportBack target)
{
mReportTo = target;
mContext = ctx; } }
This base class holds a reference to an implementation of
IReportBack and also the activity that can be used as a context. This tabbed
listener documents the callbacks from the action bar tabs to the debug text. In
this case, the DebugActivity from Listing 10–2 is the implementer of IReportBack
and also plays the role of the context. Now that we have a base listener, Listing
10–5 shows the tabbed listener.
Listing 10–5. Tab Listener to Respond to Tab Actions
// TabListener.java
package com.androidbook.actionbar;
//
//Use CTRL-SHIFT-O to import dependencies
//
public class TabListener extends BaseListener
implements ActionBar.TabListener
{
private static String tag = "tc>";
public TabListener(Context ctx,
IReportBack target)
{
super(ctx, target);
}
public void onTabReselected(Tab tab,
FragmentTransaction ft)
{
this.mReportTo.reportBack(tag,
"ontab re selected:" + tab.getText());
}
public void onTabSelected(Tab tab,
FragmentTransaction ft)
{
this.mReportTo.reportBack(tag,
"ontab selected:" + tab.getText());
}
public void onTabUnselected(Tab tab,
FragmentTransaction ft)
{
this.mReportTo.reportBack(tag,
"ontab un selected:" + tab.getText());
}
}
This tabbed listener documents the callbacks from the action bar
tabs to the debug text view of Figure 10–1.
android:scrollbars="vertical"
android:scrollbarStyle="insideOverlay"
android:scrollbarSize="25dip"
android:scrollbarFadeDuration="0"
/>
</LinearLayout>
There are a few things worth noting about this layout. We set the
background color of the text view to white. This lets we capture screens in
brighter light. The text size is also set to a large font to aid screen capture. We
also set up the text view so that it is enabled for scrolling. Although typically
layouts use ScrollView, a text view is already enabled for scrolling by itself. In
addition to enabling the scrolling properties in the XML file for the text view, we
need to call the setMovementMethod() method on the text view as shown in
Listing 10–8. Enabling Text View for Scrolling
TextView tv = this.getTextView();
tv.setMovementMethod(
ScrollingMovementMethod.getInstance());
Once we have these three new files, we need to update the following two files:
BaseActionBarActivity.java: Uncomment the invocation of the list action
bar activity (Listing 10–3).
AndroidManifest.xml: Define the new list navigation action bar activity in
the manifest file (Listing 10–11).
SPINNER ADAPTER
To be able to initialize the action bar with list navigation mode, we
need the following two things:
A spinner adapter that can tell the list navigation what the list of
navigation text is
A list navigation listener so that when one of the list items is picked we
can get a call back
Listing 10–12 presents the SimpleSpinnerArrayAdapter that implements the
SpinnerAdapter interface. the goal of this class is to give a list of items to show.
Listing 10–12. Creating a Spinner Adapter for List Navigation
//SimpleSpinnerArrayAdapter.java
package com.androidbook.actionbar;
//Use CTRL-SHIFT-O to import dependencies
public class SimpleSpinnerArrayAdapter
extends ArrayAdapter<String>
implements SpinnerAdapter
{
public SimpleSpinnerArrayAdapter(Context ctx)
{
super(ctx,
android.R.layout.simple_spinner_item,
new String[]{"one","two"});
this.setDropDownViewResource(
android.R.layout.simple_spinner_dropdown_item);
}
public View getDropDownView(
int position, View convertView, ViewGroup parent)
{
return super.getDropDownView(
position, convertView, parent);
}
}
There is no SDK class that directly implements the SpinnerAdapter
interface required by list navigation. So, we derive this class from an
ArrayAdapter and provide a simple implementation for the SpinnerAdapter. At
the end of the chapter is a reference URL on spinner adapters for further
reading. Let’s move on now to the list navigation listener.
LIST LISTENER
This is a simple implementing the ActionBar.OnNavigationListener.
Listing 10–13 shows the code for this class.
Listing 10–13. Creating a List Listener for List Navigation
//ListListener.java
package com.androidbook.actionbar;
//Use CTRL-SHIFT-O to import dependencies
public class ListListener
extends BaseListener
implements ActionBar.OnNavigationListener
{
public ListListener(
Context ctx, IReportBack target)
{
super(ctx, target);
}
public boolean onNavigationItemSelected(
int itemPosition, long itemId)
{
this.mReportTo.reportBack(
"list listener","ItemPostion:" + itemPosition);
return true;
}
}
Like the tabbed listener in Listing 10–5, we inherit from our
BaseListener so that we can log events to the debug text view through the
IReportBack interface.
We used tabbed listeners while setting up the tabbed action bar and list
listeners for setting up the list navigation action bar. For a standard action bar,
there are no listeners other than the menu callbacks. The menu callbacks don’t
need to be specially set up because they are hooked up automatically by the
SDK. As a result, it is quite easy to set up the action bar in the standard
navigation mode. Listing 10–17 presents the source code for the standard
navigation action bar activity.
Listing 10–17. Standard Navigation Action Bar Activity
//StandardNavigationActionBarActivity.java
package com.androidbook.actionbar;
//Use CTRL-SHIFT-O to import dependencies
public class StandardNavigationActionBarActivity
extends BaseActionBarActivity
{
private static String tag=
"Standard Navigation ActionBarActivity";
public StandardNavigationActionBarActivity()
{
super(tag);
}
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
workwithStandardActionBar();
}
public void workwithStandardActionBar()
{
ActionBar bar = this.getActionBar();
bar.setTitle(tag);
bar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
//test to see what happens if we were to attach tabs
attachTabs(bar);
}
public void attachTabs(ActionBar bar)
{
TabListener tl = new TabListener(this,this);
Tab tab1 = bar.newTab();
tab1.setText("Tab1");
tab1.setTabListener(tl);
bar.addTab(tab1);
Tab tab2 = bar.newTab();
tab2.setText("Tab2");
tab2.setTabListener(tl);
bar.addTab(tab2);
}
}//eof-class