SAX parser using AsyncTask to read xml file on net

SAX parser uses less memory than DOM parser, so better for mobiles. Sources were stackoverflow and android developer site but links now lost. This is the laptops.xml file placed on a remote server.

<?xml version="1.0" encoding="UTF-8"?>
<laptops>
    <laptop model = "Dell Inspiron i13z-3181PNK">
        <brand>Dell</brand>
        <price>$699.99</price>
        <description>Switch your lid to match your mood.
            A 13.3" laptop with 3rd Gen Intel Core processor power and optional SWITCH lids
        </description>
        <technical-details>
            Intel 2nd gen Core i3-2367 1.40GHz 1.40 GHz (6MB Cache)
            6 GB DIMM
            500GB 5400 rpm SATA Hard Drive
            13-Inch Screen
            Windows 7 Home Premium 64-bit
        </technical-details>
        <image-url>http://10.0.2.2:8080/laptop-images/Dell-3181PNK.jpg</image-url>
    </laptop>
    <laptop model = "Dell XPS XPS13-9001sLV">
        <brand>Dell</brand>
        <price>$1,399.99</price>
        <description>Strikingly thin, with more room to view.
        </description>
        <technical-details>
            Intel Core i7-2637M (1.70GHz, 4MB Cache)
            4 GB DIMM
            256GB Solid State Drive
            13-Inch Screen
            Windows 7 Home Premium 64-bit
        </technical-details>
        <image-url>http://10.0.2.2:8080/laptop-images/Dell-XPS13.jpg</image-url>
    </laptop>

</laptops>

Create class Laptop.

public class Laptop {

	private String brand;
    private String model;
    private String description;
    private String techDetails;
    private String price;
    private String imageURL;
    private Bitmap imageBitmap;

    public String getBrand() {
        return brand;
    }
    public void setBrand(String brand) {
        this.brand = brand;
    }
    public String getModel() {
        return model;
    }
    public void setModel(String model) {
        this.model = model;
    }
    public String getDescription() {
        return description;
    }
    public void setDescription(String description) {
        this.description = description;
    }
    public String getTechDetails() {
        return techDetails;
    }
    public void setTechDetails(String techDetails) {
        this.techDetails = techDetails;
    }
    public String getPrice() {
        return price;
    }
    public void setPrice(String price) {
        this.price = price;
    }
    public String getImageURL() {
        return imageURL;
    }
    public void setImageURL(String imageURL) {
        this.imageURL = imageURL;
    }
    public Bitmap getImageBitmap() {
        return imageBitmap;
    }
    public void setImageBitmap(Bitmap imageBitmap) {
        this.imageBitmap = imageBitmap;
    }
}

Create class CustomListViewAdapter.

public class CustomListViewAdapter extends ArrayAdapter {
    Activity context;
    List laptops;

    public CustomListViewAdapter(Activity context, List laptops) {
        super(context, R.layout.list_item2, laptops);
        this.context = context;
        this.laptops = laptops;
    }

    /*private view holder class*/
    private class ViewHolder {
        ImageView imageView;
        TextView txtBrand;
        TextView txtModel;
        TextView txtPrice;
    }

    public Laptop getItem(int position) {
        return laptops.get(position);
    }

    public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolder holder;
        LayoutInflater inflater = context.getLayoutInflater();

        if (convertView == null) {
            convertView = inflater.inflate(R.layout.list_item2, null);
            holder = new ViewHolder();
            holder.txtBrand = (TextView) convertView.findViewById(R.id.brand);
            holder.txtModel = (TextView) convertView.findViewById(R.id.model);
            holder.txtPrice = (TextView) convertView.findViewById(R.id.price);
            holder.imageView = (ImageView) convertView.findViewById(R.id.thumbnail);
            convertView.setTag(holder);
        } else {
            holder = (ViewHolder) convertView.getTag();
        }

        Laptop laptop = (Laptop) getItem(position);

        holder.txtBrand.setText(laptop.getBrand());
        holder.txtModel.setText(laptop.getModel());
        holder.imageView.setImageBitmap(laptop.getImageBitmap());
        holder.txtPrice.setText(laptop.getPrice() + "");

        return convertView;
    }
}

And class SAXXMLParser.

public class SAXXMLParser {

	public static List parse(InputStream is) {
        List laptops = null;
        try {
            // create a XMLReader from SAXParser
            XMLReader xmlReader = SAXParserFactory.newInstance().newSAXParser()
                    .getXMLReader();
            // create a SAXXMLHandler
            SAXXMLHandler saxHandler = new SAXXMLHandler();
            // store handler in XMLReader
            xmlReader.setContentHandler(saxHandler);
            // the process starts
            xmlReader.parse(new InputSource(is));
            // get the `Laptop list`
            laptops = saxHandler.getLaptops();

        } catch (Exception ex) {
            Log.d("XML", "SAXXMLParser: parse() failed");
            ex.printStackTrace();
        }

        // return Laptop list
        return laptops;
    }
}

And SAXXMLHandler.

public class SAXXMLHandler extends DefaultHandler {
    private List laptops;
    private String tempVal;
    // to maintain context
    private Laptop laptop;

    public SAXXMLHandler() {
        laptops = new ArrayList();
    }

    public List getLaptops() {
        return laptops;
    }

 // Event Handlers
    public void startElement(String uri, String localName, String qName,
            Attributes attributes) throws SAXException {
        // reset
        tempVal = "";
        if (qName.equalsIgnoreCase("laptop")) {
            // create a new instance of Laptop
            laptop = new Laptop();
            laptop.setModel(attributes.getValue("model"));
        }
    }

    public void characters(char[] ch, int start, int length)
            throws SAXException {
        tempVal = new String(ch, start, length);
    }

    public void endElement(String uri, String localName, String qName)
            throws SAXException {

        if (qName.equalsIgnoreCase("laptop")) {
            // add it to the list
            laptops.add(laptop);
        } else if (qName.equalsIgnoreCase("brand")) {
            laptop.setBrand(tempVal);
        } else if (qName.equalsIgnoreCase("description")) {
            laptop.setDescription(tempVal);
        } else if (qName.equalsIgnoreCase("technical-details")) {
            laptop.setTechDetails(tempVal);
        } else if (qName.equalsIgnoreCase("image-url")) {
            laptop.setImageURL(tempVal);
        } else if (qName.equalsIgnoreCase("price")) {
            laptop.setPrice(tempVal);
        }
    }
}

They all need an activity

public class SAXParserAsyncTaskActivity extends Activity implements
		OnClickListener, OnItemClickListener {	
	Button button;
	ListView listView;
	List laptops;
	CustomListViewAdapter listViewAdapter;

//	static final String URL = "http://10.0.2.2:8080/laptops.xml";
	static final String URL = "http://www.jesmondit.co.uk/test/test/laptops.xml";

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

		findViewsById();
		button.setOnClickListener(this);
		listView.setOnItemClickListener(this);
	}

	private void findViewsById() {
		button = (Button) findViewById(R.id.saxButton);
		listView = (ListView) findViewById(R.id.laptopList);
	}

	@Override
	public void onItemClick(AdapterView<?> parent, View view, int position,
			long id) {
	}

	@Override
	public void onClick(View view) {
		GetXMLTask task = new GetXMLTask(this);
		task.execute(new String[] { URL });
	}

	// private inner class extending AsyncTask
	private class GetXMLTask extends AsyncTask<String, Void, List> {
		private Activity context;

		public GetXMLTask(Activity context) {
			this.context = context;
		}

		@Override
		protected void onPostExecute(List laptops) {
			listViewAdapter = new CustomListViewAdapter(context, laptops);
			listView.setAdapter(listViewAdapter);
		}

		/*
		 * uses HttpURLConnection to make Http request from Android to download
		 * the XML file
		 */
		private String getXmlFromUrl(String urlString) {
			StringBuffer output = new StringBuffer("");
			try {
				InputStream stream = null;
				URL url = new URL(urlString);
				URLConnection connection = url.openConnection();

				HttpURLConnection httpConnection = (HttpURLConnection) connection;
				httpConnection.setRequestMethod("GET");
				httpConnection.connect();

				if (httpConnection.getResponseCode() == HttpURLConnection.HTTP_OK) {
					stream = httpConnection.getInputStream();

					BufferedReader buffer = new BufferedReader(
							new InputStreamReader(stream));
					String s = "";
					while ((s = buffer.readLine()) != null)
						output.append(s);
				}

			} catch (Exception ex) {
				ex.printStackTrace();
			}
			return output.toString();
	}

		@Override
		protected List doInBackground(String... urls) {
			List laptops = null;
			String xml = null;
			for (String url : urls) {
				xml = getXmlFromUrl(url);

				InputStream stream = new ByteArrayInputStream(xml.getBytes());
				laptops = SAXXMLParser.parse(stream);

				for (Laptop laptop : laptops) {
					String imageURL = laptop.getImageURL();
					Bitmap bitmap = null;
					BitmapFactory.Options bmOptions = new BitmapFactory.Options();
					bmOptions.inSampleSize = 1;

					try {
						bitmap = BitmapFactory
								.decodeStream(new URL(imageURL).openStream(),
										null, bmOptions);
					} catch (MalformedURLException e) {
						e.printStackTrace();
					} catch (IOException e) {
						e.printStackTrace();
					}
					laptop.setImageBitmap(bitmap);
				}
			}
			// stream.close();
			return laptops;
		}
	}
}

… which has a layout.

<?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" >

     <Button
        android:id="@+id/saxButton"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="@string/button" />

     <ListView
        android:id="@+id/laptopList"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
       />
</LinearLayout>

Finally there’s the layout (list_item2) to be used in the listview.

<?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="wrap_content"
    android:orientation="horizontal"
    android:padding="10dp" >

    <ImageView
        android:id="@+id/thumbnail"
        android:layout_width="70dp"
        android:layout_height="70dp"
        android:contentDescription="@string/image" />

    <LinearLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:paddingLeft="10dp" >

        <TextView
            android:id="@+id/brand"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textColor="#CC0033"
            android:textSize="16sp"
            android:textStyle="bold" />

        <TextView
            android:id="@+id/model"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textColor="#3399FF"
            android:textSize="14sp"
            android:textStyle="bold" />

        <TextView
            android:id="@+id/price"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="12sp"
            android:textStyle="italic"
            android:typeface="sans" />
    </LinearLayout>

    <LinearLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:gravity="center_vertical"
        android:orientation="vertical" >

        <ImageView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="right"
            android:contentDescription="@string/image"
            android:src="@drawable/accessory_indicator" />
    </LinearLayout>

</LinearLayout>
This entry was posted in Android. Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *