Android Development Tutorial 8

android xml parserWelcome to part 8 of my Android development tutorial. Today I’m going to show you how to make an android xml parser using the DOM. I’ll cover XmlPullParser next time.

I also cover numerous other topics including : How to use AsyncTask to execute threads in the background : How to write to the GUI from a thread : How to use Log.d : How to connect to a web service : Much more…

The code & video below will help you learn this stuff completely.

If you like videos like this, it helps to tell Google+ with a click here

Code From the Video

Here is all of the code in one package Android Stock Quote App.

activity_stock_info.xml

<?xml version="1.0" encoding="utf-8"?>
<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <TableRow
        android:id="@+id/tableRow1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" >

        <TextView
            android:id="@+id/companyNameTextView"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:padding="@dimen/activity_horizontal_margin"
            android:text="Medium Text"
            android:textAppearance="?android:attr/textAppearanceMedium" />

    </TableRow>

    <TableRow
        android:id="@+id/tableRow2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" >

        <TextView
            android:id="@+id/yearLowTextView"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:padding="@dimen/activity_horizontal_margin"
            android:text="@string/stock_year_low" 
            android:layout_weight="1" />

        <TextView
            android:id="@+id/yearHighTextView"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/stock_year_high" 
            android:layout_weight="1" />

    </TableRow>

    <TableRow
        android:id="@+id/tableRow3"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:padding="@dimen/activity_horizontal_margin" >

        <TextView
            android:id="@+id/daysLowTextView"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/stock_days_low"
            android:layout_weight="1" />

        <TextView
            android:id="@+id/daysHighTextView"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/stock_days_high"
            android:layout_weight="1" />

    </TableRow>

    <TableRow
        android:id="@+id/tableRow4"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:padding="@dimen/activity_horizontal_margin" >

        <TextView
            android:id="@+id/lastTradePriceOnlyTextView"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/last_trade_price_only"
            android:layout_weight="1" />

        <TextView
            android:id="@+id/changeTextView"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/change"
            android:layout_weight="1" />

    </TableRow>

    <TableRow
        android:id="@+id/tableRow5"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:padding="@dimen/activity_horizontal_margin" >

        <TextView
            android:id="@+id/daysRangeTextView"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/days_range" />

    </TableRow>

</TableLayout>

StockInfoActivity.java

package com.newthinktank.stockquotes;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLConnection;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlPullParserFactory;

import android.os.AsyncTask;
import android.os.Bundle;
import android.app.Activity;
import android.content.Intent;
import android.util.Log;
import android.view.Menu;
import android.widget.TextView;



public class StockInfoActivity extends Activity {
	
	// Used to identify the app in the LogCat, so I
	// can output messages and debug the program
	
	private static final String TAG = "STOCKQUOTE";
	
	// Define the TextViews I use in activity_stock_info.xml
	
	TextView companyNameTextView;
	TextView yearLowTextView;
	TextView yearHighTextView;
	TextView daysLowTextView;
	TextView daysHighTextView;
	TextView lastTradePriceOnlyTextView;
	TextView changeTextView;
	TextView daysRangeTextView;
	
	// XML node keys
	static final String KEY_ITEM = "quote"; // parent node
	static final String KEY_NAME = "Name";
	static final String KEY_YEAR_LOW = "YearLow";
	static final String KEY_YEAR_HIGH = "YearHigh";
	static final String KEY_DAYS_LOW = "DaysLow";
	static final String KEY_DAYS_HIGH = "DaysHigh";
	static final String KEY_LAST_TRADE_PRICE = "LastTradePriceOnly";
	static final String KEY_CHANGE = "Change";
	static final String KEY_DAYS_RANGE = "DaysRange";
	
	// XML Data to Retrieve
	String name = "";
	String yearLow = "";
	String yearHigh = "";
	String daysLow = "";
	String daysHigh = "";
	String lastTradePriceOnly = "";
	String change = "";
	String daysRange = "";
	
	// Used to make the URL to call for XML data
	String yahooURLFirst = "http://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20yahoo.finance.quote%20where%20symbol%20in%20(%22";
	String yahooURLSecond = "%22)&env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys";
	
	// NEW STUFF
	
	// Holds values pulled from the XML document using XmlPullParser
	String[][] xmlPullParserArray = {{"AverageDailyVolume", "0"}, {"Change", "0"}, {"DaysLow", "0"},
			{"DaysHigh", "0"}, {"YearLow", "0"}, {"YearHigh", "0"},
			{"MarketCapitalization", "0"}, {"LastTradePriceOnly", "0"}, {"DaysRange", "0"},
			{"Name", "0"}, {"Symbol", "0"}, {"Volume", "0"},
			{"StockExchange", "0"}};
			
	int parserArrayIncrement = 0;
			
	// END OF NEW STUFF
	

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		
		// Creates the window used for the UI
		setContentView(R.layout.activity_stock_info);
		
		// Get the message from the intent that has the stock symbol
		Intent intent = getIntent();
		String stockSymbol = intent.getStringExtra(MainActivity.STOCK_SYMBOL);
		
		// Initialize TextViews
		companyNameTextView = (TextView) findViewById(R.id.companyNameTextView);
		yearLowTextView = (TextView) findViewById(R.id.yearLowTextView);
		yearHighTextView = (TextView) findViewById(R.id.yearHighTextView);
		daysLowTextView = (TextView) findViewById(R.id.daysLowTextView);
		daysHighTextView = (TextView) findViewById(R.id.daysHighTextView);
		lastTradePriceOnlyTextView = (TextView) findViewById(R.id.lastTradePriceOnlyTextView);
		changeTextView = (TextView) findViewById(R.id.changeTextView);
		daysRangeTextView = (TextView) findViewById(R.id.daysRangeTextView);
		
		// Sends a message to the LogCat
		Log.d(TAG, "Before URL Creation " + stockSymbol);
		
		// Create the YQL query
		final String yqlURL = yahooURLFirst + stockSymbol + yahooURLSecond;
		
		// The Android UI toolkit is not thread safe and must always be 
		// manipulated on the UI thread. This means if I want to perform
		// any network operations like grabbing xml data, I have to do it
		// in its own thread. The problem is that you can't write to the
		// GUI from outside the main activity. AsyncTask solves those problems
		
		new MyAsyncTask().execute(yqlURL);

	}
	
	// Use AsyncTask if you need to perform background tasks, but also need
	// to change components on the GUI. Put the background operations in
	// doInBackground. Put the GUI manipulation code in onPostExecute
	
	private class MyAsyncTask extends AsyncTask<String, String, String>{
		
		// String... arg0 is the same as String[] args
		protected String doInBackground(String... args) {
			
			try {
			      
				// Get the XML URL that was passed in
				
			      URL url = new URL(args[0]);
			      
			      // connection is the communications link between the 
			      // application and a URL that we will read from.
			      
			      URLConnection connection;
			      connection = url.openConnection();

			      // Used to take advantage of HTTP specific features. 
			      // Provides tools that tell us if a connection was
			      // made, lost and other HTTP Status Codes
			      
			      HttpURLConnection httpConnection = (HttpURLConnection)connection;
			      
			      // Did we connect properly the the URL?
			      
			      int responseCode = httpConnection.getResponseCode();
			      

			      // Tests if responseCode == 200 Good Connection
			     if (responseCode == HttpURLConnection.HTTP_OK) {
			    	 
			    	 // Reads data from the connection
			        InputStream in = httpConnection.getInputStream();

			        // Provides a way to parse DOM object trees from XML documents
			        
			        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
			        
			        // Provides a DOM Document from an xml page
			        DocumentBuilder db = dbf.newDocumentBuilder();

			        // Parse the Yahoo Financial YQL Stock XML File
			        Document dom = db.parse(in);
			        
			        // The root element is query
			        Element docEle = dom.getDocumentElement();

			        // Get a list of quote nodes
			        NodeList nl = docEle.getElementsByTagName("quote");
			        
			        
			        // Checks to make sure we found a quote tag
			        if (nl != null && nl.getLength() > 0) {
			        	
			        // Cycles through if we find multiple quote tags
			        // Mainly used for demonstration purposes
			          for (int i = 0 ; i < nl.getLength(); i++) {
			            
			            // Passes the root element of the XML page, so 
			        	// that the function below can search for the 
			        	  // information needed
			            StockInfo theStock = getStockInformation(docEle);
			            
			            // Gets the values stored in the StockInfo object
			            daysLow = theStock.getDaysLow();
			            daysHigh = theStock.getDaysHigh();
			            yearLow = theStock.getYearLow();
			            yearHigh = theStock.getYearHigh();
			            name = theStock.getName();
			            lastTradePriceOnly = theStock.getLastTradePriceOnly();
			            change = theStock.getChange();
			            daysRange = theStock.getDaysRange();
			            
			            // Outputs information for tracking reasons only
			            // Log.d(TAG, "Stock Name " + name);
			            // Log.d(TAG, "Stock Year High " + yearHigh);
			            // Log.d(TAG, "Stock Year Low " + yearLow);
			            // Log.d(TAG, "Stock Days High " + daysHigh);
			            // Log.d(TAG, "Stock Days Low " + daysLow);

			            
			          }
			        }
			      }
			    } catch (MalformedURLException e) {
			      Log.d(TAG, "MalformedURLException", e);
			    } catch (IOException e) {
			      Log.d(TAG, "IOException", e);
			    } catch (ParserConfigurationException e) {
			      Log.d(TAG, "Parser Configuration Exception", e);
			    } catch (SAXException e) {
			      Log.d(TAG, "SAX Exception", e);
			    }
			    finally {
			    }
			
			// NEW STUFF
			
			try{
				
				Log.d("test","In XmlPullParser");
				
				// It is recommended to use the XmlPullParser because
				// it is faster and requires less memory then the DOM API
				
				// XmlPullParserFactory provides you with the ability to 
				// create pull parsers that parse XML documents
				
				XmlPullParserFactory factory = XmlPullParserFactory.newInstance();

				// Parser supports XML namespaces
				  factory.setNamespaceAware(true);

				  // Provides the methods needed to parse XML documents
				  XmlPullParser parser = factory.newPullParser(); 

				  // InputStreamReader converts bytes of data into a stream
				  // of characters
				  
				  parser.setInput(new InputStreamReader(getUrlData(args[0])));  

				  // Passes the parser and the first tag in the XML document
				  // for processing
				  
				  beginDocument(parser,"query");

				  // Get the currently targeted event type, which starts
				  // as START_DOCUMENT
				  
				  int eventType = parser.getEventType();

				  do{
					  
					// Cycles through elements in the XML document while
					// neither a start or end tag are found

					  nextElement(parser);

					  // Switch to the next element
					  
					  parser.next();
					  
					  // Get the current event type

					  eventType = parser.getEventType();

					  // Check if a value was found between 2 tags
					  
					  if(eventType == XmlPullParser.TEXT){
								  
						  // Get the text from between the tags
						  
						  String valueFromXML = parser.getText();
						  
						  // Store it in an array with the corresponding tag
						  // value
						  
						  xmlPullParserArray[parserArrayIncrement][1] = valueFromXML;

						  Log.d("test", "Values: " + xmlPullParserArray[parserArrayIncrement++][1]);

					  }

				  } while (eventType != XmlPullParser.END_DOCUMENT) ;  
				
			}
			
			catch (ClientProtocolException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (XmlPullParserException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (URISyntaxException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}  
			
			finally {
		    }
			
			// Print out the tags and associated values that
			// were found
			
			for(int i = 0; i < xmlPullParserArray.length; i++){
				
				Log.d("test", xmlPullParserArray[i][0] + ":" + xmlPullParserArray[i][1]);
				
			}
			
			// END OF NEW STUFF
			
			return null;
		}
		
		// NEW STUFF
		
		public InputStream getUrlData(String url) throws URISyntaxException, 
        ClientProtocolException, IOException {

			// Used to get access to HTTP resources
			
			DefaultHttpClient client = new DefaultHttpClient();
			
			// Retrieves information from the URL
			
			HttpGet method = new HttpGet(new URI(url));
			
			// Gets a response from the client on whether the 
			// connection is stable
			
			HttpResponse res = client.execute(method);
			
			// An HTTPEntity may be returned using getEntity() which tells 
			// the system where the content is coming from
			
			return res.getEntity().getContent();
		}
		
		public final void beginDocument(XmlPullParser parser, String firstElementName) throws XmlPullParserException, IOException
	    {
			int type;
			
			// next() advances to the next element in the XML
			// document being a starting or ending tag, or a value
			// or the END_DOCUMENT
			
		    while ((type=parser.next()) != parser.START_TAG
		                   && type != parser.END_DOCUMENT) {
		            ;
		    }
		
		    // Throw an error if a start tag isn't found
		    
		    if (type != parser.START_TAG) {
		    	throw new XmlPullParserException("No start tag found");
		    }
		
		    // Verify that the tag passed in is the first tag in the XML
		    // document
		    
		    if (!parser.getName().equals(firstElementName)) {
		            throw new XmlPullParserException("Unexpected start tag: found " + parser.getName() +
		                    ", expected " + firstElementName);
		    }
	    }
		
		public final void nextElement(XmlPullParser parser) throws XmlPullParserException, IOException
		{
			int type;
			
			// Cycles through elements in the XML document while
			// neither a start or end tag are found
			
			while ((type=parser.next()) != parser.START_TAG
		                   && type != parser.END_DOCUMENT) {
		            ;
			}
		}
		
		// END OF NEW STUFF
		
		// Changes the values for a bunch of TextViews on the GUI
		protected void onPostExecute(String result){
			
			companyNameTextView.setText(name);
			yearLowTextView.setText("Year Low: " + yearLow);
			yearHighTextView.setText("Year High: " + yearHigh);
			daysLowTextView.setText("Days Low: " + daysLow);
			daysHighTextView.setText("Days High: " + daysHigh);
			lastTradePriceOnlyTextView.setText("Last Price: " + lastTradePriceOnly);
			changeTextView.setText("Change: " + change);
			daysRangeTextView.setText("Daily Price Range: " + daysRange);
			
		}
		
		
	}
	
	// Sends the root xml tag and the tag name we are searching for to
	// getTextValue for processing. Then uses that information to create
	// a new StockInfo object
	private StockInfo getStockInformation(Element entry){
		
		String stockName = getTextValue(entry, "Name");
		String stockYearLow = getTextValue(entry, "YearLow");
		String stockYearHigh = getTextValue(entry, "YearHigh");
		String stockDaysLow = getTextValue(entry, "DaysLow");
		String stockDaysHigh = getTextValue(entry, "DaysHigh");
		String stocklastTradePriceOnlyTextView = getTextValue(entry, "LastTradePriceOnly");
		String stockChange = getTextValue(entry, "Change");
		String stockDaysRange = getTextValue(entry, "DaysRange");
		
		StockInfo theStock = new StockInfo(stockDaysLow, stockDaysHigh, stockYearLow,
			stockYearHigh, stockName, stocklastTradePriceOnlyTextView,
			stockChange, stockDaysRange);
		
		return theStock;
		
	}
	
	// Searches through the XML document for a tag that matches 
	// the tagName passed in. Then it gets the value from that
	// tag and returns it
	
	private String getTextValue(Element entry, String tagName){
		
		String tagValueToReturn = null;
		
		NodeList nl = entry.getElementsByTagName(tagName);
		
		if(nl != null && nl.getLength() > 0){
			
			Element element = (Element) nl.item(0);
			
			tagValueToReturn = element.getFirstChild().getNodeValue();
		}
		
		return tagValueToReturn;
		
	}

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

}

87 Responses to “Android Development Tutorial 8”

  1. Joco says:

    Hello Derek, I want to thank you for your awesome content and support.

    Im new to this all and want to create a 2d game like jetpack joyride. How long will this take if I spend 6 hours a day learning and trying?

    thanks.

    • Derek Banas says:

      You are very welcome :) Eventually I’ll start making games. Actually it is going to start very soon. If you understand the following parts of my Java video tutorial : 1 -7, 9, 11 – 18 and go through the Android tutorial you’ll be ready to go when I start making games. Have fun

      • Jack Mader says:

        Hey Derek,
        Thanks for all the great tutorials.
        I just completed Tut #8. Am getting a Source Not Found error for ActivityThread.performLaunchActivity

        ideas??

  2. Luis says:

    Excellent Video, pretty easy to understand

    • Derek Banas says:

      Thank you very much :) Always feel free to ask questions

      • Raj says:

        Hi Raj,

        I have been following your tutorials and I must tell you that this is one of the best Android tutorials that I have ever seen. I have learned a lot by listening your tutorials and following the same to create applications. FYI, I have not only bookmarked your site and have also forwarded your links to my friends. Are you are planning to incorporate tutorials based on Sherlock Themes and GUI design? Though, I am a beginner to Android, I am a Sr.Application Developer working on Java and othe technologies for the last 13 years. Your style of intstructions and tutoring has actually taught me to enhance my skills in Android within a shorter time frame. Looking forward to see more advanced tutorials on Android. Once again, thanks for sharing the knowledge with others who are eager to learn. Wishing you the best Derek.

        Cheers!

        Raj

        • Derek Banas says:

          Hi Raj,

          Thank you for the kind message :) I’m very happy that you are enjoying the Android tutorials. I’m really working to make them as good as possible. Sorry they aren’t coming out faster, but my real world job has been taking all my time. ( This is just a hobby for me )

          Yes I will cover themes and will show how to make much better looking apps in the future. As you can tell, I’m trying to cover as many topics as possible in each tutorial, while trying to avoid getting boring.

          Thanks again
          Derek

  3. OG says:

    Thanks Derek!

    I really appreciate your videos. I really have nothing specific to ask, but I know how much effort goes into these and I wanted you to know that you’re being viewed and thanked.

    Keep up!

    OG

  4. Dan says:

    I have been trying to modify the code from the tutorial to read attributes from XML elements. Like this:

    I cant seem to get it to work, no matter what my methods always return null. Any suggestions on how to implement this?

  5. Sophie says:

    Derek,

    Thanks for your tutorials. I have been following them recently.
    I have a question for you for this tutorial. The app failed to load because of the following message:

    android.widget.ScrollView cannot be cast to android.widget.TableLayout.

    Do you know what might be the cause of this problem?

    Thanks!

    • Sophie says:

      OK. I figured out the problem.

      In your MainActivity.java,

      you have:

      stockTableScrollView = (TableLayout) findViewById(R.id.stockTableScrollView);

      where the type of stockTableScrollView is TableLayout, but in your activity_main.xml

      stockTableScrollView is the id of a scrollView.

      Thanks again for your tutorials. Keep going!

  6. Vince Yun says:

    Comment

  7. Vince Yuan says:

    Thanks for the excellent tutorials.

    I believe your app runs well. But there are several bugs in the source code on the web pages. I suggest you put the whole project file on the web.

    1. need to set TableLayout’s id in activity_main.xml

    2. Sometimes the quote does not contain DaysLow/High. Need to handle it in getTextValue, otherwise the app crashes.

    private String getTextValue(Element entry, String tagName) {
    String tagValueToReturn = "";
    NodeList nl = entry.getElementsByTagName(tagName);
    if (nl != null && nl.getLength() > 0) {
    Element element = (Element) nl.item(0);
    if (element.getChildNodes().getLength() > 0)
    tagValueToReturn = element.getFirstChild().getNodeValue();
    }

    return tagValueToReturn;
    }

  8. Adam says:

    Do you have any idea why mine is breaking on
    int responseCode = httpConnection.getResponseCode() ?

    I don’t know much about log cat put from Log.d print outs I have figured out that that is the line where it breaks. If you want more info from logcat, could you tell me how to find it?

  9. Thomas says:

    Hello Derek and thanks for the videos.

    One question that has been confusing me. The overall package name is “com.newthinktank.stockqutoes”, but then there’s a line in MainActivity that says “public final static String STOCK_SYMBOL = “com.example.myfirstapp.STOCK”. Why are the package names different here? It’s probably something obvious but I’d appreciate if you could tell me!

    Thanks

    • Derek Banas says:

      This is just a common practice in Android that is used often. You don’t have to define everything as Strings though. As the tutorial continues you’ll notice that I start passing other data types between activities. Sorry about not explaining that better

  10. Henry says:

    Hi, I’m trying to add a button to delete individual stock entries. I’ve added a button but I can’t get it delete the correct view and remove the right saved preferences…

    I have this code… it always deletes the top one, and never deletes stuff from savedpreferences… any ideas?


    public OnClickListener deleteStockListener = new OnClickListener(){

    public void onClick(View v) {
    String[] stocks = stockSymbolsEntered.getAll().keySet().toArray(new String[0]);
    int id = 0;
    for (int i = 0; i < stocks.length; i++){
    if(stockSymbolEditText.getText().toString().equals(stocks[i])){
    id = i;
    break;
    }
    }

    stockTableScrollView.removeViewAt(id);

    SharedPreferences.Editor preferencesEditor = stockSymbolsEntered.edit();

    preferencesEditor.remove(stockSymbolEditText.getText().toString());
    preferencesEditor.apply();

    }
    };

  11. Anonymous says:

    First, fantastic tutorials, I really appreciate you putting forth the effort to make sure a great contribution.

    I’ve had pretty good success getting thing to work, but got an exception that my StockInfoActivity is not in the manifest. Is that required? Or is there another way to register the activity.

    Thanks again…

    • Derek Banas says:

      Thank you very much :) The Activities should automatically be placed in the manifest as you create them. If they aren’t you should try updating the Android plugin. (Help -> Check For Updates…)

  12. Rohan Shah says:

    Hey Derek,

    Thank you very much for these tutorials…
    Your work is being extremely helpful to me.
    I am following these tutorials and I have watched 8 of them, understood everything very properly.
    But in the 8th one, my LogCat says “missing INTERNET permission?” and there are 24 different errors, I have done everything as you have explained, so please help me with this.

    Again Thank you very much man, you are AWESOME… :)

    • Derek Banas says:

      Hey,

      Thank you very much for the nice compliments. You need to put the following line in your manifest file right after you define the version of android you are using.

      I hope that helps

      Derek

  13. Paresh says:

    Hey Derek,

    Thanks for the great tutorials. While following #8, I am having an exception as below.

    java.io.EOFException
    at libcore.io.Streams.readAsciiLine(Streams.java:203)
    at libcore.net.http.HttpEngine.readResponseHeaders(HttpEngine.java:573)
    at libcore.net.http.HttpEngine.readResponse(HttpEngine.java:821)
    at libcore.net.http.HttpURLConnectionImpl.getResponse(HttpURLConnectionImpl.java:283)
    at libcore.net.http.HttpURLConnectionImpl.getResponseCode(HttpURLConnectionImpl.java:495)
    at libcore.net.http.HttpsURLConnectionImpl.getResponseCode(HttpsURLConnectionImpl.java:134)

    Am I missing something here? The exception is at the time of reading the response code.

    Earlier I got the missing permission issue wrt Internet which I resolved by adding

    Needless to say, your tutorials are simply awesome.

    • Derek Banas says:

      Hey Paresh,

      Thank you :) I’m glad you are enjoying them.

      There was a bug in Android that was caused when url connections were recycled. Try updating your in Eclipse.

      Also, try downloading the completed package I provide to make sure there isn’t a typo some place. Since there was no errors in your specific class files in the src folder though, but instead in the SDK I’m guessing the bug I mentioned above is causing the problem.

      I hope that helps.

  14. Praveen says:

    awesome video thanks a lot learnt quiete a few thing

  15. Kings says:

    Hi,

    I have followed your tutorials and I am getting quite a few RunTime errors. First 1 being: “FATAL EXCEPTION: AsyncTask #3″
    I have looked through multiple forums and tried various solutions, none of which have worked.

    Any suggestions will be appreciated.

    LogCat:

    10-14 09:57:47.020: E/AndroidRuntime(861): at android.os.AsyncTask$3.done(AsyncTask.java:299)
    10-14 09:57:47.020: E/AndroidRuntime(861): at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:352)
    10-14 09:57:47.020: E/AndroidRuntime(861): at java.util.concurrent.FutureTask.setException(FutureTask.java:219)
    10-14 09:57:47.020: E/AndroidRuntime(861): at java.util.concurrent.FutureTask.run(FutureTask.java:239)
    10-14 09:57:47.020: E/AndroidRuntime(861): at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:230)
    10-14 09:57:47.020: E/AndroidRuntime(861): at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1080)
    10-14 09:57:47.020: E/AndroidRuntime(861): at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:573)
    10-14 09:57:47.020: E/AndroidRuntime(861): at java.lang.Thread.run(Thread.java:841)
    10-14 09:57:47.020: E/AndroidRuntime(861): Caused by: java.lang.SecurityException: Permission denied (missing INTERNET permission?)
    10-14 09:57:47.020: E/AndroidRuntime(861): at java.net.InetAddress.lookupHostByName(InetAddress.java:418)
    10-14 09:57:47.020: E/AndroidRuntime(861): at java.net.InetAddress.getAllByNameImpl(InetAddress.java:236)
    10-14 09:57:47.020: E/AndroidRuntime(861): at java.net.InetAddress.getAllByName(InetAddress.java:214)
    10-14 09:57:47.020: E/AndroidRuntime(861): at libcore.net.http.HttpConnection.(HttpConnection.java:70)
    10-14 09:57:47.020: E/AndroidRuntime(861): at libcore.net.http.HttpConnection.(HttpConnection.java:50)
    10-14 09:57:47.020: E/AndroidRuntime(861): at libcore.net.http.HttpConnection$Address.connect(HttpConnection.java:340)
    10-14 09:57:47.020: E/AndroidRuntime(861): at libcore.net.http.HttpConnectionPool.get(HttpConnectionPool.java:87)
    10-14 09:57:47.020: E/AndroidRuntime(861): at libcore.net.http.HttpConnection.connect(HttpConnection.java:128)
    10-14 09:57:47.020: E/AndroidRuntime(861): at libcore.net.http.HttpEngine.openSocketConnection(HttpEngine.java:316)
    10-14 09:57:47.020: E/AndroidRuntime(861): at libcore.net.http.HttpEngine.connect(HttpEngine.java:311)
    10-14 09:57:47.020: E/AndroidRuntime(861): at libcore.net.http.HttpEngine.sendSocketRequest(HttpEngine.java:290)
    10-14 09:57:47.020: E/AndroidRuntime(861): at libcore.net.http.HttpEngine.sendRequest(HttpEngine.java:240)
    10-14 09:57:47.020: E/AndroidRuntime(861): at libcore.net.http.HttpURLConnectionImpl.getResponse(HttpURLConnectionImpl.java:282)
    10-14 09:57:47.020: E/AndroidRuntime(861): at libcore.net.http.HttpURLConnectionImpl.getResponseCode(HttpURLConnectionImpl.java:497)
    10-14 09:57:47.020: E/AndroidRuntime(861): at com.kings.stockquote.StockInfoActivity$MyAsyncTask.doInBackground(StockInfoActivity.java:96)
    10-14 09:57:47.020: E/AndroidRuntime(861): at com.kings.stockquote.StockInfoActivity$MyAsyncTask.doInBackground(StockInfoActivity.java:1)
    10-14 09:57:47.020: E/AndroidRuntime(861): at android.os.AsyncTask$2.call(AsyncTask.java:287)
    10-14 09:57:47.020: E/AndroidRuntime(861): at java.util.concurrent.FutureTask.run(FutureTask.java:234)
    10-14 09:57:47.020: E/AndroidRuntime(861): … 4 more
    10-14 09:57:47.020: E/AndroidRuntime(861): Caused by: libcore.io.GaiException: getaddrinfo failed: EAI_NODATA (No address associated with hostname)
    10-14 09:57:47.020: E/AndroidRuntime(861): at libcore.io.Posix.getaddrinfo(Native Method)
    10-14 09:57:47.020: E/AndroidRuntime(861): at libcore.io.ForwardingOs.getaddrinfo(ForwardingOs.java:61)
    10-14 09:57:47.020: E/AndroidRuntime(861): at java.net.InetAddress.lookupHostByName(InetAddress.java:405)
    10-14 09:57:47.020: E/AndroidRuntime(861): … 21 more
    10-14 09:57:47.020: E/AndroidRuntime(861): Caused by: libcore.io.ErrnoException: getaddrinfo failed: EACCES (Permission denied)
    10-14 09:57:47.020: E/AndroidRuntime(861): … 24 more
    10-14 09:57:48.380: I/Choreographer(861): Skipped 42 frames! The application may be doing too much work on its main thread.
    10-14 09:57:49.112: W/EGL_emulation(861): eglSurfaceAttrib not implemented
    10-14 09:57:49.151: I/Choreographer(861): Skipped 46 frames! The application may be doing too much work on its main thread.

  16. ltrader says:

    Hello Derek,

    thanks a lot for the your videos so far, giving us the chance to learn Android development!

    By the way I also struggled with the line

    int responseCode = httpConnection.getResponseCode()

    having had an IOException. I then added the line

    to my manifest and it still fails executing the myTask.doInBackground thing..
    Trying to debug I always receive the message No source code available. I am sure it somehow needs to be mapped, if so: Which code exactly and how?

    Most I wonder that the logCat window does not come up with the messages which are written in the catch blocks. The one and only message which I receive is the “Before URL Creation ” in onCreate.

    Do you have an idea about how to figure out what is going on here?

    • Derek Banas says:

      You’re very welcome :) The easiest way to find bugs is to download the complete package for the Android Stock Quote App.

      Then compare the files in my src directory to yours using a tool like DiffNow. The only other files you may need to look at are the Manifest and the layout files.

      I hope that helps

      • Jacob Oliver says:

        Derek, I’ve downloaded and ran the completed Stock Quote app from your website, but I still get the “FATAL EXCEPTION” error described above.
        Does anyone see the same problem?
        Thank you.

        • Jacob Oliver says:

          Actually, here’s some additional info about the problem above. When I open your app in Eclipse StockInfoActivity.java shows a lot of errors.
          For example the error for line 1 is:
          “Multiple markers at this line
          - The type java.lang.Object cannot be resolved. It is indirectly referenced from
          required .class files
          - The type java.lang.String cannot be resolved. It is indirectly referenced from
          required .class files”

          I ‘solved’ this problem by changing project.properties file from ‘target=android-17′ to ‘target=android-19′. This enabled me to run the app in the emulator, but it crashes with the ‘FATAL ERROR’ above.

  17. Jenton says:

    So I’m using Android Studio to do these tutorials, and trying to set up rows in the xml design tab seems pretty finicky. It usually defaults to assigning a textview with an android:layout_column. In your tutorial, you don’t use layout_column, but instead use layout_weight. It seems like layout_weight causes a lot less formatting headaches, but is layout_column supposed to be a better formatting option in TableLayouts?

    Thanks!

    • Derek Banas says:

      I don’t think so. layout_weight is all about the total space available. So if you 1 for one component and 3 for the other they divide the total space 4 so that the second component gets 3/4ths of the space and the other gets 1/4th.

      layout_column is a sort of measurement that I don’t care for because it seems to be hard to control.

  18. aurang zeb says:

    great tutorial. Sir, please also cover the wifi direct topics in simple and detailed manner.
    thanks……..

  19. Cedric Simon says:

    This tutorial is amazing!

    I have lots of Java experience, and with this tutorial I not only learn you to develop Android apps, but I UNDERSTAND what I am doing and why.

    The example used to teach is adding an incredible value since it allow to understand each code written linking it to a “meaningful” result.

    One question: The app works great on my Galaxy Note when holding it vertically, but when I put it horizontally, the row height is much too high. Any idea on how to fix this?

    Thanks a lot for this incredible tutorials.

    Cedric.

    P.S.: I use Android Studio to develop.

    • Derek Banas says:

      Thank you Cedric, I’m happy that you are finding it useful. The reason why you are having the problem when you rotate is because I didn’t create a horizontal layout for the app. I get to how you can do that later in the tutorial. In part 19 of this series I cover it.

  20. Mirza Delic says:

    Hi, i am getting this error message:

    11-14 14:57:05.417: D/AndroidRuntime(2183): Shutting down VM
    11-14 14:57:05.417: W/dalvikvm(2183): threadid=1: thread exiting with uncaught exception (group=0xb0f6e648)
    11-14 14:57:05.417: E/AndroidRuntime(2183): FATAL EXCEPTION: main
    11-14 14:57:05.417: E/AndroidRuntime(2183): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.ikresoft.stockquote/com.ikresoft.stockquote.MainActivity}: java.lang.ClassCastException: android.widget.ScrollView cannot be cast to android.widget.TableLayout
    11-14 14:57:05.417: E/AndroidRuntime(2183): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2211)
    11-14 14:57:05.417: E/AndroidRuntime(2183): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2261)
    11-14 14:57:05.417: E/AndroidRuntime(2183): at android.app.ActivityThread.access$600(ActivityThread.java:141)
    11-14 14:57:05.417: E/AndroidRuntime(2183): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1256)
    11-14 14:57:05.417: E/AndroidRuntime(2183): at android.os.Handler.dispatchMessage(Handler.java:99)
    11-14 14:57:05.417: E/AndroidRuntime(2183): at android.os.Looper.loop(Looper.java:137)
    11-14 14:57:05.417: E/AndroidRuntime(2183): at android.app.ActivityThread.main(ActivityThread.java:5103)
    11-14 14:57:05.417: E/AndroidRuntime(2183): at java.lang.reflect.Method.invokeNative(Native Method)
    11-14 14:57:05.417: E/AndroidRuntime(2183): at java.lang.reflect.Method.invoke(Method.java:525)
    11-14 14:57:05.417: E/AndroidRuntime(2183): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:737)
    11-14 14:57:05.417: E/AndroidRuntime(2183): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
    11-14 14:57:05.417: E/AndroidRuntime(2183): at dalvik.system.NativeStart.main(Native Method)
    11-14 14:57:05.417: E/AndroidRuntime(2183): Caused by: java.lang.ClassCastException: android.widget.ScrollView cannot be cast to android.widget.TableLayout
    11-14 14:57:05.417: E/AndroidRuntime(2183): at com.ikresoft.stockquote.MainActivity.onCreate(MainActivity.java:40)
    11-14 14:57:05.417: E/AndroidRuntime(2183): at android.app.Activity.performCreate(Activity.java:5133)
    11-14 14:57:05.417: E/AndroidRuntime(2183): at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1087)
    11-14 14:57:05.417: E/AndroidRuntime(2183): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2175)
    11-14 14:57:05.417: E/AndroidRuntime(2183): ... 11 more

    How can i solve this?

    Thanks.

    • Derek Banas says:

      After the video there is a link named Android Stock Quote App

      Click it and download the whole complete package and try running it. That will clear up any typos. Then you can compare my class files, layout files and the manifest to yours with something like diffnow.com

  21. VictoR says:

    I finally finish this tutorial 8!!, First, I want to thank you for sharing some of your experience and knowledge with us. I have a few months trying to learn this and I have found your videos not only really informative but pedagogically sound to understand the concepts. It helps a lot your method of explaining what it does and why , while you are typing the code.

    I finish this tutorial and I don’t find any red flag on my code however my emulator won’t lunch. I also copy the whole package and try to run it and I got the same response. Should I move on to tutorial 9 or focus on debugging it first?

    the message I am getting is
    ….emulator fail to lunch.. I tried 3 different emulators.

    May be my pc is the problem. Is there any labtop minimum requirements that you recommend for developing in eclipse?

    Once againg thanks
    VictoR

  22. Sahil Dave says:

    Hey Derek, just wanted to ask you a question.

    Do you recommend learning all the commands like DocumentBuilder, Element etc in the MyAsyncTask?

    • Derek Banas says:

      No there is no need to memorize. In the beginning you’ll do a lot of copying and pasting from previous code. After a while you’ll remember things naturally. Comment your code very well to help.

  23. PetruBogdanPetrescu says:

    Hello Derek,

    Great work! Thank you!

    There seems to be an issue with the Yahoo page.

    While the initial page (https://developer.yahoo.com/yql/console/?q=show%20tables&env=store://datatables.org/alltableswithkeys#h=select+*+from+yahoo.finance.quote+where+symbol+in+%28%22MSFT%22%29) is reachable from my computer, “THE REST QUERY” page (https://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20yahoo.finance.quote%20where%20symbol%20in%20(%22MSFT%22)&env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys) is not. The same situation with my phone.

    After some investigation (it’s amazing how many people have this problem), I understood that there could be a problem with my home internet provider filtering somehow the “query.yahooapis.com” domain.
    Switching my phone connection from home-wireless network to “mobile data”, I was able to reach “THE REST QUERY” page.

    Thank you again for your great work.

    Best regards,
    B

  24. Oliver Foxall says:

    Hi Derek,

    I have just finished going through all the tutorials for this project and it appeared that everything was in order. However, when I went to run the app in an emulator the app started and then instantly closed. I have tried two different emulators and the same thing happened.

    I then downloaded the complete package from this webpage and set it up in Eclipse and attempted to run it. Exactly the same thing happened as before.

    Is there anything I can do about this?

    • Derek Banas says:

      Hi Oliver,

      Sorry about the problems. I’m guessing that Yahoo changed their tags and that is the issue. Just in the past few weeks I have been getting complaints. I’ll be doing a new Android tutorials starting this month. This time I’ll try not to use anything that could possibly break.

  25. Saurabh PAtni says:

    Superb fantastic series Derek.
    App runs perfectly well, made some mistakes, but as you suggested above to use DiffNow tool was able to grab it.
    Thanks…. Learning is Fun

  26. Jeff says:

    Hi Derek,

    When I press print, it prints the whole website out. Is there a way to only print the code?

  27. Shikha says:

    Hi Derek,
    Nice video tutorial. I had learn a lot from videos till now. Will complete the whole tutorial soon. I test the app in your tutorial on my Nexus 7 and not on the emulator as it’s very slow.

    I got two errors while testing the app.
    I) Once you populate the app with stocks and then you tilt the tablet(change orientation to horizontal from vertical), all list is gone and replaced by a single stock which is the last stock which you have entered(say YHOO)

    II) You cannot enter a wrong symbol as it gives error after pressing the Quote button that this app have been stopped.

    Can you please fix them. In the first error can you also tell how to fix the app to run only on vertical mode.

    • Derek Banas says:

      Sorry about the errors. I should have stated that the apps weren’t optimized, but instead were structured more to cover as much as possible.

      I’m making a new Android tutorial that will fix those issues in the next few weeks.

  28. Zach says:

    Hey Derek,

    I just finished with this tutorial. I ran the program, and while it’s not catching any errors, all of the stock information returns empty when I hit the quote button. Everything else seems to be working fine, including the web button.

    I’ve been going my code and comparing it to yours, but I can’t seem to find what’s wrong. Do you have any ideas as to what’s causing this?

  29. Subash Ghimire says:

    Hi Derek,

    I’ve done all the things as you have shown in this tutorial and previous but the app didn’t work. I executed the program into my android device, the app started but when i enetred the symbol of a company i.e msft and aapl and hit enter nothing happened. Plz help me solve this problem.

  30. Jeff says:

    I’m printing them all out, just to check if I missed something. I don’t recall seeing these two source files created, which confused me a little. I’m not sure if anybody else got confused.

Leave a Reply

Your email address will not be published.

You may use these HTML tags and attributes: <a href="" title="" rel=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Google+