Tuesday, 21 August 2012

Android Essentials: Creating Simple User Forms

Step 0: Creating a Simple Android Project

Begin by creating a new Android project. You can also follow along using the source code provided as a supplement to this tutorial.

Step 1: Designing the Form

First, you need to give some thought to want kind of data you want to collect from the user. The form may have any number of fields. Consider the types of data you want to collect and choose the appropriate type of control. For example:
  • To collect text input, use EditText controls
  • To limit the user to a fixed set of responses, use Spinner controls, similar to a drop-down menu
  • To collect boolean (yes/no) input, use CheckBox controls
  • To allow the user to trigger events, use Button controls
For this tutorial, you will be designing a feedback form. This form collects five pieces of data from the user:
  • The user’s name (a string)
  • The user’s email (a string)
  • The type of feedback (options: Praise, Gripe, Suggestion or Bug)
  • The feedback message (a string)
  • Whether or not the user wants an email response (a boolean)

Step 2: Creating the Layout Resource

Begin by creating a layout resource for the form screen. The form will have a bunch of fields, which could span more than a single screen (depending on the device screen size), so you should consider wrapping the entire form within a ScrollView control to enable scrollbars.
The ScrollView control must have exactly one child view, so consider which layout control is most appropriate for the form you want to create. Forms are often contained within a vertically oriented LinearLayout control, so that the form fields cascade down the page vertically, one after another. This also helps the user’s focus move from field to field naturally.
A simple form layout resource might look like this:
view plaincopy to clipboardprint?
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <ScrollView  
  3.     xmlns:android="http://schemas.android.com/apk/res/android"  
  4.     android:id="@+id/ScrollView01"   
  5.     android:layout_width="wrap_content"  
  6.     android:layout_height="wrap_content"   
  7.     android:scrollbars="vertical">  
  8.     <LinearLayout   
  9.         android:layout_width="fill_parent"  
  10.         android:orientation="vertical"   
  11.         android:layout_height="fill_parent">  
  12.   
  13. <!--Put form controls here-->  
  14.   
  15.     </LinearLayout>  
  16. </ScrollView>    

Step 3: Add a TextView Control (Form Description)

Next, you need to add a TextView control within the LinearLayout control. The TextView control called TextViewTitle displays the form description and purpose to the user. This control displays a string resource called @string/feedbacktitle, which must be defined within the /res/values/strings.xml string resource file.
Here is the XML to add to your form layout resource file:
  1. <TextView   
  2.     android:id="@+id/TextViewTitle"  
  3.     android:layout_width="wrap_content"   
  4.     android:layout_height="wrap_content"  
  5.     android:text="@string/feedbacktitle"   
  6.     android:textSize="10pt">  
  7. </TextView>  

Step 4: Add an EditText Control (Name)

Now you need to add your first EditText control just below the TextView control you just created. This EditText control called EditTextName acts as a form field for the user’s name. You can use the hint attribute to supply a string to display in the EditText control when it’s empty (e.g. “Type your name here…”). You can also set the inputType attribute of the EditText control to apply name entering logic.
Here is the XML to add to your form layout resource file:
view plaincopy to clipboardprint?
  1. <EditText   
  2.     android:id="@+id/EditTextName"  
  3.     android:layout_height="wrap_content"  
  4.     android:hint="@string/feedbackname"  
  5.     android:inputType="textPersonName"  
  6.     android:layout_width="fill_parent">  
  7. </EditText>  

Step 5: Add another EditText Control (Email)

Next, you need to add your second EditText control just below the EditText control called EditTextName. This EditText control called EditTextEmail acts as a form field for the user’s email address. Again, set the hint attribute to supply a string to display in the EditText control when it’s empty. This time, set the inputType attribute of the EditText control to textEmailAddress, which will make entering emails easier on the user.
Here is the XML to add to your form layout resource file:
  1. <EditText  
  2.     android:id="@+id/EditTextEmail"  
  3.     android:layout_height="wrap_content"  
  4.     android:hint="@string/feedbackemail"  
  5.     android:inputType="textEmailAddress"  
  6.     android:layout_width="fill_parent">  
  7. </EditText>  

Step 6: Add a Spinner Control (Feedback Type)

Next, you need to add a Spinner control just below the EditText control you just created. This Spinner control called SpinnerFeedbackType allows the user to select the type of feedback from a fixed list of options (Praise, Gripe, Suggestion, or Bug).
First, you need to define these choices as individual string resources in the strings.xml resource file.
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <resources>  
  3.     <!--Other string resources also defined in this file… -->  
  4.     <string name="feedbacktype1">Praise</string>  
  5.     <string name="feedbacktype2">Gripe</string>  
  6.     <string name="feedbacktype3">Suggestion</string>  
  7.     <string name="feedbacktype4">Bug</string>  
  8. </resources>  
Next, create a string array resource using the individual string resources as follows in /res/values/arrays.xml:
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <resources>  
  3.     <string-array name="feedbacktypelist">  
  4.         <item>@string/feedbacktype1</item>  
  5.         <item>@string/feedbacktype2</item>  
  6.         <item>@string/feedbacktype3</item>  
  7.         <item>@string/feedbacktype4</item>  
  8.     </string-array>  
  9. </resources>  
Now you are ready to configure the Spinner control in your form layout. Begin by supplying the prompt attribute, which will provide a helpful string at the top of the Spinner control. Next, specify the list of string choices using the entries attribute—specifically, set the entries attribute to the string array you just defined: @array/feedbacktypelist.
Here is the XML to add to your form layout resource file:
  1. <Spinner  
  2.     android:id="@+id/SpinnerFeedbackType"  
  3.     android:layout_height="wrap_content"  
  4.     android:prompt="@string/feedbacktype"  
  5.     android:layout_width="fill_parent"  
  6.     android:entries="@array/feedbacktypelist">  
  7. </Spinner>  

Step 7: Add a Multi-Line EditText Control (Feedback)

Next, you need to add one more EditText control just below the Spinner control. This EditText control called EditTextFeedbackBody acts as a form field for the feedback text. Again, set the hint attribute to supply a string to display in the EditText control when it’s empty. This time you want to give the user ample space to write praise, gripes, suggestions, or describe bugs in the application. Therefore, you may want to set the inputType attribute of the EditText control to textMultiLine and specify the number of lines to draw using the lines attribute.
Here is the XML to add to your form layout resource file:
  1. <EditText  
  2.     android:id="@+id/EditTextFeedbackBody"  
  3.     android:layout_height="wrap_content"  
  4.     android:hint="@string/feedbackbody"  
  5.     android:inputType="textMultiLine"   
  6.     android:lines="5"  
  7.     android:layout_width="fill_parent">  
  8. </EditText>  

Step 8: Add a CheckBox Control

Next, you need to add a CheckBox control just below the EditText control you just created. This CheckBox control called CheckBoxResponse allows the user to choose whether or not they want to request an email response from the app developer. You can use the text attribute to supply a string to display next to the CheckBox control.
Here is the XML to add to your form layout resource file:
  1. <CheckBox  
  2.     android:id="@+id/CheckBoxResponse"  
  3.     android:layout_height="wrap_content"  
  4.     android:text="@string/feedbackresponse"  
  5.     android:layout_width="fill_parent">  
  6. </CheckBox>  

Step 9: Add a Button Control

Finally, you are ready to finish off the form with a Button control. If you want to have a button with text on it, use the Button control; if you prefer a button with a picture on it, use an ImageButton control instead. We will use a Button control here. First, set the text on the Button control using the text attribute. Next, you can easily register a click handler (as opposed to registering it programmatically in your Activity) for your Button control using the onClick attribute.
Here is the XML to add to your form layout resource file:
  1. <Button  
  2.     android:id="@+id/ButtonSendFeedback"  
  3.     android:layout_height="wrap_content"  
  4.     android:text="@string/feedbackbutton"  
  5.     android:onClick="sendFeedback"  
  6.     android:layout_width="fill_parent">  
  7. </Button>  
Excellent! You’ve finished designing your form. Now, all you need to do is implement the sendFeedback() method in your Activity.
Android SDK: Creating Forms

Step 10: Implement a Button click handler

In the Button control, you specified the onClick attribute as sendFeedback. Now you will need to implement a method called sendFeedback() within your Activity class. For example:
  1. public void sendFeedback(View button) {   
  2.     // Do click handling here  
  3. }  

Step 11: Reading Input from EditText Controls

Now that your form is designed and the controls have been implemented, you next need to collect the form data from the individual fields when the Button control is clicked.
For an EditText control, you use the getText() method.
  1. final EditText nameField = (EditText) findViewById(R.id.EditTextName);  
  2. String name = nameField.getText().toString();  
  3.   
  4. final EditText emailField = (EditText) findViewById(R.id.EditTextEmail);  
  5. String email = emailField.getText().toString();  
  6.   
  7. final EditText feedbackField = (EditText) findViewById(R.id.EditTextFeedbackBody);  
  8. String feedback = feedbackField.getText().toString();  

Step 12: Reading Input From Spinner Controls

Your form included a Spinner control. You use the getSelectedItem() method to read the data from this form control.
  1. final Spinner feedbackSpinner = (Spinner) findViewById(R.id.SpinnerFeedbackType);  
  2. String feedbackType = feedbackSpinner.getSelectedItem().toString();  
In this case, the selected item in the Spinner control is the String chosen by the user of the selected item.

Step 13: Reading Input from CheckBox Controls

Finally, your form included a CheckBox control. In this case, the result is just a flag to tell your application if the box was checked or not.
  1. final CheckBox responseCheckbox = (CheckBox) findViewById(R.id.CheckBoxResponse);  
  2. boolean bRequiresResponse = responseCheckbox.isChecked();  
You can use this Boolean value however you want in your app.

Step 14: Generate the Appropriate Email Details

Now that you’ve got all your form data, you’re ready to craft a message. Simply process all the data fields and build an appropriate feedback message. For example, you might use some fields in the message subject, and others in the message body. You can use format strings to help build the appropriate strings, the specifics of which will be discussed in an upcoming quick tip.
Android SDK: Creating Forms

Conclusion

In this tutorial, you learned how to use various types of input controls to design a feedback form within an Android application. The EditText control is versatile and powerful, allowing for many different types of text and freeform input. The Spinner and Checkbox controls help limit the user’s input to a specific set of responses. The Button control is a simple way to generate an event to process the form input.
There are many other controls worth exploring for use within forms. There is a lot more we could cover regarding good form design, how form controls fit into the Activity lifecycle, and how input methods and such factor into things, but for now, focus on gaining a good handle on the basics of form controls and how to use them.

Sunday, 19 August 2012

JavaServer Faces

JavaServer Faces (JSF) is a Java-based Web application framework intended to simplify development integration of web-based user interfaces.

JSF is a request-driven MVC web framework for constructing user interfaces using components. As a display technology, JSF 2 uses Facelets. Other view technologies such as XUL can also be employed. JSF 1.x uses JavaServer Pages (JSP) for its display technology. JavaServer Faces is a standardized technology which was formalized in a specification through the Java Community Process. It is part of the Java Platform, Enterprise Edition.
Core features

    Managed Beans: A dependency injection system (easily interfaced with CDI, Spring, or Guice) - also called "Backing Beans" or "Page Beans"
    A template-based component system, for rapid composite component creation - without the need for Java classes.
    Built-in Ajax support using <f:ajax /> (since JSF v2.0).
    Built-in support for bookmarking & page-load actions.
    Integration with the Unified Expression Language (EL), which is core to the function of JSF. Views may access managed bean fields and methods via EL: <my:component rendered="#{myBean.userLoggedIn}" />
    A default set of HTML and web-application specific UI components
    A server-side event model : For dispatching events and attaching listeners to core system functionality, such as "Before Render Response" or "After Validation"
    State management, supporting: "request", "session", "application", "flash", and "view" scoped Java beans.
    Two XML-based tag libraries (core and html) for expressing a JavaServer Faces interface within a view template (can be used with both JSP or Facelets)

Saturday, 18 August 2012

Android Date picker

 MyAndroidAppActivity.java
package com.mkyong.android;
 
import java.util.Calendar;
import android.app.Activity;
import android.app.DatePickerDialog;
import android.app.Dialog;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.DatePicker;
import android.widget.TextView;
 
public class MyAndroidAppActivity extends Activity {
 
 private TextView tvDisplayDate;
 private DatePicker dpResult;
 private Button btnChangeDate;
 
 private int year;
 private int month;
 private int day;
 
 static final int DATE_DIALOG_ID = 999;
 
 @Override
 public void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.main);
 
  setCurrentDateOnView();
  addListenerOnButton();
 
 }
 
 // display current date
 public void setCurrentDateOnView() {
 
  tvDisplayDate = (TextView) findViewById(R.id.tvDate);
  dpResult = (DatePicker) findViewById(R.id.dpResult);
 
  final Calendar c = Calendar.getInstance();
  year = c.get(Calendar.YEAR);
  month = c.get(Calendar.MONTH);
  day = c.get(Calendar.DAY_OF_MONTH);
 
  // set current date into textview
  tvDisplayDate.setText(new StringBuilder()
   // Month is 0 based, just add 1
   .append(month + 1).append("-").append(day).append("-")
   .append(year).append(" "));
 
  // set current date into datepicker
  dpResult.init(year, month, day, null);
 
 }
 
 public void addListenerOnButton() {
 
  btnChangeDate = (Button) findViewById(R.id.btnChangeDate);
 
  btnChangeDate.setOnClickListener(new OnClickListener() {
 
   @Override
   public void onClick(View v) {
 
    showDialog(DATE_DIALOG_ID);
 
   }
 
  });
 
 }
 
 @Override
 protected Dialog onCreateDialog(int id) {
  switch (id) {
  case DATE_DIALOG_ID:
     // set date picker as current date
     return new DatePickerDialog(this, datePickerListener, 
                         year, month,day);
  }
  return null;
 }
 
 private DatePickerDialog.OnDateSetListener datePickerListener 
                = new DatePickerDialog.OnDateSetListener() {
 
  // when dialog box is closed, below method will be called.
  public void onDateSet(DatePicker view, int selectedYear,
    int selectedMonth, int selectedDay) {
   year = selectedYear;
   month = selectedMonth;
   day = selectedDay;
 
   // set selected date into textview
   tvDisplayDate.setText(new StringBuilder().append(month + 1)
      .append("-").append(day).append("-").append(year)
      .append(" "));
 
   // set selected date into datepicker also
   dpResult.init(year, month, day, null);
 
  }
 };
 
}
P.S The “DatePickerDialog” example above, is referenced from Google Android date picker example, with some minor change.

3. Demo

Run the application.
1. Result, “date picker” and “textview” are set to current date.
android datepicker demo1

Thursday, 16 August 2012

Optimizing Battery Life

For your app to be a good citizen, it should seek to limit its impact on the battery life of its host device. After this class you will be able to build apps that monitor modify their functionality and behavior based on the state of the host device.
By taking steps such as disabling background service updates when you lose connectivity, or reducing the rate of such updates when the battery level is low, you can ensure that the impact of your app on battery life is minimized, without compromising the user experience
Monitoring the Battery Level and Charging State
Learn how to alter your app's update rate by determining, and monitoring, the current battery level and changes in charging state.
Determining and Monitoring the Docking State and Type
Optimal refresh rates can vary based on how the host device is being used. Learn how to determine, and monitor, the docking state and type of dock being used to affect your app's behavior.
Determining and Monitoring the Connectivity Status
Without Internet connectivity you can't update your app from an online source. Learn how to check the connectivity status to alter your background update rate. You'll also learn to check for Wi-Fi or mobile connectivity before beginning high-bandwidth operations.
Manipulating Broadcast Receivers On Demand
Broadcast receivers that you've declared in the manifest can be toggled at runtime to disable those that aren't necessary due to the current device state. Learn to improve efficiency by toggling and cascading state change receivers and delay actions until the device is in a specific state.

Wednesday, 15 August 2012

Android Custom Components


Android offers a sophisticated and powerful componentized model for building your UI, based on the fundamental layout classes: View and ViewGroup. To start with, the platform includes a variety of prebuilt View and ViewGroup subclasses — called widgets and layouts, respectively — that you can use to construct your UI.

A partial list of available widgets includes Button, TextView, EditText, ListView, CheckBox, RadioButton, Gallery, Spinner, and the more special-purpose AutoCompleteTextView, ImageSwitcher, and TextSwitcher.

Among the layouts available are LinearLayout, FrameLayout, RelativeLayout, and others. For more examples, see Common Layout Objects.

If none of the prebuilt widgets or layouts meets your needs, you can create your own View subclass. If you only need to make small adjustments to an existing widget or layout, you can simply subclass the widget or layout and override its methods.

Creating your own View subclasses gives you precise control over the appearance and function of a screen element. To give an idea of the control you get with custom views, here are some examples of what you could do with them:

    You could create a completely custom-rendered View type, for example a "volume control" knob rendered using 2D graphics, and which resembles an analog electronic control.
    You could combine a group of View components into a new single component, perhaps to make something like a ComboBox (a combination of popup list and free entry text field), a dual-pane selector control (a left and right pane with a list in each where you can re-assign which item is in which list), and so on.
    You could override the way that an EditText component is rendered on the screen (the Notepad Tutorial uses this to good effect, to create a lined-notepad page).
    You could capture other events like key presses and handle them in some custom way (such as for a game).

The sections below explain how to create custom Views and use them in your application. For detailed reference information, see the View class.
The Basic Approach

Here is a high level overview of what you need to know to get started in creating your own View components:

    Extend an existing View class or subclass with your own class.
    Override some of the methods from the superclass. The superclass methods to override start with 'on', for example, onDraw(), onMeasure(), and onKeyDown(). This is similar to the on... events in Activity or ListActivity that you override for lifecycle and other functionality hooks.
    Use your new extension class. Once completed, your new extension class can be used in place of the view upon which it was based.

Tip: Extension classes can be defined as inner classes inside the activities that use them. This is useful because it controls access to them but isn't necessary (perhaps you want to create a new public View for wider use in your application).
Fully Customized Components

Fully customized components can be used to create graphical components that appear however you wish. Perhaps a graphical VU meter that looks like an old analog gauge, or a sing-a-long text view where a bouncing ball moves along the words so you can sing along with a karaoke machine. Either way, you want something that the built-in components just won't do, no matter how you combine them.

Fortunately, you can easily create components that look and behave in any way you like, limited perhaps only by your imagination, the size of the screen, and the available processing power (remember that ultimately your application might have to run on something with significantly less power than your desktop workstation).

To create a fully customized component:

    The most generic view you can extend is, unsurprisingly, View, so you will usually start by extending this to create your new super component.
    You can supply a constructor which can take attributes and parameters from the XML, and you can also consume your own such attributes and parameters (perhaps the color and range of the VU meter, or the width and damping of the needle, etc.)
    You will probably want to create your own event listeners, property accessors and modifiers, and possibly more sophisticated behavior in your component class as well.
    You will almost certainly want to override onMeasure() and are also likely to need to override onDraw() if you want the component to show something. While both have default behavior, the default onDraw() will do nothing, and the default onMeasure() will always set a size of 100x100 — which is probably not what you want.
    Other on... methods may also be overridden as required.

Extend onDraw() and onMeasure()

The onDraw() method delivers you a Canvas upon which you can implement anything you want: 2D graphics, other standard or custom components, styled text, or anything else you can think of.

Note: This does not apply to 3D graphics. If you want to use 3D graphics, you must extend SurfaceView instead of View, and draw from a separate thread. See the GLSurfaceViewActivity sample for details.

onMeasure() is a little more involved. onMeasure() is a critical piece of the rendering contract between your component and its container. onMeasure() should be overridden to efficiently and accurately report the measurements of its contained parts. This is made slightly more complex by the requirements of limits from the parent (which are passed in to the onMeasure() method) and by the requirement to call the setMeasuredDimension() method with the measured width and height once they have been calculated. If you fail to call this method from an overridden onMeasure() method, the result will be an exception at measurement time.

At a high level, implementing onMeasure() looks something like this:

    The overridden onMeasure() method is called with width and height measure specifications (widthMeasureSpec and heightMeasureSpec parameters, both are integer codes representing dimensions) which should be treated as requirements for the restrictions on the width and height measurements you should produce. A full reference to the kind of restrictions these specifications can require can be found in the reference documentation under View.onMeasure(int, int) (this reference documentation does a pretty good job of explaining the whole measurement operation as well).
    Your component's onMeasure() method should calculate a measurement width and height which will be required to render the component. It should try to stay within the specifications passed in, although it can choose to exceed them (in this case, the parent can choose what to do, including clipping, scrolling, throwing an exception, or asking the onMeasure() to try again, perhaps with different measurement specifications).
    Once the width and height are calculated, the setMeasuredDimension(int width, int height) method must be called with the calculated measurements. Failure to do this will result in an exception being thrown.

Here's a summary of some of the other standard methods that the framework calls on views:

Friday, 10 August 2012

HTC One X Android 4.0.4 update bringing better Beats today




HTC has announced that it is pushing out an update for the HTC One X today that will make a number of OS improvements.

Android 4.0.4 has been making its way to a number of handsets recently and now the HTC One X can be added to the list, with HTC saying about the update: "As part of our ongoing commitment to ensure customers are receiving software updates that improve their user experience, we are pleased to announce our next upgrade for the HTC One X will be released on August 10."

HTC also revealed in its statement the features that have been enhanced with the update.

"The primary update will include an upgrade to Android version 4.0.4 (Ice Cream Sandwich), in addition to an improved Sense experience which will: enable the ability to map menu function to the 'recent app' key (improving visual presentation in non ICS apps like Facebook); improve tab management in the browser with a dedicated tab switching button and enhance camera capabilities such as white balance and continuous autofocus," it explained.
Improvements

"Customers can expect enhancements to memory, platform stability and the overall browsing experience.

"Other improvements include a Single Sign-On for Facebook allowing user access across applications and browsers and upgrades to Beats audio, which reflect our dedication to providing an authentic sound experience."

Considering in our HTC One X review we gave the phone 4.5 stars, these updates look set to strengthen what is already a great phone.

HTC revealed this week that it will be issuing Android 4.0 updates to all its ICS phones by the end of August.


Android 4.0.4 Features
Enhances camera App
Adds Menu functionality to multitasking button
Stability improvements
Better camera performance
Smoother screen rotation
Improved phone number recognition

Use jQuery Mobile to Build a Native Android News Reader App

Use jQuery Mobile to Build a Native Android News Reader App: Part 3

Converting Into A Native Android Application

The web application completed in Part 2 will now be converted into a native Android application. The discussion below applies to Android OS 2.2 & 2.3.
The Android application will use index.html as its UI component. We will write an android.app.Activity class to define the integration point between index.html and the native application. We will also write an android.webkit.WebViewClient class to make sure that the News Detail page is displayed inside the original android.webkit.WebView instance where the News application is launched.

Changes In index.html

We will update the NEWS_URI variable as follows:
  1. var NEWS_URI = 'http://rss.news.yahoo.com/rss/';  
We do not need bridge.php in the native Android application to forward AJAX calls to Yahoo! News. This is because the same-origin restriction does not apply here. When packaged as part of the native application, the index.html file is not downloaded from a web server. As such, it can make AJAX calls to remote URLs.
In addition, we add the following function:
  1. var EMPTY = '';  
  2. ...  
  3. function changeLocation(varURI){  
  4.   showProgress();     
  5.   $.get(EMPTY,function(data){  
  6.     window.location = varURI;  
  7.   });     
  8. }  
The changeLocation() function will be called from the android.webkit.WebViewClient, which will be shown momentarily. The purpose of the function is to show the progress page during transition from the News page to the News Detail page.
  • The first step in changeLocation() is to display the progress page.
  • Remember that the jQuery get() function is a specialized jQuery ajax() function. We call get() passing to it an empty URL and a callback handler, that sets the window.location variable to the input argument. The input argument is the URL in the <a href='...'> attribute enclosed within an a tag for a news item, as discussed in Part 2, “Going To The News Detail Page From The News Page”. When the URL loads, the progress page is replaced with contents from that URL.
  • As we point out below, the function changeLocation() is not an essential part of migrating the web application into a native one. It is only needed to display a progress page when transitioning from the News page to the News Detail page in the native application.
  • A progress page is not needed in the web application when transitioning from the News page to the News Detail page. This is because during the transition the web browser itself displays a progress indicator to the user. For example, in Android, both the native and Dolphin browsers display a spinning wheel and a progress bar in the navigation toolbar. In iOS, the Safari browser displays a similar progress indicator.

The Activity Class

The initial portion of our Activity class, named NewsActivity is shown below:
  1. package com.news;  
  2.   
  3. import android.app.Activity;  
  4. import android.webkit.WebView;  
  5. import android.os.Bundle;  
  6. ...  
  7. public class NewsActivity extends Activity {  
  8.     WebView mWebView;  
  9.   
  10.   public void onCreate(Bundle savedInstanceState) {  
  11.     super.onCreate(savedInstanceState);  
  12.     setContentView(R.layout.main);  
  13.   
  14.     mWebView = (WebView) findViewById(R.id.webview);  
  15.     mWebView.setWebViewClient(new NewsClient());  
  16.     mWebView.getSettings().setJavaScriptEnabled(true);  
  17.     mWebView.getSettings().setDomStorageEnabled(true);  
  18.     mWebView.loadUrl("android_asset/www/index.html");  
  19.   }  
  20.   ...  
  21. }  
  • In the onCreate() method, we first call the default implementation from the super class and then invoke setContentView() to load the layout file for this Activity. The input argument to setContentView() is R.layout.main which is a reference to main.xml in the res/layout folder.
  • We get a handle to the WebView via findViewById(R.id.webview). We set a custom WebViewClient on the WebView, named NewsClient (to be reviewed soon). Then, we configure the WebView to allow JavaScript execution and the DOM storage API (the latter is necessary to use HTML5 localStorage).
  • Finally, we ask the WebView to load the index.html page that has the UI code.
On the News Detail page, pressing the back button of the device will take the user back to the Categories page. To be assured of that, we first need to handle the onKeyDown event in our NewsActivity. This is shown below:
  1. public class NewsActivity extends Activity {  
  2. WebView mWebView;  
  3.   
  4.  public void onCreate(Bundle savedInstanceState) {  
  5.    ...  
  6.  }  
  7.    
  8.  public boolean onKeyDown(int keyCode, KeyEvent event) {  
  9.    if ((keyCode == KeyEvent.KEYCODE_BACK) && mWebView.canGoBack()) {  
  10.      mWebView.goBack();              
  11.      return true;  
  12.    }  
  13.    return super.onKeyDown(keyCode, event);  
  14.  }    
  15.  ...  
If the key event corresponds to the back button of the device and the WebView has history to go back to, we then ask the WebView to go back a single step in its history. In the News Detail page, this will correspond to index.html. When history goes one step back, the Categories page will be displayed following the steps described in Part 2, “Application Startup”.
Lastly, let us look at the custom WebViewClient which is implemented as an inner class of NewsActivity.
  1.  public class NewsActivity extends Activity {  
  2.     WebView mWebView;  
  3.   
  4.   public void onCreate(Bundle savedInstanceState) {  
  5.     ...  
  6.     mWebView.setWebViewClient(new NewsClient());  
  7.     ...  
  8.   }  
  9.     
  10.   public boolean onKeyDown(int keyCode, KeyEvent event) {  
  11.     ...  
  12.   }    
  13.     
  14.   private class NewsClient extends WebViewClient {  
  15.   
  16.     public boolean shouldOverrideUrlLoading(WebView view, String url) {  
  17.       view.loadUrl("javascript:changeLocation('" + url + "')");  
  18.       return true;  
  19.     }  
  20.   }  
  21. ...  
  22. }  
  23.    
The only operation we override from the parent class is shouldOverrideUrlLoading() where we instruct the WebView to call the JavaScript function changeLocation() in index.html.
  • Had we not defined a custom WebViewClient, the News Detail page would be displayed in a separate browser application, outside the News application. Therefore, defining a custom WebViewClient is essential to display the News Detail page as part of the News application (i.e. in the same WebView that hosts the index.html).
  • We could have written shouldOverrideUrlLoading()in a more simplified manner, as follows:
    1. public boolean shouldOverrideUrlLoading(WebView view, String url)  
    2. {  
    3.     view.loadUrl(url);  
    4.     return true;  
    5. }  
    That would be sufficient to display the News Detail page in the same WebView that hosts index.html. However, the transition from the News page to the News Detail page would not include showing the progress page.
Having reviewed the Activity class, let us look at other components of our application.

AndroidManifest.xml

  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <manifest xmlns:android="http://schemas.android.com/apk/res/android"  
  3.   package="com.news" android:versionCode="1" android:versionName="1.0">  
  4.     <application android:icon="@drawable/icon" android:label="@string/app_name">  
  5.       <activity android:name=".NewsActivity" android:configChanges="orientation|keyboardHidden"  
  6.         android:label="@string/app_name">  
  7.           <intent-filter>  
  8.             <action android:name="android.intent.action.MAIN" />  
  9.             <category android:name="android.intent.category.LAUNCHER" />  
  10.           </intent-filter>  
  11.       </activity>  
  12.     </application>  
  13.     <uses-permission android:name="android.permission.INTERNET" />  
  14. </manifest>   
For a general discussion on the AndroidManifest.xml file refer to the official reference. In that file, there are two particular items worthy of commenting on.
  • As described in the android.app.Activity documentation, by default, a configuration change, including a change in orientation or keyboard accessibility, results in the current activity being destroyed. To prevent the default behavior, we configure our application by specifying the configuration changes that will be handled by the application itself. This is defined in the configChanges attribute where orientation corresponds to orientation change and keyboardHidden corresponds to a keyboard accessibility change (e.g. a user lays open the device keyboard). We are configuring the application so that if any of those changes occur, the current activity is not destroyed.
  • The element <uses-permission android:name="android.permission.INTERNET" /> allows the application to access the Internet.

strings.xml

  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <resources>  
  3.   <string name="app_name">News</string>  
  4. </resources>  
This file defines the constant named app_name which is used to identify the News application. The value of that attribute is displayed in various places in our Android device, as shown below. From left to right: under the application launch icon, the application title bar, Settings – Manage applications.