Javacadabra
Javacadabra

Reputation: 5758

Downloading an XML file from a web server Android

I am developing an application for college that connects to a web server and reads data from an XML on the server. The appilcation is working but I am currently trying to really break down the code and understand exactly what is happening.

My question is that I have an inner class that extends the AsyncTask class. Within this inner class I create a new URL object and get an InputStream. I understand that because I am doing this I can then successfully connect to the web server from the background thread and make whatever requests I like.

In the past I always used the DefaultHttpClient to execute HTTP requests. However in this code I do not create an instance of this class anywhere. Instead I just get an input stream to read in the sequence of bytes.

Could someone explain in the code below what is meant by parsing spec and also if somewhere behind the scenes a HTTP request is actually being made?

URL url = new URL("http://feeds.pcworld.com/pcworld/latestnews");

Documentation on Android Dev says:

Creates a new URL instance by parsing spec.

This is my entire MainActivity

public class MainActivity extends ListActivity {

List<Item>items;//Holds item objects containing info relating to element pulled from XML file.
Item item; //Instance of Item - contains all data relating to a specific Item.
ArticleListAdapter adapter;//Generates the Views and links the data source (ArrayList) to the ListView.

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    //Set the layout
    setContentView(R.layout.activity_main);

    //initialize variables
    items = new ArrayList<Item>();

    //Perform a http request for the file on the background thread. 
    new PostTask().execute();

    //Create instance of the adapter and pass the list of items to it.
    adapter = new ArticleListAdapter(this, items);

    //Attach adapter to the ListView.
    setListAdapter(adapter);        

}


private InputStream getInputStream(URL url) {
    try{
        return url.openConnection().getInputStream();
    }catch(IOException e){
        return null;
    }
}

/**
 * Executed when an Item in the List is clicked. Will display the article being clicked in a browser.
 */
@Override
protected void onListItemClick(ListView l, View v, int position, long id) {
    //Get the link from the item object stored in the array list
    Uri uri = items.get(position).getLink();
    //Create new intent to open browser
    Intent intent = new Intent(Intent.ACTION_VIEW, uri);
    startActivity(intent);
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.activity_main, menu);
    return true;
}

//ASYNC CLASS
private class PostTask extends AsyncTask<String, Integer, String>{

    @Override
    protected String doInBackground(String... arg0) {
        try{
            //link to data source
            URL url = new URL("http://feeds.pcworld.com/pcworld/latestnews");

            //Set up parser
            XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
            factory.setNamespaceAware(false);
            XmlPullParser xpp = factory.newPullParser();

            //get XML from input stream
            InputStream in = getInputStream(url);
            if (in == null) {
                throw new Exception("Empty inputstream");
            }
            xpp.setInput(in, "UTF_8");

            //Keep track of which tag inside of XML
            boolean insideItem = false;

            //Loop through the XML file and extract data required
            int eventType = xpp.getEventType();

            while (eventType != XmlPullParser.END_DOCUMENT) {

                if (eventType == XmlPullParser.START_TAG) {
                    Log.v("ENTER", String.valueOf(xpp.getEventType()));

                    if (xpp.getName().equalsIgnoreCase("item")) {
                        insideItem = true;

                        //Create new item object
                        item = new Item();

                    } else if (xpp.getName().equalsIgnoreCase("title")) {
                        if (insideItem){
                            item.setTitle(xpp.nextText());
                            Log.i("title", item.getTitle());
                        }

                    } 

                    else if (xpp.getName().equalsIgnoreCase("description")) {
                        if (insideItem){
                            item.setDescription(xpp.nextText());
                        }
                    }

                    else if (xpp.getName().equalsIgnoreCase("link")) {
                        if (insideItem){
                            item.setLink(Uri.parse(xpp.nextText()));                            
                        }
                    }
                }else if(eventType==XmlPullParser.END_TAG && xpp.getName().equalsIgnoreCase("item")){

                    //If no longer inside item tag then we know we are finished parsing data relating to one specific item.
                    insideItem=false;
                    //add item to list
                    items.add(item);

                }


                eventType = xpp.next(); //move to next element
                publishProgress(); //update progress on UI thread.
            }


                } catch (MalformedURLException e) {

                    e.printStackTrace();

                } catch (XmlPullParserException e) {

                    e.printStackTrace();

                } catch (IOException e) {

                    e.printStackTrace();

                }
                catch (Exception e) {

                    e.printStackTrace();

                }


        return "COMPLETED";
    }

    /*
     * Update the List as each item is parsed from the XML file.
     * @see android.os.AsyncTask#onProgressUpdate(Progress[])
     */
    @Override
    protected void onProgressUpdate(Integer... values) {
        adapter.notifyDataSetChanged();

    }

    /*
     * Runs on UI thread after doInBackground is finished executing.
     * @see android.os.AsyncTask#onPostExecute(java.lang.Object)
     */
    public void onPostExecute(String s) {
        //Toast message to inform user of how many articles have been downloaded.
        Toast.makeText(getApplicationContext(), s + " Items: " + items.size(), Toast.LENGTH_SHORT).show();
        adapter.notifyDataSetChanged();
    }

}

}

I am sorry if this question is very basic, but like I said I am trying to learn and that is what this site is all about right?

I'd appreciate any feedback or help people have in relation to this topic. Many thanks!

Upvotes: 1

Views: 1710

Answers (1)

Vit Khudenko
Vit Khudenko

Reputation: 28418

parsing spec - means it will parse the string you pass to the constructor. The URL API creators just named this string (url/uri) in a more generic way - the spec. Probably because it specifies the resource to which you will connect. If string does not represent a valid URL, then it throws MalformedURLException. After parsing it knows what host, port, path, etc. to use for making the HTTP request.

The fact of creating a URL instance does not mean any networking happens. It is similar to File API - where creating a File instance does not open/read/write anything.

url.openConnection().getInputStream() - here is where networking happens (an HTTP request is fired).

Here is the source code of ULR: http://www.docjar.com/html/api/java/net/URL.java.html So you can look how it works.

Upvotes: 1

Related Questions