Friday, April 30, 2010

A simple RSS reader, in ListView

In the last exercise, "A simple RSS reader, using Android's org.xml.sax package", the RSS's titles are displayed as a single String. For sure it's not a good presentation in this way.

In this article, it will be modified to display it in ListView.



AndroidManifest.xml to grant "android.permission.INTERNET" to the application. (Refer to last article "A simple RSS reader, using Android's org.xml.sax package")

In order to use ListView, create a new file, /res/layout/rsslist.xml
<?xml version="1.0" encoding="utf-8"?>
<TextView
 xmlns:android="http://schemas.android.com/apk/res/android"
 android:id="@+id/rowtext"
 android:layout_width="fill_parent"
 android:layout_height="25px"
 android:textSize="10sp" />


Modify main.xml to have a ListView
<?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"
   >
<TextView 
   android:layout_width="fill_parent"
   android:layout_height="wrap_content"
   android:text="@string/hello" />
<ListView
 android:id="@android:id/list"
 android:layout_width="fill_parent"
 android:layout_height="wrap_content" />
<TextView
 android:id="@android:id/empty"
 android:layout_width="fill_parent"
 android:layout_height="wrap_content"
 android:text="No Data" />
</LinearLayout>


Modify AndroidRssReder.java
package com.exercise.AndroidRssReader;

import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;

import android.app.ListActivity;
import android.os.Bundle;
import android.widget.ArrayAdapter;

public class AndroidRssReader extends ListActivity {
 
 private List<String> item = new ArrayList<String>();
 
   /** Called when the activity is first created. */
   @Override
   public void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       setContentView(R.layout.main);

       try {
   URL rssUrl = new URL("http://feeds.feedburner.com/Android-er?format=xml");
   SAXParserFactory mySAXParserFactory = SAXParserFactory.newInstance();
   SAXParser mySAXParser = mySAXParserFactory.newSAXParser();
   XMLReader myXMLReader = mySAXParser.getXMLReader();
   RSSHandler myRSSHandler = new RSSHandler();
   myXMLReader.setContentHandler(myRSSHandler);
   InputSource myInputSource = new InputSource(rssUrl.openStream());
   myXMLReader.parse(myInputSource);
   
  } catch (MalformedURLException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  } catch (ParserConfigurationException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  } catch (SAXException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  } catch (IOException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }
      
  ArrayAdapter<String> itemList = new ArrayAdapter<String>(this, R.layout.rsslist, item);
  setListAdapter(itemList);
   }
  
   private class RSSHandler extends DefaultHandler
   {
    final int stateUnknown = 0;
    final int stateTitle = 1;
    int state = stateUnknown;
    
  @Override
  public void startDocument() throws SAXException {
   // TODO Auto-generated method stub
  }

  @Override
  public void endDocument() throws SAXException {
   // TODO Auto-generated method stub
  }

  @Override
  public void startElement(String uri, String localName, String qName,
    Attributes attributes) throws SAXException {
   // TODO Auto-generated method stub
   if (localName.equalsIgnoreCase("title"))
   {
    state = stateTitle;
   }
   else
   {
    state = stateUnknown;
   }
  }

  @Override
  public void endElement(String uri, String localName, String qName)
    throws SAXException {
   // TODO Auto-generated method stub
   state = stateUnknown;
  }

  @Override
  public void characters(char[] ch, int start, int length)
    throws SAXException {
   // TODO Auto-generated method stub
   String strCharacters = new String(ch, start, length);
   if (state == stateTitle)
   {
    item.add(strCharacters);
    
   }
  }
    
   }
}


Download the files.


Thursday, April 22, 2010

A simple RSS reader, using Android's org.xml.sax package.

In the last article, "Read XML Resources in Android, using XmlResourceParser: XML parsing interface", Android application read XML resource inside application. In the current article, a external XML will be read using Android SAX APIs.

The source of XML is "http://feeds.feedburner.com/Android-er?format=xml", which is RSS feed of my blog.

SAX is the Simple API for XML, originally a Java-only API. SAX was the first widely adopted API for XML in Java, and is a “de facto” standard. The current version is SAX 2.0.1, and there are versions for several programming language environments other than Java.

org.xml.sax is a Android's package provides the core SAX APIs.

In order to make it simple, only the contents under "title" tag will be retrieved and appended as a string.



To allow the Android application, "android.permission.INTERNET" have to be granted to the application. Modify AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.exercise.AndroidRssReader"
    android:versionCode="1"
    android:versionName="1.0">
  <application android:icon="@drawable/icon" android:label="@string/app_name">
      <activity android:name=".AndroidRssReader"
                android:label="@string/app_name">
          <intent-filter>
              <action android:name="android.intent.action.MAIN" />
              <category android:name="android.intent.category.LAUNCHER" />
          </intent-filter>
      </activity>

  </application>
  <uses-sdk android:minSdkVersion="4" />
<uses-permission android:name="android.permission.INTERNET" />
</manifest>


Modify main.xml to add a TextView to display the result.
<?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"
  >
<TextView
  android:layout_width="fill_parent"
  android:layout_height="wrap_content"
  android:text="@string/hello" />
<ScrollView
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<TextView
   android:layout_width="fill_parent"
   android:layout_height="wrap_content"
   android:id="@+id/result" />
</ScrollView>
</LinearLayout>


Java source code.
package com.exercise.AndroidRssReader;

import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;

import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;

public class AndroidRssReader extends Activity {

String streamTitle = "";

  /** Called when the activity is first created. */
  @Override
  public void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.main);
    
      TextView result = (TextView)findViewById(R.id.result);
    
      try {
  URL rssUrl = new URL("http://feeds.feedburner.com/Android-er?format=xml");
  SAXParserFactory mySAXParserFactory = SAXParserFactory.newInstance();
  SAXParser mySAXParser = mySAXParserFactory.newSAXParser();
  XMLReader myXMLReader = mySAXParser.getXMLReader();
  RSSHandler myRSSHandler = new RSSHandler();
  myXMLReader.setContentHandler(myRSSHandler);
  InputSource myInputSource = new InputSource(rssUrl.openStream());
  myXMLReader.parse(myInputSource);
 
  result.setText(streamTitle);
 
 } catch (MalformedURLException e) {
  // TODO Auto-generated catch block
  e.printStackTrace();
  result.setText("Cannot connect RSS!");
 } catch (ParserConfigurationException e) {
  // TODO Auto-generated catch block
  e.printStackTrace();
  result.setText("Cannot connect RSS!");
 } catch (SAXException e) {
  // TODO Auto-generated catch block
  e.printStackTrace();
  result.setText("Cannot connect RSS!");
 } catch (IOException e) {
  // TODO Auto-generated catch block
  e.printStackTrace();
  result.setText("Cannot connect RSS!");
 }
    
    
  }

  private class RSSHandler extends DefaultHandler
  {
   final int stateUnknown = 0;
   final int stateTitle = 1;
   int state = stateUnknown;
  
   int numberOfTitle = 0;
   String strTitle = "";
   String strElement = "";
  
 @Override
 public void startDocument() throws SAXException {
  // TODO Auto-generated method stub
  strTitle = "--- Start Document ---\n";
 }

 @Override
 public void endDocument() throws SAXException {
  // TODO Auto-generated method stub
  strTitle += "--- End Document ---";
  streamTitle = "Number Of Title: " + String.valueOf(numberOfTitle) + "\n"
     + strTitle;
 }

 @Override
 public void startElement(String uri, String localName, String qName,
   Attributes attributes) throws SAXException {
  // TODO Auto-generated method stub
  if (localName.equalsIgnoreCase("title"))
  {
   state = stateTitle;
   strElement = "Title: ";
   numberOfTitle++;
  }
  else
  {
   state = stateUnknown;
  }
 }

 @Override
 public void endElement(String uri, String localName, String qName)
   throws SAXException {
  // TODO Auto-generated method stub
  if (localName.equalsIgnoreCase("title"))
  {
   strTitle += strElement + "\n";
  }
  state = stateUnknown;
 }

 @Override
 public void characters(char[] ch, int start, int length)
   throws SAXException {
  // TODO Auto-generated method stub
  String strCharacters = new String(ch, start, length);
  if (state == stateTitle)
  {
   strElement += strCharacters;
  }
 }
  
  }
}


Download the files.

Further Reading: A simple RSS reader, in ListView

Update:
In current Android system, your app cannot run networking operation on main thread (or called UI thread), otherwise android.os.NetworkOnMainThreadException will be thrown. Please read the post android.os.NetworkOnMainThreadException.



Tuesday, April 20, 2010

Read XML Resources in Android, using XmlResourceParser: XML parsing interface

XmlResourceParser is the XML parsing interface returned for an XML resource. This is a standard XmlPullParser interface, as well as an extended AttributeSet interface and an additional close() method on this interface for the client to indicate when it is done reading the resource.

In this exercise, we read our own XML Resource (in /res/xml folder) using XmlResourceParser, and display the contents on screen.



First of all, create a folder /res/xml, and our own XML file myxml.xml
<?xml version="1.0" encoding="utf-8"?>
<rootelement1>
<subelement>
Hello XML Sub-Element 1
</subelement>
<subelement>
Hello XML Sub-Element 2
<subsubelement>Sub Sub Element</subsubelement>
</subelement>
</rootelement1>


Modify main.xml
<?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"
>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/hello"
/>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="@+id/my_xml"
/>
</LinearLayout>


Finally, modify java code
package com.exercise.AndroidXmlResource;

import java.io.IOException;

import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;

import android.app.Activity;
import android.content.res.Resources;
import android.content.res.XmlResourceParser;
import android.os.Bundle;
import android.widget.TextView;

public class AndroidXmlResource extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);

TextView myXmlContent = (TextView)findViewById(R.id.my_xml);
String stringXmlContent;
try {
stringXmlContent = getEventsFromAnXML(this);
myXmlContent.setText(stringXmlContent);
} catch (XmlPullParserException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}

private String getEventsFromAnXML(Activity activity)
throws XmlPullParserException, IOException
{
StringBuffer stringBuffer = new StringBuffer();
Resources res = activity.getResources();
XmlResourceParser xpp = res.getXml(R.xml.myxml);
xpp.next();
int eventType = xpp.getEventType();
while (eventType != XmlPullParser.END_DOCUMENT)
{
if(eventType == XmlPullParser.START_DOCUMENT)
{
stringBuffer.append("--- Start XML ---");
}
else if(eventType == XmlPullParser.START_TAG)
{
stringBuffer.append("\nSTART_TAG: "+xpp.getName());
}
else if(eventType == XmlPullParser.END_TAG)
{
stringBuffer.append("\nEND_TAG: "+xpp.getName());
}
else if(eventType == XmlPullParser.TEXT)
{
stringBuffer.append("\nTEXT: "+xpp.getText());
}
eventType = xpp.next();
}
stringBuffer.append("\n--- End XML ---");
return stringBuffer.toString();
}
}


Download the files.

Related Article: A simple RSS reader, using Android's org.xml.sax package.



Friday, April 16, 2010

How to define dimension in Android using XML

You can create common dimensions to use for various screen elements by defining dimension values in XML.

Here is some examples to define dimension using XML.

<?xml version="1.0" encoding="utf-8"?>
<resources>
<dimen name="one_pixels">1px</dimen>
<dimen name="five_dp">5dp</dimen>
<dimen name="1_inch">1in</dimen>
<dimen name="1_cm">10mm</dimen>
</resources>


Wednesday, April 14, 2010

Android - Apps can easily embed the web


Watch Android engineers demonstrate that applications on Android can easily embed the web. Apps can easily embed HTML, Javascript, and style sheets. An app can render web content through a WebView.

Thursday, April 1, 2010

Generate random number in Android

To generate random number in Android, class java.util.Random can be used.

This class java.util.Random provides methods that generates pseudo-random numbers of different types, such as int, long, double, and float.

It support two public constructor:
Random() - Construct a random generator with the current time of day in milliseconds as the initial state.
Random(long seed) - Construct a random generator with the given seed as the initial state.

Generate random number in Android

main.xml
<?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"
>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/hello"
/>
<Button
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Generate Random number"
android:id="@+id/generate"
/>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="@+id/generatenumber"
/>
</LinearLayout>


AndroidRandom.java
package com.exercise.AndroidRandom;

import java.util.Random;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;

public class AndroidRandom extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);

final Random myRandom = new Random();

Button buttonGenerate = (Button)findViewById(R.id.generate);
final TextView textGenerateNumber = (TextView)findViewById(R.id.generatenumber);

buttonGenerate.setOnClickListener(new OnClickListener(){

@Override
public void onClick(View v) {
// TODO Auto-generated method stub
textGenerateNumber.setText(String.valueOf(myRandom.nextInt()));
}});
}
}


Related:
- Generate sequence of Random number.