I am creating an Android application. In that, I am showing the result by parsing an XML file that is stored in the SD card of the mobile. But it is taking more than one minute to parse the XMl file.
So for this I have implemented the AsyncTask functionality, but still it is taking more than one min.
The same code, if I am running as a Java application for parsing the XML, is taking 3-5 seconds to parse the complete XML and printing the data.
Parsing code
public class ParseMyTripResponseXML {
String aprovedStatus="";
SetFlightRecordsData objFlight;
public MyTripRespone parseMyTripXML(File filename) {
MyTripRespone respObj = new MyTripRespone();
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder dBuilder = null;
CorporateBookingApprovals corpApprovalObj = null;
List<CorporateBookingApprovals> corpApprovalList = new ArrayList<CorporateBookingApprovals>();
try {
dBuilder = dbFactory.newDocumentBuilder();
}
catch (ParserConfigurationException e) {
e.printStackTrace();
}
Document doc = null;
try {
doc = dBuilder.parse(filename);
}
catch (SAXException e) {
Log.d("SAXException", e.getMessage()+"");
}
catch (IOException e) {
Log.d("IOException", e.getMessage()+"");
}
doc.getDocumentElement().normalize();
Node rootNode = doc.getElementsByTagName("Root").item(0);
Element rootElement = (Element) rootNode;
String status = getTagValue("StatusCode", rootElement);
if (status.equals("200")) {
NodeList corpList = ((Element) doc.getElementsByTagName("Result").item(0)).getElementsByTagName("CorporateBookingApprovals");
for (int i = 0; i < corpList.getLength(); i++) {
try {
Node corporateDetailsNode = corpList.item(i);
Element corporateDetailsElement = (Element) corporateDetailsNode;
corpApprovalObj = new CorporateBookingApprovals();
corpApprovalObj.setApprovalId(getTagValue("ApprovalId", corporateDetailsElement));
corpApprovalObj.setAgentId(getTagValue("AgentId", corporateDetailsElement));
String statusApproval = getTagValue("ApprovalStatus", corporateDetailsElement);
if(statusApproval.equals("approved")){
aprovedStatus = "A";
}else if (statusApproval.equals("pending")) {
aprovedStatus = "P";
}
else if (statusApproval.equals("inqueue")) {
aprovedStatus = "Q";
}
else if (statusApproval.equals("rejected")) {
aprovedStatus = "R";
}
corpApprovalObj.setApprovalStatus(aprovedStatus);
corpApprovalObj.setInsertTime(getTagValue("InsertTime", corporateDetailsElement));
objFlight = new SetFlightRecordsData();
objFlight.setFlightData(doc, corpApprovalObj);
corpApprovalList.add(corpApprovalObj);
}
catch (Exception e) {
Log.d("exception in main", e.getMessage()+"");
continue;
}
}
respObj.setCoroprateBookingDetails(corpApprovalList);
}
return respObj;
}
public static String getTagValue(String sTag, Element eElement) {
NodeList nlList = eElement.getElementsByTagName(sTag).item(0)
.getChildNodes();
Node nValue = (Node) nlList.item(0);
if (nValue == null) {
return "";
}
else {
return nValue.getNodeValue();
}
}
How do I make it faster?
I am using the DOM parser.
I suggest the general approach to speeding up your XML parse routine by adding timer functions and process of elimination, commenting out sections and rerunning it so you know exactly what is causing your slow down. Usual suspects would be object creation calls and string handling.
long startTime;
long endTime;
startTime = android.os.SystemClock.uptimeMillis();
// parse routine here
endTime = android.os.SystemClock.uptimeMillis();
Log.d("xmlparse", "Excution time: "+(endTime-startTime)+" ms");
Related
public String getMetaData() {
String errors = "";
try {
URL url = new URL("http://in2streaming.com:9999/stats?sid=1.xml");
URLConnection conn = url.openConnection();
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
// Error Here:
Document doc = db.parse(conn.getInputStream().toString());
// get the root node
NodeList nodeList = doc.getElementsByTagName("SHOUTCASTSERVER");
Node node=nodeList.item(0);
// the node has three child nodes
for (int i = 0; i < node.getChildNodes().getLength(); i++) {
Node temp=node.getChildNodes().item(i);
if(temp.getNodeName().equalsIgnoreCase("SONGTITLE")){
return temp.getTextContent();
}
}
return "Couldn't reach XML";
}
catch (Exception e) {
return "Exception ";
}
}
Calling this function via Runnable, Got Exception android.os.NetworkOnMainThreadException
I might change the link to http://in2streaming.com:9999/7.html and use HTMl parser instead
// Refresh meta data
private final Runnable refresh_meta = new Runnable() {
#Override
public void run() {
Toast.makeText(m_context, getMetaData(), Toast.LENGTH_SHORT).show();
m_handler.postDelayed(this, 5000);
}
};
For NetworkOnMainThreadException(You can also use AsyncTask):
Executors.newSingleThreadExecutor().submit(new Runnable() {
#Override
public void run() {
Toast.makeText(MainActivity.this, getMetaData(), Toast.LENGTH_SHORT).show();
}
});
If you want to Schedule every 5 sec.
You can use ScheduledExecutorService
ScheduledExecutorService worker = Executors.newSingleThreadScheduledExecutor();
worker.scheduleAtFixedRate(refresh_meta,
1, //initial delay
5, //run every 5 seconds
TimeUnit.SECONDS);
And Update your Runnable as
private Runnable refresh_meta = new Runnable() {
#Override
public void run() {
final String text = getMetaData();
runOnUiThread(new Runnable() {
#Override
public void run() {
Toast.makeText(m_context, text, Toast.LENGTH_SHORT).show();
}
}
);
}
};
Also,
Change Document doc = db.parse(conn.getInputStream().toString()); to
Document doc = db.parse(conn.getInputStream());
First some remarks:
a) Do not muffle the exceptions like you do here :
catch (Exception e) {
return "Exception ";
}
This way you will never know what was the exception that was thrown. It is better to log/print the exception's stack trace, for example:
catch (Exception e) {
Log.e("TAG", "Error", e);
return "Exception";
}
b) conn.getInputStream().toString() doesn't do what you suppose it does (convert the InputStream to String). DocumentBuilder's parse method takes an InputStream as parameter no need to convert it to String.
Having the above in mind here is your method:
public String getMetaData() {
String errors = "";
try {
URL url = new URL("http://in2streaming.com:9999/stats?sid=1.xml");
URLConnection conn = url.openConnection();
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
// Error Here:
Document doc = db.parse(conn.getInputStream());
// get the root node
NodeList nodeList = doc.getElementsByTagName("SHOUTCASTSERVER");
Node node=nodeList.item(0);
// the node has three child nodes
for (int i = 0; i < node.getChildNodes().getLength(); i++) {
Node temp=node.getChildNodes().item(i);
if(temp.getNodeName().equalsIgnoreCase("SONGTITLE")){
return temp.getTextContent();
}
}
return "Couldn't reach XML";
}
catch (Exception e) {
Log.e("TAG", "Error in getMetaData()", e);
return "Exception ";
}
}
Try running your app again and if an error arises from this method it will be printed in your logcat with the message "Error in getMetaData()". Update your question accordingly with the error to let other members help you.
I'm creating a weather app which gets the min/max temperature from a 5 day forecast XML with same node names. I want to use the current date to look through the XML and find the correct min/max for that day.
This is the weather XML: Link
Here is my code, I've trimmed it just enough to the part where I don't understand the multi-nodes, but still I wanted it to be reusable (Currently it just gets the first min/max as denoted by a 0):
public class MyAsyncTask extends AsyncTask < Void, Void, String > {
//========================== pre execute to get date for xml =======
protected void onPreExecute() {
try {
DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
} catch (Exception e) {}
}#
Override
protected String doInBackground(Void...params) {
//=========================== Load data using xml ================
try {
URL xmlUrl2 = new URL("http://api.openweathermap.org/data/2.5/forecast/daily?q=london&mode=xml&units=metric&cnt=5");
InputStream inm = xmlUrl2.openStream();
Document docm = parsem(inm);
docm.getDocumentElement().normalize();
Node nNodem = docm.getElementsByTagName("temperature").item(0);
Element eElementm = (Element) nNodem;
double dmax = Math.round(Double.parseDouble(eElementm.getAttribute("max")));
int dxmax = (int) dmax;
xmaxtemp = Integer.toString(dxmax);
double dmin = Math.round(Double.parseDouble(eElementm.getAttribute("min")));
int dxmin = (int) dmin;
xmintemp = Integer.toString(dxmin);
} catch (UnknownHostException s) {
internet = false;
} catch (IOException i) {
System.out.println("IO Exception error!");
} catch (Exception ex) {
ex.printStackTrace();
}
return xtemp;
}
//========================= show data===============
#
Override
protected void onPostExecute(String result) {
TextView minmax = (TextView) findViewById(R.id.minmax);
minmax.setText("↑" + xmaxtemp + " " + xmintemp + "↓");
}
//======================== parse document =======
public static Document parse(InputStream is) {
Document ret = null;
DocumentBuilderFactory domFactory;
DocumentBuilder builder;
try {
domFactory = DocumentBuilderFactory.newInstance();
domFactory.setValidating(false);
domFactory.setNamespaceAware(false);
builder = domFactory.newDocumentBuilder();
ret = builder.parse(is);
} catch (Exception ex) {
System.err.println("unable to load XML: " + ex);
}
return ret;
}
}
For better use, u should use xpath to have a perfect manipulation over ur xml data:
this is an example how to get all temperature nodes
String expression = "//temperature";
NodeList nodeList = (NodeList) xPath.compile(expression).evaluate(xmlDocument, XPathConstants.NODESET);
After that you can manipulate the list.
this is a good tuto to start using xpath with java:
java-xml-xpath-tutorial/
In the below code I got an error when running my android project for RssReader.
My main file:
public class Earthquake extends Activity {
ListView earthquakeListView;
ArrayAdapter < Quake > aa;
ArrayList < Quake > earthquakes = new ArrayList < Quake > ()
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
earthquakeListView = (ListView) this.findViewById(R.id.earthquakeListView);
int layoutID = android.R.layout.simple_list_item_1;
aa = new ArrayAdapter < Quake > (this, layoutID, earthquakes);
earthquakeListView.setAdapter(aa);
refreshEarthquakes();
}
private void refreshEarthquakes() {
//get the XML
URL url;
try {
String quakeFeed = getString(R.string.quake_feed);
url = new URL(quakeFeed);
URLConnection connection;
connection = url.openConnection();
HttpURLConnection httpConnection = (HttpURLConnection) connection;
int responseCode = httpConnection.getResponseCode();
if (responseCode == HttpURLConnection.HTTP_OK) {
InputStream in = httpConnection.getInputStream();
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
//Parse the earthquake feed
Document dom = db.parse( in );
Element docEle = dom.getDocumentElement();
//Clear the old earthquakes
earthquakes.clear();
//Get a list of each earthquake entry
NodeList nl = docEle.getElementsByTagName("entry");
if (nl != null && nl.getLength() > 0) {
for (int i = 0; i < nl.getLength(); i++) {
Element entry = (Element) nl.item(i);
Element title = (Element) entry.getElementsByTagName("title").item(0);
Element g = (Element) entry.getElementsByTagName("georss:point").item(0);
Element when = (Element) entry.getElementsByTagName("updated").item(0);
Element link = (Element) entry.getElementsByTagName("link").item(0);
String details = title.getFirstChild().getNodeValue();
String hostname = "http://earthquake.usgs.gov";
String linkString = hostname + link.getAttribute("href");
String point = g.getFirstChild().getNodeValue();
String dt = when.getFirstChild().getNodeValue();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'hh:mm:ss'Z'");
Date qdate = new GregorianCalendar(0, 0, 0).getTime();
try {
qdate = sdf.parse(dt);
} catch (ParseException e) {
e.printStackTrace();
}
String[] location = point.split(" ");
Location l = new Location("dummyGPS");
l.setLatitude(Double.parseDouble(location[0]));
l.setLongitude(Double.parseDouble(location[1]));
String magnitudeString = details.split(" ")[1];
int end = magnitudeString.length() - 1;
double magnitude = Double.parseDouble(magnitudeString.substring(0, end));
details = details.split(",")[1].trim();
Quake quake = new Quake(qdate, details, l, magnitude, linkString);
//Process a newly found earthquake
addNewQuake(quake);
}
}
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ParserConfigurationException e) {
e.printStackTrace();
} catch (SAXException e) {
e.printStackTrace();
} finally {}
}
private void addNewQuake(Quake _quake) {
//Add the new quake to our list of earthquakes
earthquakes.add(_quake);
//Notify the array adapter of a change
aa.notifyDataSetChanged();
}
}
Second file:
public class Quake {
private Date date;
private String details;
private Location location;
private double magnitude;
private String link;
public Date getDate() {
return date;
}
public String getDetails() {
return details;
}
public Location getLocation() {
return location;
}
public double getMagnitude() {
return magnitude;
}
public String getLink() {
return link;
}
public Quake(Date _d, String _det, Location _loc, double _mag, String _link) {
date = _d;
details = _det;
location = _loc;
magnitude = _mag;
link = _link;
}
#Override
public String toString() {
SimpleDateFormat sdf = new SimpleDateFormat("HH.mm");
String dateString = sdf.format(date);
return dateString + ": " + magnitude + " " + details;
}
}
I have read many articles with this and I have tried to add AsyncTask but it doesn't work. Also I have tried to add this:
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
But this error comes up:
android.os.NetworkOnMainThreadException
How can I fix this issue?
This exception is thrown when an application attempts to perform a networking operation on its main thread. Run your code in AsyncTask.
see : http://www.androiddesignpatterns.com/2012/06/app-force-close-honeycomb-ics.html
I want to access particular attributes from xml like in this example there are 2 image tag but 2 different attributes size small and size medium so how can i access medium
<image size="small">http://userserve-ak.last.fm/serve/34/62210477.png</image><image size="medium">http://userserve-ak.last.fm/serve/64/62210477.png</image>
I tried this it works on lower android version but it wont work on 4.0
XPathFactory xPathfactory = XPathFactory.newInstance();
XPath xpath = xPathfactory.newXPath();
try {
expr = xpath.compile("//image[#size=\"large\"]");
nl = (NodeList) expr.evaluate(doc, XPathConstants.NODESET);
here is Full code
public class loadSomeStuff extends AsyncTask<Void, Void, String>
{
XPathExpression expr;
NodeList nl;
int i;
String name="test";
#Override
protected String doInBackground(Void... params) {
// TODO Auto-generated method stub
final String KEY_NAME = "name";
final String KEY_IMAGE ="image";
//final String KEY_COST = "cost";
//final String KEY_DESC = "description";
String URL = "http://ws.audioscrobbler.com/2.0/?method=artist.search&artist=enrique_iglesias&api_key=b25b959554ed76058ac220b7b2e0a026&limit=" + 1 + "&page=" + 1;
XmlParser parser = new XmlParser();
String xml = parser.getXmlFromUrl(URL); // getting XML
Document doc = parser.getDomElement(xml); // getting DOM element
//XPathFactory xPathfactory = XPathFactory.newInstance();
//XPath xpath = xPathfactory.newXPath();
//try {
// expr = xpath.compile("//image[#size=\"large\"]");
//nl = (NodeList) expr.evaluate(doc, XPathConstants.NODESET);
NodeList nl = doc.getElementsByTagName("artist");
for (i = 0; i < nl.getLength(); i++)
{
Element e = (Element) nl.item(i);
name = parser.getValue(e, KEY_NAME);// name child value
image = parser.getValue(e, KEY_IMAGE);
System.out.print(image);
Log.v(image, "image url");
return image;
}
return null;
}
#Override
protected void onPostExecute(String result) {
// TODO Auto-generated method stub
super.onPostExecute(result);
URL thumb_u;
try {
thumb_u = new URL(result);
Drawable thumb_d = Drawable.createFromStream(thumb_u.openStream(), "src");
Toast toast = Toast.makeText(myActionbar.this, image, Toast.LENGTH_LONG);
toast.show();
icon.setImageDrawable(thumb_d);
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
here is My Xmlparserfile in which my getvalue and get elements are defined
public Document getDomElement(String xml){
Document doc = null;
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
try {
DocumentBuilder db = dbf.newDocumentBuilder();
InputSource is = new InputSource();
is.setCharacterStream(new StringReader(xml));
doc = db.parse(is);
} catch (ParserConfigurationException e) {
Log.e("Error: ", e.getMessage());
return null;
} catch (SAXException e) {
Log.e("Error: ", e.getMessage());
return null;
} catch (IOException e) {
Log.e("Error: ", e.getMessage());
return null;
}
// return DOM
return doc;
}
public String getValue(Element item, String str) {
NodeList n = item.getElementsByTagName(str);
return this.getElementValue(n.item(0));
}
public final String getElementValue( Node elem ) {
Node child;
if( elem != null){
if (elem.hasChildNodes()){
for( child = elem.getFirstChild(); child != null; child = child.getNextSibling() ){
if( child.getNodeType() == Node.TEXT_NODE ){
return child.getNodeValue();
}
}
}
}
return "";
}
}
Try this:
XMLParser parser = new XMLParser();
String URL = "http://ws.audioscrobbler.com/2.0/?method=artist.gettopalbums&artist=akon&api_key=your_api_key";
String xml = parser.getXmlFromUrl(URL); // getting XML
Document doc = parser.getDomElement(xml); // getting DOM element
NodeList nl = doc.getElementsByTagName("album");
for (int i = 0; i < nl.getLength(); i++) {
Element e = (Element) nl.item(i);
Log.e("name", parser.getValue(e, "name"));
NodeList k = e.getElementsByTagName("image");
for (int j = 0; j < k.getLength(); j++) {
Element e1 = (Element) k.item(j);
if(e1.getAttribute("size").equals("large"))
Log.e("ImageURL", parser.getValue(e1, "image"));
}
}
I have an AsyncTask which is executed just before my application quits. It gets the location and also parses my layout xml file. The location is retrieved but the parsing doesn't get executed.
Calling AsyncTask in my Main Activity:
public void quitApplication()
{
FinishProcess fProcess = new FinishProcess();
fProcess.execute(this);
}
AsyncTask:
public class FinishProcess extends AsyncTask<Main, Void, Void>
{
#Override
protected Void doInBackground(Main... params) {
LocationHandler lh = new LocationHandler();
try {
lh.getLocationSingle(null, params[0]);
} catch (InterruptedException e) {
e.printStackTrace();
}
parseXML(params[0]);
return null;
}
private void parseXML(Main params)
{
String ANDROID_ID = "android:id";
Resources resources = params.getResources();
try {
InputStream fXmlFile = resources.openRawResource(R.raw.pages);
//Reads xml file and gets the node types and attributes
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
Document doc = dBuilder.parse(fXmlFile);
doc.getDocumentElement().normalize();
NodeList nList = doc.getElementsByTagName("*");
for (int temp = 0; temp < nList.getLength(); temp++) {
Node nNode = nList.item(temp);
if (nNode.getNodeType() == Node.ELEMENT_NODE) {
Element eElement = (Element) nNode;
System.out.println(eElement.getNodeName());
}
}
}
catch (Exception e) {
System.out.println("Catch");
e.printStackTrace();
}
}
}
If your application is quitting after starting this process, then perhaps the main thread is dying while the background one (AsyncTask) is running, thereby orphaning it. If this needs to be done during shutdown try doing it in Application.onTerminate without the AsyncTask thread.