Archive
Dealing with AsyncTask and Screen Orientation
A common task in Android is to perform some background activity in another thread, meanwhile displaying a ProgressDialog to the user. Example of these tasks include downloading some data from internet, logging into an application, etc. Implementing an AsyncTask is fairly a simple job, the big challenge is how to handle it properly when an orientation change occurs.
In this article I will walk though a series of potential solutions to address the screen orientation issues when using an AsyncTask.
So, lets create a proof of concept application that makes use of an AsyncTask which does not handle configuration changes yet, and then present a few solutions.
Here’s the AsyncTask implementation that we will be using during the tutorial:
public class AsyncTaskExample extends AsyncTask<String, Integer, String> {
private final TaskListener listener;
public AsyncTaskExample(TaskListener listener) {
this.listener = listener;
}
@Override
protected void onPreExecute() {
listener.onTaskStarted();
}
@Override
protected String doInBackground(String... params) {
for (int i = 1; i <= 10; i++) {
Log.d("GREC", "AsyncTask is working: " + i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return "All Done!";
}
@Override
protected void onPostExecute(String result) {
listener.onTaskFinished(result);
}
}
- doInBackground() – this will be called by the AsyncTask on a background thread, and performs all the heavy work. For the sake of this example, I just wrote a simple loop with a delay of 1 sec between iterations to simulate a task that takes some time.
- The constructor of the class takes a listener as a parameter. The listener will be used to delegate the work of onPreExecute()/onPostExecute() to the calling Activity.
This is the interface definition used by AsyncTaskExample:
public interface TaskListener {
void onTaskStarted();
void onTaskFinished(String result);
}
And here’s the usage of AsyncTaskExample (the problematic case):
public class MainActivity extends Activity implements TaskListener, OnClickListener {
private ProgressDialog progressDialog;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
findViewById(R.id.start).setOnClickListener(this);
}
@Override
public void onClick(View v) {
if (v.getId() == R.id.start) {
new AsyncTaskExample(this).execute();
}
}
@Override
public void onTaskStarted() {
progressDialog = ProgressDialog.show(CopyOfMainActivity.this, "Loading", "Please wait a moment!");
}
@Override
public void onTaskFinished(String result) {
if (progressDialog != null) {
progressDialog.dismiss();
}
}
}
The Activity implements the TaskListener interface and provides appropriate implementation for its methods, displaying the ProgressDialog when the task is started, and dismissing it when the task is finished. The AsyncTask is fired when clicking on a button.
Now, if you run this example without changing the screen orientation, the AsyncTask will start and finish its work normally. Problems begin to appear when the device orientation is changed while the AsyncTask is in the middle of the work. The application will crash, and an exception similar to these ones will be thrown: java.lang.IllegalArgumentException: View not attached to window manager, or Activity has leaked window com.android.internal.policy….
The cause relies in the Activity life cycle. A change in device orientation is interpreted as a configuration change which causes the current activity to be destroyed and then recreated. Android calls onPause(), onStop(), and onDestroy() on currently instance of activity, then a new instance of the same activity is recreated calling onCreate(), onStart(), and onResume(). The reason why Android have to do this, is because depending of screen orientation, portrait or landscape, we may need to load and display different resources, and only through re-creation Android can guarantee that all our resources will be re-requested.
But don’t panic, you are not alone, there are several solutions that will help us to deal with this situation.
Solution 1 – Think twice if you really need an AsyncTask.
AsyncTasks are good for performing background work, but they are bound to the Activity which adds some complexity. For things like making HTTP requests to a server perhaps you should consider an IntentService. IntentService used in conjunction with a BroadcastReceiver or ResultReceiver to deliver results, could do a better job than an AsyncTask in certain situations.
Solution 2 – Put the AsyncTask in a Fragment.
Using fragments probably is the cleanest way to handle configuration changes. By default, Android destroys and recreates the fragments just like activities, however, fragments have the ability to retain their instances, simply by calling: setRetainInstance(true), in one of its callback methods, for example in the onCreate().
There’s however one aspect that should be taken in consideration in order to achieve the desired result. Our AsyncTask uses a ProgressDialog to signal when the AsyncTask is started, and dismisses it when the task is done. This complicates a bit the things because even if we are using setRetainInstance(true), we should close all windows and dialogs when the Activity is destroyed, otherwise we will get an: Activity has leaked window com.android.internal.policy… exception. This happens when you try to show a dialog after you have exited the Activity.
In order to address this issue, we will add some logic to keep track of AsyncTask status (running/not running). We will dismiss the ProgressDialog when the fragment is detached from activity, and check in onActivityCreated() the status of AsyncTask. If the status is “running”, this means we are returning from a screen orientation and we will just re-create and display the ProgressDialog to show that the AsyncTask is still working.
public class ExampleFragment extends Fragment implements TaskListener, OnClickListener {
private ProgressDialog progressDialog;
private boolean isTaskRunning = false;
private AsyncTaskExample asyncTask;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
// If we are returning here from a screen orientation
// and the AsyncTask is still working, re-create and display the
// progress dialog.
if (isTaskRunning) {
progressDialog = ProgressDialog.show(getActivity(), "Loading", "Please wait a moment!");
}
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_layout, container, false);
Button button = (Button) view.findViewById(R.id.start);
button.setOnClickListener(this);
return view;
}
@Override
public void onClick(View v) {
if (!isTaskRunning) {
asyncTask = new AsyncTaskExample(this);
asyncTask.execute();
}
}
@Override
public void onTaskStarted() {
isTaskRunning = true;
progressDialog = ProgressDialog.show(getActivity(), "Loading", "Please wait a moment!");
}
@Override
public void onTaskFinished(String result) {
if (progressDialog != null) {
progressDialog.dismiss();
}
isTaskRunning = false;
}
@Override
public void onDetach() {
// All dialogs should be closed before leaving the activity in order to avoid
// the: Activity has leaked window com.android.internal.policy... exception
if (progressDialog != null && progressDialog.isShowing()) {
progressDialog.dismiss();
}
super.onDetach();
}
}
Solution 3 – Lock the screen orientation
You could do this in 2 ways:
a) permanently locking the screen orientation of the activity, specifying the screenOrientation attribute in the AndroidManifest with “portrait” or “landscape” values:
<activity android:screenOrientation="portrait" ... />
b) or, temporarily locking the screen in onPreExecute(), and unlocking it in onPostExecute(), thus preventing any orientation change while the AsyncTask is working:
@Override
public void onTaskStarted() {
lockScreenOrientation();
progressDialog = ProgressDialog.show(CopyOfCopyOfMainActivity.this, "Loading", "Please wait a moment!");
}
@Override
public void onTaskFinished(String result) {
if (progressDialog != null) {
progressDialog.dismiss();
}
unlockScreenOrientation();
}
private void lockScreenOrientation() {
int currentOrientation = getResources().getConfiguration().orientation;
if (currentOrientation == Configuration.ORIENTATION_PORTRAIT) {
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
} else {
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
}
}
private void unlockScreenOrientation() {
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR);
}
Solution 4 – Prevent the Activity from being recreated.
This is the easiest way to handle configuration changes, but the less advised. The only thing you need to do is to specify the configChanges attribute followed by a list of values that specifies when the activity should prevent itself from restarting.
<activity android:configChanges="orientation|keyboardHidden" android:name=".MainActivity" .... />
Using this approach however, is not recommended, and this is clearly stated in the Android documentation: Using this attribute should be avoided and used only as a last-resort.
You may ask what’s wrong with this approach. Well, if you build the above example against Android 2.2 it will work fine, but if you build it against Android 3.0 and higher, you may notice that the application still crashes on orientation change. This is because starting with Android 3.0 you need also to handle the screenSize, and smallestScreenSize:
<activity android:configChanges="orientation|keyboardHidden|screenSize|smallestScreenSize" android:name=".MainActivity" .... />
As it turns out, not only a screen orientation causes the Activity to recreate, there are also other events which may produce configuration changes and restart the Activity, and there’s a good chance that we won’t handle them all. This is why the use of this technique is discouraged.
Integrating Google Analytics SDK (V2) with Android
The Google Analytics SDK for Android makes it easy for developers to collect valuable statics about how the users are using their app.
Here are some features that Android Google Analytics SDK offers:
- The number of active users that are using the application
- Usage of specific features
- The number and type of application crashes
- From where in the world the application is used
- And many other useful metrics.
Just to illustrate the integration process lets create a simple proof of concept application with 2 activities: MainActivity and AboutActivity, and 2 buttons: Rate and Share.
Our mission is to integrate Google Analytics SDK with the application, to:
- track activity views, (MainActivity and About)
- track events (how many times the buttons “Rate”, and “Share” are clicked)
If you are searching for Google Analytics I’m assuming you are already pretty familiar with Android and could create the proof of concept application yourself, so I will skip this step and concentrate solely on integration.
1. Downloading the SDK
Go to downloads page and download GoogleAnalyticsAndroid.zip Version 2.0. Extract the archive and add libGoogleAnalyticsV2.jar to your project’s /libs directory.
At the moment of writing this post, Google provides two versions: version 1.5.1 (legacy), and version 2.0 beta. Still if the Version 2 of SDK is beta, I highly suggest you choose this version, over the 1.5.1 (legacy).
The reason not to choose SDK 1.5.1 is that it uses a tracking model that is designed to track visitors to traditional websites and interaction with widgets in traditional web pages.
The new “App” profiles and reports will only accept data from version 2 or higher of the SDK.
2. Creating a Google Analytics account
Before starting to use the SDK you first must create an account at: http://www.google.com/analytics/
- Sign in to your account.
- Click Admin.
- Click Account list (just below the menu bar)
- Click +New Account
- When asked what you would like to track, select App property.

- Enter all the necessary information and click Get Tracking ID.
Now that you have a Tracking ID, you can begin the integration with the application. The first step is to update the AndroidManifest file.
3. Updating AndroidManifest file.
Add folowing permissions to the AndroidManifest file:
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
4. Creating the analytics.xml file
In version 2 of Google Analytics SDK for Android, the tracking settings are managed from an xml resource file called: analytics.xml. You will need to create this file in res/values directory, and add your tracking ID as well as other settings here.
<?xml version="1.0" encoding="utf-8"?> <resources> <!-- Replace placeholder ID with your tracking ID --> <string name="ga_trackingId">UA-00000000-0</string> <!-- Enable Activity tracking --> <bool name="ga_autoActivityTracking">true</bool> <!-- Enable debug --> <bool name="ga_debug">true</bool> <!-- The screen names that will appear in your reporting --> <string name="com.testgoogleanalytics.MainActivity">MainActivity</string> <string name="com.testgoogleanalytics.About">About</string> <!-- The inverval of time after all the collected data should be sent to the server, in seconds. --> <integer name="ga_dispatchPeriod">30</integer> </resources>
5. Tracking activities.
To track activities add the tracking methods to the onStart() and onStop() of each of your activities.
// Example of tracking MainActivity
public class MainActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
@Override
protected void onStart() {
super.onStart();
EasyTracker.getInstance().activityStart(this); // Add this method
}
@Override
protected void onStop() {
super.onStop();
EasyTracker.getInstance().activityStop(this); // Add this method
}
}
One thing to note here is that EasyTraker requires a context before you can use it. If you attempt to call any of its methods but did not pass first a context, you may end up with an IllegalStateException.
In the above example, in the onStart() and onStop() methods the context is passed as an argument to activityStart() and activityStop(), but if you need to make EasyTracker calls in other classes or methods, you’ll need to call EasyTracker’s setContext(Context context) method first:
Context context= this; // Get current context. EasyTracker.getInstance().setContext(context); // Set context // EasyTracker is now ready for use.
6. Tracking events
Tracking events is just as easy as tracking activities, you just need a Tracker object and call the trackEvent(String category, String action, String label, int value) method.
public class MainActivity extends Activity {
private Tracker tracker;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Set context
EasyTracker.getInstance().setContext(getApplicationContext());
// Instantiate the Tracker
tracker = EasyTracker.getTracker();
// Add tracking functionality to "Rate" button
Button rate = (Button) findViewById(R.id.rate);
rate.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
// The rest of your code
tracker.trackEvent("Buttons Category", "Rate", "", 0L);
}
});
// Add tracking functionality to "Share" button....
}
}
In this particular example I don’t need a label nor a value, that is why I set for the last 2 parameters of trackEvent() method, an empty string a 0 (zero), but depending of your needs you may populate them with some data.
7. Debugging
Debugging helps you deal with troubleshooting, and make you sure that the data actually is sent to the server. To set the Google Analytics in debug mode, add the following setting in the analytics.xml
<bool name="ga_debug">true</bool>
Once your are in debug mode, you can watch the log information in LogCat:
Waiting for the big moment!
If everything is configured correctly, the reports should appear on live. Usually it takes about 24 hours to see the data in your account.
What happens if my application is used when no network is available?
Just in case you asked this yourself…, all the events are persisted in a local storage, and they will be sent the next time your app is running and dispatch is called.
Last but not least
One important thing not to be forgotten: you must indicate to your users, either in the application itself or in your terms of service, that you reserve the right to anonymously track and report a user’s activity inside of your app.
Android Google Analytics SDK offers more than tracking activities and events, see: https://developers.google.com/analytics/devguides/collection/android/v2/ to get the most out of it.
Please visit the Android Tutorials page for more tutorials.
Android Asset Studio – The easiest way to create icons for your android apps!
Android Asset Studio is an online utility that lets you generate all kind of icons you may need for your android applications, starting with launcher icons, action bar and tab icons, notification icons, and menu icons. It even includes a simple 9-patch generator allowing you to create 9-patch images.
One of the trickier parts when creating the icons is that you should create them for all kinds of resolutions: ldpi, mdpi, hdpi, and xhdpi. With Android Asset Studio this is as simple as uploading an image. The tool generates automatically for you all the versions of the icon under all resolutions, and make them available as a downloadable zip archive.
The icons may be generated from an image uploaded, or from a clipart library, or from text. It’s a very convenient tool and I highly recommend using it if you want to have professional, good looking icons on all resolutions.
How to create popups in Android
In this post I’ll show you how to create a popup window in Android. A popup window can be used to display an arbitrary view, and it can be very convenient in cases when you want to display an additional information, but don’t want or it’s not appropriate to launch a new activity or display a dialog.
The final output should look like this:
We will use the PopupWindow class to create the popup.
One thing I would like to mention is that we want the popup to be attached to the button that opened it. For example if the “Show Popup” button from the screenshot above would be positioned in the middle of the screen, we want the popup window stick to the button’s position. To achieve this, first we should get the button’s “x” and “y” position on the screen, and pass them to the popup window. Then will we use an offset to align the popup properly – a bit to the right, and a bit down, so it won’t overlap the whole button.
Another think I would like to mention is that we will use a 9 patch background image for the popup, so it will look more fancy. But of course you can skip it and put any background you want, or no background at all.
9 patch image:
Put the image into res/drawable directory.
1. Create a new project in Eclipse:
Project: TestPopup
Activity: TestPopupActivity
2. Open layout/main.xml file and add a button
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:background="#CCC" android:orientation="vertical" > <Button android:id="@+id/show_popup" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Show Popup" /> </LinearLayout>
3. Create a new layout file: layout/popup_layout.xml that defines the layout of popup.
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="wrap_content" android:id="@+id/popup" android:layout_height="wrap_content" android:background="@drawable/popup_bg" android:orientation="vertical" > <TextView android:id="@+id/textView1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Popup" android:textAppearance="?android:attr/textAppearanceLarge" /> <TextView android:id="@+id/textView2" android:layout_marginTop="5dp" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="This is a simple popup" /> <Button android:id="@+id/close" android:layout_marginTop="10dp" android:layout_gravity="center_horizontal" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Close" /> </LinearLayout>
4. And now the most interesting part. Open the TestPopupActivity and fill it with below code. Carefully read the comments to understand what’s going on.
public class TestPopupActivity extends Activity {
//The "x" and "y" position of the "Show Button" on screen.
Point p;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Button btn_show = (Button) findViewById(R.id.show_popup);
btn_show.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
//Open popup window
if (p != null)
showPopup(TestPopupActivity.this, p);
}
});
}
// Get the x and y position after the button is draw on screen
// (It's important to note that we can't get the position in the onCreate(),
// because at that stage most probably the view isn't drawn yet, so it will return (0, 0))
@Override
public void onWindowFocusChanged(boolean hasFocus) {
int[] location = new int[2];
Button button = (Button) findViewById(R.id.show_popup);
// Get the x, y location and store it in the location[] array
// location[0] = x, location[1] = y.
button.getLocationOnScreen(location);
//Initialize the Point with x, and y positions
p = new Point();
p.x = location[0];
p.y = location[1];
}
// The method that displays the popup.
private void showPopup(final Activity context, Point p) {
int popupWidth = 200;
int popupHeight = 150;
// Inflate the popup_layout.xml
LinearLayout viewGroup = (LinearLayout) context.findViewById(R.id.popup);
LayoutInflater layoutInflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View layout = layoutInflater.inflate(R.layout.popup_layout, viewGroup);
// Creating the PopupWindow
final PopupWindow popup = new PopupWindow(context);
popup.setContentView(layout);
popup.setWidth(popupWidth);
popup.setHeight(popupHeight);
popup.setFocusable(true);
// Some offset to align the popup a bit to the right, and a bit down, relative to button's position.
int OFFSET_X = 30;
int OFFSET_Y = 30;
// Clear the default translucent background
popup.setBackgroundDrawable(new BitmapDrawable());
// Displaying the popup at the specified location, + offsets.
popup.showAtLocation(layout, Gravity.NO_GRAVITY, p.x + OFFSET_X, p.y + OFFSET_Y);
// Getting a reference to Close button, and close the popup when clicked.
Button close = (Button) layout.findViewById(R.id.close);
close.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
popup.dismiss();
}
});
}
}
GAG Pictures – Have Fun! Spread The Fun!
Hello everyone, I would like to introduce you my second Android application published on Google Play – GAG Pictures. Compared with the first one, this application is intended to bring you much fun.
GAG Pictures is your daily set of funny images! Every time the application is launched it downloads a set of new funny images from the famous site 9gag.com. Every image has a Share button so you can share that hilarious image with your friends. The current version allows you to share only the direct link to image, but in the upcoming releases the ability to send the image itself will be provided.
Have fun!
Drawing Shapes in Android
In this post I would like to share my findings about defining and using shapes. A shape is an XML file that defines a geometric shape, including strokes, colors and gradients
To define a shape:
1. Create a new Android XML file in the folder res/drawable
2. Make sure the root element of the file is <shape >. (If it’s not, then change it manually)
3. Inside the <shape> element, press CTRL + Space to reveal all the available elements you can use to define a shape:
As you can see, the elements are pretty self explanatory. To reveal the attributes of an element, put the cursor inside that element and press CTRL + Space:
4. Once the shape is defined, you can specify it as a background resource to any view: android:background=”@drawable/myshape”
res/drawable/boxbg.xml:
<?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android" > <stroke android:width="2dp" android:color="#FFFFFF" /> <corners android:radius="5dp" /> <gradient android:angle="270" android:centerColor="#6E7FFF" android:endColor="#142FFC" android:startColor="#BAC2FF" /> </shape>
res/drawable/box2bg.xml:
<?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android" > <solid android:color="#4D9611" /> <stroke android:width="4dp" android:color="#FFFB00" /> </shape>
res/layout/main.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<!-- First box, boxbg.xml -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="80dp"
android:layout_margin="20dp"
android:background="@drawable/boxbg"
android:orientation="vertical"
android:padding="5dp" >
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/hello"
android:textColor="#000"
android:textSize="20dp" />
</LinearLayout>
<!-- Second box, box2bg.xml -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="80dp"
android:layout_margin="20dp"
android:background="@drawable/box2bg"
android:orientation="vertical"
android:padding="7dp" >
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/hello"
android:textColor="#FFF"
android:textSize="20dp" />
</LinearLayout>
</LinearLayout>
The final output should look like this:
Creating A Simple RSS Application in Android
In this tutorial we will build a simple rss application.
Requirements are:
1) parse an rss feed and display the headlines in a ListView
2) when the user clicks on a headline, open the Android browser and redirect to corresponding web page.
We will parse the PCWorld‘s rss looking for the latest news: http://feeds.pcworld.com/pcworld/latestnews
The final result will look like in the screenshot below:
1. Create a new project in Eclipse:
Project: SimpleRssReader
Activity: SimpleRssReaderActivity
2. Add required permissions to AndroidManifest file.
The application will make use of Internet, so this should be specified in the AndroidManifest file, otherwise an exception will be thrown. Just after the <application> tag, (as a child of <manifest> tag), add the following line:
<uses-permission android:name="android.permission.INTERNET"/>
3. Open the main.xml layout file, delete the already existing TextView control, and add instead a ListView with the id “list”. This should should look like this:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" > <ListView android:id="@+android:id/list" android:layout_width="fill_parent" android:layout_height="wrap_content" > </ListView> </LinearLayout>
4. Lets create the skeleton of our main activity.
Open the SimpleRSSReaderActivity and make it extend ListActivity, instead of Activity as it comes by default. We need this in order to display the headlines in the ListView by binding to an array which will hold our data, using the list view adapter.
Add 2 instance variables: “headlines” and “links” of type List.
It should look like this:
public class SimpleRSSReaderActivity extends ListActivity {
List headlines;
List links;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
}
5. In the onCreate() method, just after the setContentView(….) , add following lines:
// Initializing instance variables
headlines = new ArrayList();
links = new ArrayList();
try {
URL url = new URL("http://feeds.pcworld.com/pcworld/latestnews");
XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
factory.setNamespaceAware(false);
XmlPullParser xpp = factory.newPullParser();
// We will get the XML from an input stream
xpp.setInput(getInputStream(url), "UTF_8");
/* We will parse the XML content looking for the "<title>" tag which appears inside the "<item>" tag.
* However, we should take in consideration that the rss feed name also is enclosed in a "<title>" tag.
* As we know, every feed begins with these lines: "<channel><title>Feed_Name</title>...."
* so we should skip the "<title>" tag which is a child of "<channel>" tag,
* and take in consideration only "<title>" tag which is a child of "<item>"
*
* In order to achieve this, we will make use of a boolean variable.
*/
boolean insideItem = false;
// Returns the type of current event: START_TAG, END_TAG, etc..
int eventType = xpp.getEventType();
while (eventType != XmlPullParser.END_DOCUMENT) {
if (eventType == XmlPullParser.START_TAG) {
if (xpp.getName().equalsIgnoreCase("item")) {
insideItem = true;
} else if (xpp.getName().equalsIgnoreCase("title")) {
if (insideItem)
headlines.add(xpp.nextText()); //extract the headline
} else if (xpp.getName().equalsIgnoreCase("link")) {
if (insideItem)
links.add(xpp.nextText()); //extract the link of article
}
}else if(eventType==XmlPullParser.END_TAG && xpp.getName().equalsIgnoreCase("item")){
insideItem=false;
}
eventType = xpp.next(); //move to next element
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (XmlPullParserException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
// Binding data
ArrayAdapter adapter = new ArrayAdapter(this,
android.R.layout.simple_list_item_1, headlines);
setListAdapter(adapter);
6. In the onCreate() method we passed an input stream to setInput(): xpp.setInput(getInputStream(url), "UTF_8");
getInputStream() is not a standard Java method, so we should create it. This method should take as an argument the feed url, and return the input stream.
public InputStream getInputStream(URL url) {
try {
return url.openConnection().getInputStream();
} catch (IOException e) {
return null;
}
}
7. Finnaly, we want when a title is clicked, the Android browser to be opened and display the corresponding article. This one is simple, we override the onListItemClick() method, get the position of article in the ListView, retrieve the coresponding link, and pass the url of that article to ACTION_VIEW intent which takes care further of displaying the web page.
@Override
protected void onListItemClick(ListView l, View v, int position, long id) {
Uri uri = Uri.parse(links.get(position));
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
startActivity(intent);
}
By this time you should compile and run successfully the application.
Well, if everything went fine and you are done with the simple rss application, the next step to consider is how can you enhance the visual aspect of the application. Adding some style to the ListView, for example alternating between background colors, or displaying an icon next to each headline, can considerably increase the visual aspect, which will make your application look more appealing.
Take a look at this tutorial: Building a Custom Fancy ListView in Android, where I show in details how to achieve this.
This application, however, has one major drawback. Its drawback is that all the parsing and network access is done on the UI thread. As a result, you may notice that when starting the application, it “freezes” for a few seconds and then displays the headlines. To fix this issue, you should put all the parsing functionality in a background thread. In regards how to do that, you definitely should consider this post: Understanding AsyncTask – Once and Forever








![get_it_on_play_logo_large[1] Get it on Google Play - GAG Pictures](http://androidresearch.files.wordpress.com/2012/04/get_it_on_play_logo_large1.png?w=595)







