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.
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 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");
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 this code here that worked all this time in 2.3 now we have to update it and I am getting a lot of errors like NetworkOnMainThreadException. I want to go and grab a xml from my web service, bring it down and parse it into an array list. Here is the code
//Gets the xml from the url specified
String CallWebService(String url){
String xml = null;
try {
// defaultHttpClient
DefaultHttpClient httpClient = new DefaultHttpClient();
HttpGet httpGet = new HttpGet(url);
HttpResponse httpResponse = httpClient.execute(httpGet);
HttpEntity httpEntity = httpResponse.getEntity();
xml = EntityUtils.toString(httpEntity);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
// return XML
return xml;
}
//Parses the xml to get DOM element
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;
}
//Gets the child nodes of the xml
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 || child.getNodeType() == Node.CDATA_SECTION_NODE){
return child.getNodeValue();
}
}
}
}
return "";
}
I also have a getChildElements method. The problem is when I call this method. I used to do so like this:
String serviceURL = "http://webservice.example.com/";
String xml = CallWebService(serviceURL);
Document doc = GetDomElement(xml); // getting DOM element
NodeList nl = doc.getElementsByTagName("details");
getChildElements(nl);
But now in 4.1 I need to do this asynchronously and I don't know how. Any help will be greatly appreciated.
EDIT
Here is what i have bu the Thread does not start
final String serviceURL = "urlString";
mHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
if(msg.what == JOB_COMPLETE) {
String xml = (String) msg.obj;
Document doc = GetDomElement(xml); // getting DOM element
NodeList nl = doc.getElementsByTagName("details");
getChildElements(nl);
}
super.handleMessage(msg);
}
};
Thread t = new Thread() {
#Override
public void run() {
String xml = CallWebService(serviceURL);
Message msg = Message.obtain(mHandler, JOB_COMPLETE, xml);
msg.sendToTarget();
}
};
t.start();
EDIT
So I am trying the async way and it still wont work. Its not hitting the GetDomElement at all. Here is the code.
//I call this in my onCreate()
new getAppInfo().execute("http://webservice.example.com");
private class getAppInfo extends AsyncTask<String, Void, String> {
/** The system calls this to perform work in a worker thread and
* delivers it the parameters given to AsyncTask.execute() */
protected String doInBackground(String... urls) {
return CallWebService(urls[0]);
}
/** The system calls this to perform work in the UI thread and delivers
* the result from doInBackground() */
protected void onPostExecute(String xml) {
Document doc = GetDomElement(xml); // getting DOM element
NodeList nl = doc.getElementsByTagName("details");
getChildElements(nl);
}
}
You have to implement an AsyncTask:
http://developer.android.com/reference/android/os/AsyncTask.html
Btw this is needed from Android 3 (if I remember well).
I've implemented this in my app, you can browse my code here: https://github.com/enrichman/roma-tre/blob/master/src/com/roma3/infovideo/utility/rss/RssTask.java
Hope this help
http://www.techrepublic.com/blog/app-builder/using-androids-asynctask-to-handle-long-running-io/670?pg=2&tag=content;siu-container
Define a Handler in your main ui thread in activity onCreate for example
private Handler mHandler;
private static int JOB_COMPLETE = 1;
mHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
if(msg.what == JOB_COMPLETE) {
String xml = (String) msg.obj;
// do whatever you want with that string
}
super.handleMessage(msg);
}
};
Then run all your long jobs in background thread
final String url = "...........";
Thread t = new Thread() {
#Override
public void run() {
String xml = CallWebService(url);
Message msg = Message.obtain(mHandler, JOB_COMPLETE, xml);
msg.sendToTarget();
}
};
t.start();
The exception that is thrown when an application attempts to perform a networking operation on its main thread.
This is only thrown for applications targeting the Honeycomb SDK or higher. Applications targeting earlier SDK versions are allowed to do networking on their main event loop threads, but it's heavily discouraged
see android developers page
Do your network related task using Async task or try using safe threads
I get a NetworkOnMainThreadException when I try to implement the following code:
public class HandlingXMLStuff extends ListActivity{
static final String URL = "xml_file";
static final String ITEM = "item"; //parent
static final String Id = "id";
static final String Name = "name";
static final String Desc = "desc";
static final String Link = "Link";
#Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.xmllist);
ArrayList<HashMap<String, String>> menuItems = new ArrayList<HashMap<String, String>>();
xmlparser parser = new xmlparser();
String xml = parser.getXmlFromUrl(URL);
Document doc = parser.getDomElement(xml);
NodeList nl = doc.getElementsByTagName(ITEM);
//START: loop through all item nodes <item>
for (int i = 0;i<nl.getLength();i++){
//lets create our HASHMAP!! (feeds items into our ArrayList)
HashMap<String, String> map = new HashMap<String, String>();
Element e = (Element) nl.item(i);
//add each child node to the HashMap (key, value/<String, String>)
map.put(Name, parser.getValue(e, Name));
map.put(Desc, parser.getValue(e, Desc));
map.put(Link, parser.getValue(e, Link));
menuItems.add(map);
}//DONE
ListAdapter adapter = new SimpleAdapter(this, menuItems, R.layout.list_item,
new String[] {Name, Desc, Link}, new int []{R.id.name, R.id.description, R.id.link});
setListAdapter(adapter);
}
}
and the handler:
public class xmlparser{
public String getXmlFromUrl(String url) {
String xml = null;
try {
DefaultHttpClient httpClient = new DefaultHttpClient();
HttpPost httpPost = new HttpPost(url);
HttpResponse httpResponse = httpClient.execute(httpPost);
HttpEntity httpEntity = httpResponse.getEntity();
xml = EntityUtils.toString(httpEntity);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return xml;
}
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 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 "";
}
}
Any idea why? It should work, all the tutorials I've read treat this as working code but it doesn't run and only throws the exception. I've read I might need to implement asynctask but im new to it and not sure what parts need their own thread. Thanks for any help, critique (constructive), suggestions, etc.
Any idea why?
Because, if that hunk of code is being executed on the main application thread, you are doing network I/O on the main application thread.
I've read I might need to implement asynctask but im new to it and not sure what parts need their own thread.
I would put the network I/O and the parsing in doInBackground() and the setListAdapter() call in onPostExecute() of an AsyncTask.
If you simply want to test your code, and don't want to add any more complications yet, you can add this to your onCreate()
if (android.os.Build.VERSION.SDK_INT > 9) {
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
}
You don't want this to be permanent, as network operations on the UI thread makes for a bad experience when using the app, but can be useful when testing.
Adding to CommonsWare answer, the NetworkOnMainThreadException was added sometime between 2.3.3 (Gingerbread_MR1) and 3.0 (Honeycomb). If you look at
android.app.ActivityThread
you will find the following piece of code:
/**
* For apps targetting SDK Honeycomb or later, we don't allow
* network usage on the main event loop / UI thread.
*
* Note to those grepping: this is what ultimately throws
* NetworkOnMainThreadException ...
*/
if (data.appInfo.targetSdkVersion > 9) {
StrictMode.enableDeathOnNetwork();
}
I think the tutorials that you were following were written before this was put into place, and so did not cause the NetworkOnMainThreadException. Follow CommonsWare instructions regarding AsyncTask and you'll fix your error.