-1

I have modified the code from Head First Android display to get the RSS feeds from NASA's Image of the Day. I decided to use AsyncTask to get the data and then pass it back to the UI thread to update. However, there is some strange results here.
enter image description here enter image description here The one on the right is the UI after clicking the button. Strange enough.

Below is my code for the Activity

package com.example.nasadailyimage;

import android.os.AsyncTask;
import android.os.Bundle;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.*;

public class NasaDailyImage extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        Button b = (Button) findViewById(R.id.button);
        //get feeds only when button is clicked!
        b.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                new AsyncRetriever().execute(new IotdHandler()); // Get the feeds !!
            }
        });
    }
//------------------------------------------------------------------------------
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.nasa_daily_image, menu);
        return true;
    }
//------------------------------------------------------------------------------
    /**
     * This method is called by onPostExecute and is used to update the UI.
     * It first checks if an error occured while parsing the RSS feed.
     * If yes, it displays "Error" in all TextViews and displays an 
     * AlertDialog.
     * Else, it displays the new data.
     * @param hasErrorOccured
     * @param reply
     */
    public synchronized void resetDisplay(boolean hasErrorOccured,IotdHandler reply){
        if(hasErrorOccured){

            AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(
                    this);

                // set title
                alertDialogBuilder.setTitle("An error has occured while retrieving feed");

                // set dialog message
                alertDialogBuilder
                    .setMessage("Click to exit")
                    .setCancelable(false)
                    .setNegativeButton("Exit",new DialogInterface.OnClickListener() {
                        public void onClick(DialogInterface dialog,int id) {
                            // if this button is clicked, just close
                            // the dialog box and do nothing
                            dialog.cancel();
                        }
                    });
                // create alert dialog
                AlertDialog alertDialog = alertDialogBuilder.create();

                // show it
                alertDialog.show();


            TextView textHeader = (TextView) findViewById(R.id.textHeader);
            TextView date = (TextView) findViewById(R.id.date);
            ImageView img = (ImageView) findViewById(R.id.image);
            TextView desc = (TextView) findViewById(R.id.desc);

            textHeader.setText("Error");
            date.setText("Error");
            desc.setText("Error");

            return;
        }else{
            TextView textHeader = (TextView) findViewById(R.id.textHeader);
            TextView date = (TextView) findViewById(R.id.date);
            ImageView img = (ImageView) findViewById(R.id.image);
            TextView desc = (TextView) findViewById(R.id.desc);

            textHeader.setText(reply.getTitle());
            date.setText(reply.getDate());
            img.setImageBitmap(reply.getImage());
            desc.setText(reply.getDescription());
        }
    }
//------------------------------------------------------------------------------
    /**
     * This class retrieves data from the RSS feed. I am using AsyncTask because
     * it is not a good practice to block the UI thread while performing 
     * network operations.
     *
     */
    class AsyncRetriever extends AsyncTask<IotdHandler,Void,IotdHandler>{

        @Override
        protected IotdHandler doInBackground(IotdHandler... arg0) {
            IotdHandler handler = arg0[0];
            handler.processFeed(); // get the RSS feed data !
            return handler;
        }
//------------------------------------------------------------------------------    
        @Override
        protected void onPostExecute(IotdHandler fromInBackground){
            resetDisplay(fromInBackground.errorOccured,fromInBackground);
        }
//------------------------------------------------------------------------------
    }
}  

IotdHandler

public class IotdHandler extends DefaultHandler{
    private String url = "http://www.nasa.gov/rss/image_of_the_day.rss";
    /**
     * Since the events  get called differently, you need to keep
     * a track of which tag you are in.
     */

    private boolean inTitle = false;
    private boolean inDescription = false;
    private boolean inItem = false;
    private boolean inDate = false;
    public boolean errorOccured = false;
    boolean firstItemHit = false;

    private Bitmap image = null;
    private String title = null;
    private StringBuffer description = new StringBuffer();
    private String date = null;
//------------------------------------------------------------------------------
    public void processFeed(){
        try{
            SAXParserFactory factory = SAXParserFactory.newInstance();
            SAXParser parser = factory.newSAXParser();
            InputStream stream = new URL(url).openStream();
            parser.parse(stream, this);
        }catch(Exception e){
            errorOccured = true;
        }
    }
//------------------------------------------------------------------------------
    private Bitmap getBitmap(String url){
        try{
            HttpURLConnection con = (HttpURLConnection)new URL(url).openConnection();
            con.setDoInput(true);
            con.connect();
            InputStream input = con.getInputStream();
            Bitmap bmp = BitmapFactory.decodeStream(input);
            input.close();
            return bmp;
        }catch(Exception e){
            errorOccured = true;
            return null;
        }
    }
//------------------------------------------------------------------------------
    @Override
    public void startElement(String uri,String localName,String qName, 
            Attributes attr) throws SAXException{
            if(localName.equals("item")){ 
                if(localName.equals("title")){inTitle = true;}
                if(localName.equals("description")){inDescription = true;}
                if(localName.equals("pubDate")){inDate = true;}
                if(localName.equals("enclosure")){
                    String url = attr.getValue(0);
                    getBitmap(url);
                }
            }

    }
//------------------------------------------------------------------------------
    @Override
    public void characters(char[] ch,int start,int length){
        String charData = new String(ch);
            if(inTitle){
                title = charData;
            }
            if(inDescription){
                description.append(charData);
            }
            if(inDate){
                date = charData;
            }
    }
//------------------------------------------------------------------------------
    public Bitmap getImage(){return image;}
    public String getTitle(){return title;}
    public StringBuffer getDescription(){return description;}
    public String getDate(){return date;}
//------------------------------------------------------------------------------
}

How do I go about solving this?

4

1 回答 1

2

I believe the issue is in the startElement function in your IotdHandler

basically you are doing a check to see if localName equals "item", then within that if block you check to see if localName equals "title" then "description" etc. None of those inner if statements will ever be true since they will only be evaluated when localName equals "item"

You could remove the check

if(localName.equals("item"))

all together that way those inner if statements have a chance of evaluating to true or if you want to ensure the matches for title, description etc. are within the item node you could change it to:

        if(localName.equals("item")){inItem = true;}
        if(inItem){
            if(localName.equals("title")){inTitle = true;}
            if(localName.equals("description")){inDescription = true;}
            if(localName.equals("pubDate")){inDate = true;}
            if(localName.equals("enclosure")){
                String url = attr.getValue(0);
                getBitmap(url);
            }
        }

Though with all those booleans you are using to determine if you are in a block or not, you should make sure that you set them to false by overriding the endElement function ala

@Override
public void endElement(String uri,String localName,String qName) throws SAXException{
        if(localName.equals("item")){inItem = false;}
        if(localName.equals("title")){inTitle = false;}
        if(localName.equals("description")){inDescription = false;}
        if(localName.equals("pubDate")){inDate = false;}
}
于 2013-07-23T05:32:58.643 回答