NetworkOnMainThread - android

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.

Related

How to sort my xml in Listview by pubdate in android

I have an Rss feed that i'm parsing. I need it to sort and organize from top to bottom by pubdate. Here is the code that i'm using.
XML Parser
public class XMLParser {
// constructor
public XMLParser() {
}
/**
* Getting XML from URL making HTTP request
* #param url string
* */
public String getXmlFromUrl(String url) {
String xml = null;
try {
// defaultHttpClient
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
return xml;
}
/**
* Getting XML DOM element
* #param XML string
* */
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;
}
/** Getting node value
* #param elem element
*/
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 "";
}
/**
* Getting node value
* #param Element node
* #param key string
* */
public String getValue(Element item, String str) {
NodeList n = item.getElementsByTagName(str);
return this.getElementValue(n.item(0));
}
}
Parsing Activity
public class AndroidXMLParsingActivity extends ListActivity {
// All static variables
static final String URL = "http://www.cpcofc.org/devoapp.xml";
// XML node keys
static final String KEY_ITEM = "item"; // parent node
static final String KEY_ID = "item";
static final String KEY_NAME = "title";
static final String KEY_COST = "description";
static final String KEY_DESC = "description";
ArrayList<HashMap<String, String>> menuItems = new ArrayList<HashMap<String, String>>();
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
ArrayList<HashMap<String, String>> menuItems = new ArrayList<HashMap<String, String>>();
XMLParser parser = new XMLParser();
String xml = parser.getXmlFromUrl(URL); // getting XML
Document doc = parser.getDomElement(xml); // getting DOM element
NodeList nl = doc.getElementsByTagName(KEY_ITEM);
// looping through all item nodes <item>
for (int i = 0; i < nl.getLength(); i++) {
// creating new HashMap
HashMap<String, String> map = new HashMap<String, String>();
Element e = (Element) nl.item(i);
// adding each child node to HashMap key => value
map.put(KEY_ID, parser.getValue(e, KEY_ID));
map.put(KEY_NAME, parser.getValue(e, KEY_NAME));
map.put(KEY_COST, parser.getValue(e, KEY_COST));
map.put(KEY_DESC, parser.getValue(e, KEY_DESC));
// adding HashList to ArrayList
menuItems.add(map);
}
// Adding menuItems to ListView
ListAdapter adapter = new SimpleAdapter(this, menuItems,
R.layout.list_item,
new String[] { KEY_DESC, KEY_NAME, KEY_COST}, new int[] {
R.id.desciption, R.id.name, R.id.cost});
setListAdapter(adapter);
// selecting single ListView item
ListView lv = getListView();
lv.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
// getting values from selected ListItem
String name = ((TextView) view.findViewById(R.id.name)).getText().toString();
String cost = ((TextView) view.findViewById(R.id.cost)).getText().toString();
// Starting new intent
Intent in = new Intent(getApplicationContext(), SingleMenuItemActivity.class);
in.putExtra(KEY_NAME, name);
in.putExtra(KEY_COST, cost);
startActivity(in);
}
});
}
}
Here is what it looks like right now
I need to show the reverse of this with day 1 at the top. Anyone have any ideas on how to make this work?
You just need to reverse the order of the List in order to achieve what you want,
we can use Collections class provided by java collection framework ... here is the simple code
Collections.reverse(menuItems);
it will reverse your collection.... I hope this will help you
you shouldn't need to override sort the ArrayAdapter class implements that for you. All you need to do is create your own Comparator that will sort the generic type objects the way you want them to appear. Also, Your code should work correctly if you use this approach.
adapter = new CustomAdapter(this, R.layout.list,R.id.title, data);
adapter.sort(new Comparator<RowData>() {
public int compare(RowData arg0, RowData arg1) {
return arg0.mProductName.compareTo(arg1.mProductName);
}
});
setListAdapter(adapter);
adapter.notifyDataSetChanged();
For more reference..
http://www.vogella.com/articles/AndroidListView/article.html#listview_filtersort
https://github.com/bauerca/drag-sort-listview/tree/master/demo
both previous answers will cost you some performance because they loop through the ArrayList AT LEAST once.
you can simply use a reverse iterator for your loop like this:
int len = nl.getLength();
for (int i = len; i > 0; --i)
i also extracted the length of the array into a local variable cause it's way faster than calling the getLength method every time.

Unable to start activity ComponentInfo{

I have the following mistake:
12-05 20:35:31.005: E/AndroidRuntime(1084): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.helplawyer/com.example.helplawyer.AndroidXMLParsingActivity}: android.os.NetworkOnMainThreadException
in xml manifest I added <uses-permission android:name="android.permission.INTERNET" />
this is my main class
package com.example.helplawyer;
public class AndroidXMLParsingActivity extends ListActivity {
// All static variables
static final String URL = "http://www.consultant.ru/rss/hotdocs.xml";
// XML node keys
static final String KEY_ITEM = "item"; // parent node
static final String KEY_TITLE = "title";
static final String KEY_DATE = "pubDate";
static final String KEY_LINK = "link";
static final String KEY_DESC = "description";
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.mainxml);
ArrayList<HashMap<String, String>> menuItems = new ArrayList<HashMap<String, String>>();
XMLParser parser = new XMLParser();
String xml = parser.getXmlFromUrl(URL); // getting XML
Document doc = parser.getDomElement(xml); // getting DOM element
NodeList nl = doc.getElementsByTagName(KEY_ITEM);
// looping through all item nodes <item>
for (int i = 0; i < nl.getLength(); i++) {
// creating new HashMap
HashMap<String, String> map = new HashMap<String, String>();
Element e = (Element) nl.item(i);
// adding each child node to HashMap key => value
map.put(KEY_TITLE, parser.getValue(e, KEY_TITLE));
map.put(KEY_LINK, parser.getValue(e, KEY_LINK));
map.put(KEY_DATE, parser.getValue(e, KEY_DATE));
map.put(KEY_DESC, parser.getValue(e, KEY_DESC));
// adding HashList to ArrayList
menuItems.add(map);
}
// Adding menuItems to ListView
ListAdapter adapter = new SimpleAdapter(this, menuItems,
R.layout.list_item,
new String[] { KEY_TITLE, KEY_DESC, KEY_DATE, KEY_LINK }, new int[] {
R.id.name, R.id.description, R.id.cost, R.id.link });
setListAdapter(adapter);
// selecting single ListView item
ListView lv = getListView();
lv.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
// getting values from selected ListItem
String name = ((TextView) view.findViewById(R.id.name)).getText().toString();
String cost = ((TextView) view.findViewById(R.id.cost)).getText().toString();
String link = ((TextView) view.findViewById(R.id.link)).getText().toString();
String description = ((TextView) view.findViewById(R.id.description)).getText().toString();
// Starting new intent
Intent in = new Intent(getApplicationContext(), SingleMenuItemActivity.class);
in.putExtra(KEY_TITLE, name);
in.putExtra(KEY_DATE, cost);
in.putExtra(KEY_LINK, link);
in.putExtra(KEY_DESC, description);
startActivity(in);
}
});
}
}
XMLParser
package com.example.helplawyer;
public class XMLParser {
// constructor
public XMLParser() {
}
/**
* Getting XML from URL making HTTP request
* #param url string
* */
public String getXmlFromUrl(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;
}
/**
* Getting XML DOM element
* #param XML string
* */
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;
}
/** Getting node value
* #param elem element
*/
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 "";
}
/**
* Getting node value
* #param Element node
* #param key string
* */
public String getValue(Element item, String str) {
NodeList n = item.getElementsByTagName(str);
return this.getElementValue(n.item(0));
}
}
I read on stackoverflow that I need to use new Thread(new Runnable() {
but I don't understand how to rewrite my code that my app works good.
Please, help me with my problem!
Thank you
From the Android documentation.
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 the document Designing for Responsiveness.
Also see StrictMode.
Look here for examples of running this operation in the background (Find "How to Avoid ANRs")
You cannot access network from your main thread.
you need to use AsyncTask . Check my answer at
Android Connecting with PHP and MySql Force Close
Note the AsyncTask<String, Void, String>, here first String is the parameter to doInBackground , Void is parameter to onProgressUpdate(), we are not implementing this method, second String is parameter to onPostExecute()
Now, from MainActivity when you call new InnerClass().execute(urltoxml); Android will automatically call doInBackground() and will pass urltoxml as the argument`
Do all your network stuff inside doInbackground, when finished, doInBackground will return a result string and android will pass that as the parameter to onPostExecute().
Use that string however you want from onPostExecute
public class MainActivity extends Activity implements OnClickListener{
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button button = (Button)findViewById(R.id.button1);
button.setOnClickListener( new OnClickListener(){
#Override
public void onClick(View v){
new InnerClass().execute(urltoxml);
}
});
}
public class InnerClass extends AsyncTask<String, Void, String>{
#Override
protected String doInBackground(String... arg0) {
String returnVal;
//process your xml here
//store the result in returnVal;
return returnVal;
}
#Override
protected void onPostExecute(String result) {
//do something with the data
}
}
}
You are running Network Request on main UI thread.
Android >=3.0 does not allow to run Network Request on main UI thread. You need to use
AsyncTask to do network operation.

Call web service in android 4.1

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

Parse CDATA with XMLParser in this specific case for ANDROID

I've seen quite a few posts about this, but actually I did not get any to work. I am building a simple TV guide android application. I simply Use RSS from a tvprofil.net to show whats on TV today. The problem is, I do not know how to Parse CDATA in XML. I am using some standard parser with DOM... at least I think so..
This is a bit of XML:
.
.
.
<item>
<title>RTS1 14.08.2012</title>
<pubDate>Tue, 14 Aug 2012 06:00:00</pubDate>
<content:encoded><![CDATA[06:00 Vesti<br>06:05 Jutarnji program<br>08:00 Dnevnik
<br>8:15 Jutarnji Program<br>09:00 Vesti ... ]]></content:encoded>
</item>
.
.
.
now, this is my main app:
public class Main extends ListActivity {
// All static variables
static final String URL = "http://tvprofil.net/rss/feed/channel-group-2.xml";
// XML node keys
static final String KEY_ITEM = "item"; // parent node
static final String KEY_NAME = "title";
static final String KEY_DATE = "pubDate";
static final String KEY_DESC = "content:encoded";
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ArrayList<HashMap<String,String>> menuItems = new ArrayList<HashMap<String,String>>();
XMLParser parser = new XMLParser();
String xml = parser.getXmlFromUrl(URL); //get XML
Document doc = parser.getDomElement(xml); // get DOM elem.
NodeList nl = doc.getElementsByTagName(KEY_ITEM);
//loop
for (int i=0; i< nl.getLength(); i++){
HashMap<String, String> map = new HashMap<String, String>();
Element e = (Element) nl.item(i);
//add to map
map.put(KEY_NAME, parser.getValue(e, KEY_NAME));
map.put(KEY_DATE, parser.getValue(e, KEY_DATE));
map.put(KEY_DESC, parser.getValue(e, KEY_DESC));
// hash => list
menuItems.add(map);
}
ListAdapter adapter = new SimpleAdapter(this, menuItems, R.layout.list_item,
new String[]{KEY_NAME, KEY_DESC, KEY_DATE}, new int[]{
R.id.name, R.id.description, R.id.date
});
setListAdapter(adapter);
//singleView
ListView lv = getListView();
lv.setOnItemClickListener(new OnItemClickListener(){
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id){
String name = ((TextView)view.findViewById(R.id.name)).getText().toString();
String date = ((TextView)view.findViewById(R.id.date)).getText().toString();
String description = ((TextView)view.findViewById(R.id.description)).getText().toString();
//intent
Intent in = new Intent(getApplicationContext(), SingleMenuItemActivity.class);
in.putExtra(KEY_NAME, name);
in.putExtra(KEY_DATE, date);
in.putExtra(KEY_DESC, description);
startActivity(in);
}
});
}
}
and the parser class:
public class XMLParser {
// constructor
public XMLParser() {
}
/**
* Getting XML from URL making HTTP request
* #param url string
* */
public String getXmlFromUrl(String url) {
String xml = null;
try {
// defaultHttpClient
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
return xml;
}
/**
* Getting XML DOM element
* #param XML string
* */
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;
}
/** Getting node value
* #param elem element
*/
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 "";
}
/**
* Getting node value
* #param Element node
* #param key string
* */
public String getValue(Element item, String str) {
NodeList n = item.getElementsByTagName(str);
return this.getElementValue(n.item(0));
}
}
there is one more class for Single menu item.. but I think it's irrelevant in this case.
Now, I'd just like to see no HTML tags after parsing it and dealing with CDATA...
Anyone got idea about this one?
Add this
dbf.setCoalescing(true);
where dbf is
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
First add this method
public String getCharacterDataFromElement(Element e, String str) {
NodeList n = e.getElementsByTagName(str);
Element e1=(Element) n.item(0);
Node child = e1.getFirstChild();
if (child instanceof CharacterData) {
CharacterData cd = (CharacterData) child;
return cd.getData();
}
return "";
}
Call the above method as so-
map.put(KEY_DESC, parser.getCharacterDataFromElement(e, KEY_DESC));
This should get you the CDATA in String format. HOpe this helps
getTextContent.
This attribute returns the text content of this node and its
descendants
getNodeValue()
The value of this node, depending on its type;
usually you shouled use getTextContent.
zg_spring's answer worked perfectly for me when I needed to extract image URLs from CDATA in a set of "description" xml elements:
//Get the content of all "item" elements
DocumentBuilder db = DocumentBuilderFactory.newInstance().newDocumentBuilder();
Document doc = db.parse(new InputSource(new StringReader(xml)));
NodeList nlDetails = doc.getElementsByTagName("item");
//Loop through elements and extract content of "description" elements
for(int k = 0; k < numDetails; k++) {
Element nDetails = (Element)nlDetails.item(k);
NodeList nlCoverURL = nDetails.getElementsByTagName("description");
Node nCoverURL = nlCoverURL.item(0);
String sCoverURL = nCoverURL.getTextContent();
//Isolate the relevant part of the String and load it into an ArrayList
String[] descriptionContent = sCoverURL.split("\"");
String s = descriptionContent[11]
alImages.add(s);
}

Parsing an xml with AsyncTask using Http request

I am making a connection to the Internet using HTTP Request, parsing an XML
Everything works correctly, but I want to do is make the connection from a AsyncTask for new versions of android sdk.
Usually should not give problems, but I am following a tutorial and after trying many options and see similar threads on this website, I can not apply it correctly.
This is the code I'm using
Activity 1:
public class CustomizedListView extends Activity {
// All static variables
static final String URL = "http://api.androidhive.info/music/music.xml";
// XML node keys
static final String KEY_SONG = "song"; // parent node
static final String KEY_ID = "id";
static final String KEY_TITLE = "title";
static final String KEY_ARTIST = "artist";
static final String KEY_DURATION = "duration";
static final String KEY_THUMB_URL = "thumb_url";
private ArrayList<HashMap<String, String>> data;
ListView list;
LazyAdapter adapter;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
final ArrayList<HashMap<String, String>> songsList = new ArrayList<HashMap<String, String>>();
XMLParser parser = new XMLParser();
String xml = parser.getXmlFromUrl(URL); // getting XML from URL
Document doc = parser.getDomElement(xml); // getting DOM element
NodeList nl = doc.getElementsByTagName(KEY_SONG);
// looping through all song nodes <song>
for (int i = 0; i < nl.getLength(); i++) {
// creating new HashMap
HashMap<String, String> map = new HashMap<String, String>();
Element e = (Element) nl.item(i);
// adding each child node to HashMap key => value
map.put(KEY_ID, parser.getValue(e, KEY_ID));
map.put(KEY_TITLE, parser.getValue(e, KEY_TITLE));
map.put(KEY_ARTIST, parser.getValue(e, KEY_ARTIST));
map.put(KEY_DURATION, parser.getValue(e, KEY_DURATION));
map.put(KEY_THUMB_URL, parser.getValue(e, KEY_THUMB_URL));
// adding HashList to ArrayList
songsList.add(map);
}
list=(ListView)findViewById(R.id.list);
// Getting adapter by passing xml data ArrayList
adapter=new LazyAdapter(this, songsList);
list.setAdapter(adapter);
}
}
And this is the second activity:
public class XMLParser {
// constructor
public XMLParser() {
}
/**
* Getting XML from URL making HTTP request
* #param url string
* */
public String getXmlFromUrl(String url) {
String xml = null;
try {
// defaultHttpClient
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
return xml;
}
/**
* Getting XML DOM element
* #param XML string
* */
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;
}
/** Getting node value
* #param elem element
*/
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 "";
}
/**
* Getting node value
* #param Element node
* #param key string
* */
public String getValue(Element item, String str) {
NodeList n = item.getElementsByTagName(str);
return this.getElementValue(n.item(0));
}
}
...I understand that it must be encapsulated in a AsycTask is:
try {
// defaultHttpClient
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
return xml;
...But to be using strings of two activitys, I can not find a way to do
Thank you very much for the help
Regards
use this type of class as subclass in your activity:
private class YourDownload extends AsyncTask<Void, Void, Void> {
#Override
protected Void doInBackground(Void... params) {
/*
make connection & download XML here,
use your XML parser class object to parse the xml from here
create ArrayList & etc. from here...
*/
return null;
}
#Override
protected void onPostExecute(Void result) {
// postexecute logic
super.onPostExecute(result);
}
#Override
protected void onPreExecute() {
// pre execute logic
super.onPreExecute();
}
}
use YourDownload from onCreate() as new YourDownload().execute();
Probably this will help you..

Categories

Resources