I have two tabs hosted in my Main Activity (I use ActionBarSherlock).
My fragments load and parse a distant xml to populate the listview.
If I change the device orientation when fragment is fully loaded, it loads again without problem with the new orientation.
But if I change it while the fragment is loading, the app force closes at the completion of loading.
Am I doing something wrong?
public class PartOne extends SherlockListFragment{
// All static variables
static final String URL = "http://Y.xml";
// XML node keys
static final String KEY_ITEM = "item"; // parent node
static final String KEY_TITLE = "title";
static final String KEY_CAT = "category";
static final String KEY_DESC = "description";
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
new BackgroundAsyncTask().execute();
}
public class BackgroundAsyncTask extends AsyncTask<String, String, ArrayList<HashMap<String, String>>> {
#Override
protected void onPreExecute() {
}
#Override
protected ArrayList<HashMap<String, String>> doInBackground(String... paths) {
ArrayList<HashMap<String, String>> menuItems = new ArrayList<HashMap<String, String>>();
XMLParser parser = new XMLParser();
String xml = parser.getXmlFromUrl(URL); // getting XML
if (xml != null) {
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++) {
if(i%2 != 1) {
// creating new HashMap
HashMap<String, String> map = new HashMap<String, String>();
Element e = (Element) nl.item(i);
// data to string (to modify them)
String titre = parser.getValue(e, KEY_TITLE);
String categorie = parser.getValue(e, KEY_CAT);
String description = parser.getValue(e, KEY_DESC);
// adding each child node to HashMap key => value
map.put(KEY_TITLE, titre);
map.put(KEY_CAT, categorie);
map.put(KEY_DESC, description);
// adding HashList to ArrayList
menuItems.add(map);
}
}
}
// 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.title)).getText().toString();
String cost = ((TextView) view.findViewById(R.id.categ)).getText().toString();
String description = ((TextView) view.findViewById(R.id.desciption)).getText().toString();
// Starting new intent
Intent in = new Intent(view.getContext(), SingleMenuItemActivity.class);
in.putExtra(KEY_TITLE, name);
in.putExtra(KEY_CAT, cost);
in.putExtra(KEY_DESC, description);
startActivity(in);
}
});
return menuItems;
}
protected void onPostExecute(ArrayList<HashMap<String, String>> result) {
ListAdapter adapter = new SimpleAdapter(getActivity(),
result, R.layout.list_item,
new String[] {KEY_TITLE, KEY_DESC, KEY_CAT},
new int[] {R.id.title, R.id.desciption, R.id.categ});
setListAdapter(adapter);
}
}
Log :
java.lang.RuntimeException: An error occured while executing doInBackground()
at android.os.AsyncTask$3.done(AsyncTask.java:278)
at java.util.concurrent.FutureTask$Sync.innerSetException(FutureTask.java:273)
at java.util.concurrent.FutureTask.setException(FutureTask.java:124)
at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:307)
at java.util.concurrent.FutureTask.run(FutureTask.java:137)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:208)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1076)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:569)
at java.lang.Thread.run(Thread.java:856)
Caused by: java.lang.IllegalStateException: Content view not yet created
at android.support.v4.app.ListFragment.ensureList(ListFragment.java:328)
at android.support.v4.app.ListFragment.getListView(ListFragment.java:222)
Handle your task in onConfigurationChanged (Configuration newConfig) mothod,
something like this
Thread th=null;
public void onCreate(bundle savedInstanceState)
{
//Initialize layout
if(th==null) //This is to check whether task is running
{
//Assign your task
th=new Thread();
th.start();
}
}
//handle the same here
public void onConfigurationChanged (Configuration newConfig)
{
//Do the layout changes
if(th==null)//This is to check whether task is running
{
//Assign your task
th=new Thread();
th.start();
}
}
Related
Hi I was viewing the details then when i hit the bottom right back button, to go back to the listview, I have the error "android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views."
but I don't know how to solve this:
public class Record extends ListActivity {
// Progress Dialog
private ProgressDialog pDialog;
// JSON parser class
JSONParser jsonParser = new JSONParser();
//testing on Emulator:
private static final String READ_SPECIFIC_RECORD_URL = "http://192.168.1.178:8888/searchdb/record.php";
//JSON IDS:
private static final String TAG_TITLE = "title";
private static final String TAG_POSTS = "posts";
private static final String TAG_ADDRESS = "address";
private static final String TAG_OPHOURS = "ophours";
private static final String TAG_CONTACT = "contact";
private static final String TAG_CONTACT2 = "contact2";
private static final String TAG_CAT = "cat";
private static final String TAG_BRAND = "brand";
private static final String TAG_COMPANY = "company";
private static final String TAG_RATINGS = "avgrating";
//An array of all of our comments
private JSONArray mComments = null;
//manages all of our comments in a list.
private ArrayList<HashMap<String, String>> mCommentList;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//note that use read_comments.xml instead of our single_post.xml
setContentView(R.layout.details);
}
#Override
protected void onResume() {
// TODO Auto-generated method stub
super.onResume();
//loading the comments via AsyncTask
new LoadRecordDetails().execute();
}
/**
* Retrieves json data of comments
*/
/**
* Retrieves recent post data from the server.
*/
public void updateJSONdata() {
// Instantiate the arraylist to contain all the JSON data.
// we are going to use a bunch of key-value pairs, referring
// to the json element name, and the content, for example,
// message it the tag, and "I'm awesome" as the content..
Bundle b = getIntent().getExtras();
String id = b.getString("key");
List<NameValuePair> params = new ArrayList<NameValuePair>();
params.add(new BasicNameValuePair("id", id));
Log.d("request!", "starting");
//Posting user data to script
JSONObject json = jsonParser.makeHttpRequest(
READ_SPECIFIC_RECORD_URL, "POST", params);
// full json response
Log.d("Search attempt", json.toString());
mCommentList = new ArrayList<HashMap<String, String>>();
//when parsing JSON stuff, we should probably
//try to catch any exceptions:
try {
mComments = json.getJSONArray(TAG_POSTS);
// looping through all posts according to the json object returned
for (int i = 0; i < mComments.length(); i++) {
JSONObject c = mComments.getJSONObject(i);
//gets the content of each tag
String title = c.getString(TAG_TITLE);
String address = c.getString(TAG_ADDRESS);
String ophours = c.getString(TAG_OPHOURS);
String contact = c.getString(TAG_CONTACT);
String contact2 = c.getString(TAG_CONTACT2);
String cat = c.getString(TAG_CAT);
String brand = c.getString(TAG_BRAND);
String company = c.getString(TAG_COMPANY);
String avgrating = c.getString(TAG_RATINGS);
// creating new HashMap
HashMap<String, String> map = new HashMap<String, String>();
map.put(TAG_TITLE, title);
map.put(TAG_ADDRESS, address);
map.put(TAG_OPHOURS, ophours);
map.put(TAG_CONTACT, contact);
map.put(TAG_CONTACT2, contact2);
map.put(TAG_CAT, cat);
map.put(TAG_BRAND, brand);
map.put(TAG_COMPANY, company);
map.put(TAG_RATINGS, avgrating);
// adding HashList to ArrayList
mCommentList.add(map);
//annndddd, our JSON data is up to date same with our array list
}
} catch (JSONException e) {
e.printStackTrace();
}
}
/**
* Inserts the parsed data into our listview
*/
private void updateList() {
// For a ListActivity we need to set the List Adapter, and in order to do
//that, we need to create a ListAdapter. This SimpleAdapter,
//will utilize our updated Hashmapped ArrayList,
//use our single_post xml template for each item in our list,
//and place the appropriate info from the list to the
//correct GUI id. Order is important here.
ListAdapter adapter = new SimpleAdapter(this, mCommentList,
R.layout.single_record, new String[] { TAG_TITLE, TAG_ADDRESS,
TAG_OPHOURS, TAG_CONTACT, TAG_CONTACT2, TAG_CAT, TAG_BRAND, TAG_COMPANY, TAG_RATINGS },
new int[] { R.id.outletname, R.id.outletaddress, R.id.outletophours, R.id.outletcontact,
R.id.outletcontact2, R.id.outletcat, R.id.outletbrand, R.id.outletcompany, R.id.ratings});
((SimpleAdapter) adapter).setViewBinder(new MyBinder());
setListAdapter(adapter);
//Showing empty view when ListView is empty
ListView listView = (ListView) findViewById(android.R.id.list);
listView.setEmptyView(findViewById(android.R.id.empty));
}
//ratingsbar
class MyBinder implements SimpleAdapter.ViewBinder {
public boolean setViewValue(View view, Object data, String textRepresentation) {
if(view.getId() == R.id.ratings){
String stringval = (String) data;
float ratingValue = Float.parseFloat(stringval);
RatingBar ratingBar = (RatingBar) view;
ratingBar.setRating(ratingValue);
return true;
}
return false;
}
}
//call
public class LoadRecordDetails extends AsyncTask<Void, Boolean, Boolean> {
#Override
protected void onPreExecute() {
super.onPreExecute();
pDialog = new ProgressDialog(Record.this);
pDialog.setMessage("Loading details...");
pDialog.setIndeterminate(false);
pDialog.setCancelable(false);
pDialog.show();
}
#Override
protected Boolean doInBackground(Void... arg0) {
updateJSONdata();
return null;
}
#Override
protected void onPostExecute(Boolean result) {
super.onPostExecute(result);
pDialog.dismiss();
updateList();
}
}
}
From logcat:
02-24 23:38:26.033 5653-5789/com.example.searchtest W/dalvikvm﹕ threadid=19: thread exiting with uncaught exception (group=0x4172ac08)
02-24 23:38:26.038 5653-5789/com.example.searchtest E/AndroidRuntime﹕ FATAL EXCEPTION: AsyncTask #4
Process: com.example.searchtest, PID: 5653
java.lang.RuntimeException: An error occured while executing doInBackground()
at android.os.AsyncTask$3.done(AsyncTask.java:300)
at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:355)
at java.util.concurrent.FutureTask.setException(FutureTask.java:222)
at java.util.concurrent.FutureTask.run(FutureTask.java:242)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:231)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
at java.lang.Thread.run(Thread.java:841)
Caused by: android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
at android.view.ViewRootImpl.checkThread(ViewRootImpl.java:7069)
at android.view.ViewRootImpl.invalidateChildInParent(ViewRootImpl.java:1108)
at android.view.ViewGroup.invalidateChild(ViewGroup.java:4542)
at android.view.View.invalidate(View.java:11795)
at android.view.View.invalidate(View.java:11736)
at android.widget.ImageView.invalidateDrawable(ImageView.java:211)
at android.graphics.drawable.Drawable.invalidateSelf(Drawable.java:393)
at android.graphics.drawable.Drawable.setVisible(Drawable.java:624)
at android.widget.ImageView.onDetachedFromWindow(ImageView.java:1265)
at android.view.View.dispatchDetachedFromWindow(View.java:13543)
at android.view.ViewGroup.dispatchDetachedFromWindow(ViewGroup.java:2800)
at android.view.ViewGroup.dispatchDetachedFromWindow(ViewGroup.java:2800)
at android.view.ViewGroup.dispatchDetachedFromWindow(ViewGroup.java:2800)
at android.view.ViewGroup.removeAllViewsInLayout(ViewGroup.java:4249)
at android.widget.AbsListView.resetList(AbsListView.java:2388)
at android.widget.ListView.resetList(ListView.java:527)
at android.widget.ListView.setAdapter(ListView.java:468)
at android.app.ListActivity.setListAdapter(ListActivity.java:265)
at com.example.searchtest.Results.updateList(Results.java:90)
at com.example.searchtest.Results.access$100(Results.java:23)
at com.example.searchtest.Results$LoadResults.doInBackground(Results.java:154)
at com.example.searchtest.Results$LoadResults.doInBackground(Results.java:138)
at android.os.AsyncTask$2.call(AsyncTask.java:288)
at java.util.concurrent.FutureTask.run(FutureTask.java:237)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:231)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
at java.lang.Thread.run(Thread.java:841)
Thanks!! :D
Log file tells this :
android.view.ViewRootImpl$CalledFromWrongThreadException:
Only the original thread that created a view hierarchy can touch its views.
This exeption means that you are trying to thouch view that's not in this thread.
Here is an explanation:
There is the thread call UI and in your code there is an another one called AsyncTask
and in this line : updateList(); you are calling the method that trying to thouch the view that is in UI thread,like this :
ListView listView = (ListView) findViewById(android.R.id.list);
So, for solving this issue just remove this line and put it in onCreate, so your code should look like this :
public class Record extends ListActivity {
.
.
.
ListView listView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//note that use read_comments.xml instead of our single_post.xml
setContentView(R.layout.details);
listView = (ListView) findViewById(android.R.id.list);
}
}
Is it possible to reload a ListView once the data is downloaded? Basically I'm updating an app for 4.1 but my ListView downloads and parses an XML file, I know that I have to run this now in a background thread but when I open the activity via a tab the screen is blank. I am not sure how to get this to work or what part of the code I need to use in the background thread, can someone please help. Thank you.
public class ThirdActivity extends ListActivity {
// All static variables
static final String URL = "http://selectukradio.com/SelectUKSchedule.xml"; // http://api.androidhive.info/pizza/?format=xml http://selectukradio.com/SelectUKSchedule.xml
// XML node keys
static final String KEY_ITEM = "day"; // parent node item
static final String KEY_ID = "link"; // id
static final String KEY_NAME = "dj"; // name
static final String KEY_COST = "time"; // cost
static final String KEY_DESC = "tempDay"; // description
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_3);
try{
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)); // "Rs. " +
map.put(KEY_DESC, parser.getValue(e, KEY_DESC));
// adding HashList to ArrayList
menuItems.add(map);
}
// Adding menuItems to ListView
ListAdapter adapter = new SimpleAdapter(ThirdActivity.this, menuItems,
R.layout.list_item,
new String[] { KEY_NAME, KEY_COST,KEY_DESC,KEY_ID }, new int[] {
R.id.name, R.id.cost, R.id.day, R.id.link });
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();
String link = ((TextView) view.findViewById(R.id.link)).getText().toString();
// Starting new intent
Intent in = new Intent(getApplicationContext(), SingleMenuItemActivity.class);
in.putExtra(KEY_NAME, name);
in.putExtra(KEY_COST, cost);
in.putExtra(KEY_ID, link);
startActivity(in);
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
#Override public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
Intent intent = new Intent();
intent.setAction(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_HOME);
startActivity(intent);
}
return super.onKeyDown(keyCode, event);
}
}
Nick's comment has upvotes but everyone is forgetting that notifyDataSetChanged() must be called on the adapter, not on the list view.
In this example you are using a SimpleAdapter which takes the list of items in the constructor. So to change the data wrapped by the adapter, you have to update this list and then call notifyDataSetChanged() on the adapter to get the list view to update.
Here's how you could rework the code to solve your problems. All I have done is move the XML download code to an AsyncTask, and moved the list adapter and data items to be instance variables so you can access them when async task completes.
Please note I haven't tested this code, but it should give you the right idea!
public class ThirdActivity extends ListActivity {
// All static variables
static final String URL = "http://selectukradio.com/SelectUKSchedule.xml"; // http://api.androidhive.info/pizza/?format=xml http://selectukradio.com/SelectUKSchedule.xml
// XML node keys
static final String KEY_ITEM = "day"; // parent node item
static final String KEY_ID = "link"; // id
static final String KEY_NAME = "dj"; // name
static final String KEY_COST = "time"; // cost
static final String KEY_DESC = "tempDay"; // description
// Initially set list of items to empty array
ArrayList<HashMap<String, String>> mMenuItems = new ArrayList<HashMap<String, String>>();
SimpleAdapter mAdapter;
UpdateTask mUpdateTask;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_3);
// Adding menuItems to ListView
mAdapter = new SimpleAdapter(ThirdActivity.this, mMenuItems,
R.layout.list_item,
new String[] { KEY_NAME, KEY_COST,KEY_DESC,KEY_ID },
new int[] { R.id.name, R.id.cost, R.id.day, R.id.link });
setListAdapter(mAdapter);
// 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();
String link = ((TextView) view.findViewById(R.id.link)).getText().toString();
// Starting new intent
Intent in = new Intent(getApplicationContext(), SingleMenuItemActivity.class);
in.putExtra(KEY_NAME, name);
in.putExtra(KEY_COST, cost);
in.putExtra(KEY_ID, link);
startActivity(in);
}
});
// Start an update
updateMenuItems();
}
#Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
Intent intent = new Intent();
intent.setAction(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_HOME);
startActivity(intent);
return true; // handled event
}
return super.onKeyDown(keyCode, event);
}
// Call this method to download latest XML file from network and update listview
private void updateMenuItems() {
if (mUpdateTask == null) {
mUpdateTask = new UpdateTask();
mUpdateTask.execute(URL);
}
}
// Async task to download XML on background thread
private class UpdateTask extends AsyncTask<String, Void, String> {
// This method runs on a background.
// Do network operation and returns XML parser, or null on exception
protected String doInBackground(String... url) {
try {
XMLParser parser = new XMLParser();
return parser.getXmlFromUrl(url[0]);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
// This method runs on the main thread when the async task completes.
// Make sure you only update your UI from this method!
protected void onPostExecute(String xml) {
if (xml == null) {
// Download failed, display error message or something
return;
}
XMLParser parser = new XMLParser();
Document doc = parser.getDomElement(xml); // getting DOM element
NodeList nl = doc.getElementsByTagName(KEY_ITEM);
// looping through all item nodes <item>
mMenuItems.clear();
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)); // "Rs. " +
map.put(KEY_DESC, parser.getValue(e, KEY_DESC));
// adding HashList to ArrayList
mMenuItems.add(map);
}
// all done, notify listview adapter to update
mAdapter.notifyDataSetChanged();
}
}
}
Here is the final class
public class ThirdActivity extends ListActivity {
// All static variables
static final String URL = "http://selectukradio.com/SelectUKSchedule.xml"; // http://api.androidhive.info/pizza/?format=xml http://selectukradio.com/SelectUKSchedule.xml
// XML node keys
static final String KEY_ITEM = "day"; // parent node item
static final String KEY_ID = "link"; // id
static final String KEY_NAME = "dj"; // name
static final String KEY_COST = "time"; // cost
static final String KEY_DESC = "tempDay"; // description
String xml = new String();
// Initially set list of items to empty array
ArrayList<HashMap<String, String>> mMenuItems = new ArrayList<HashMap<String, String>>();
SimpleAdapter mAdapter;
UpdateTask mUpdateTask;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_3);
// Adding menuItems to ListView
mAdapter = new SimpleAdapter(ThirdActivity.this, mMenuItems,
R.layout.list_item,
new String[] { KEY_NAME, KEY_COST,KEY_DESC,KEY_ID },
new int[] { R.id.name, R.id.cost, R.id.day, R.id.link });
setListAdapter(mAdapter);
// 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();
String link = ((TextView) view.findViewById(R.id.link)).getText().toString();
// Starting new intent
Intent in = new Intent(getApplicationContext(), SingleMenuItemActivity.class);
in.putExtra(KEY_NAME, name);
in.putExtra(KEY_COST, cost);
in.putExtra(KEY_ID, link);
startActivity(in);
}
});
// Start an update
updateMenuItems();
}
#Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
Intent intent = new Intent();
intent.setAction(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_HOME);
startActivity(intent);
return true; // handled event
}
return super.onKeyDown(keyCode, event);
}
// Call this method to download latest XML file from network and update listview
private void updateMenuItems() {
if (mUpdateTask == null) {
mUpdateTask = new UpdateTask();
mUpdateTask.execute(URL);
}
}
// Async task to download XML on background thread
private class UpdateTask extends AsyncTask<String, Void, XMLParser> {
// This method runs on a background.
// Do network operation and returns XML parser, or null on exception
protected XMLParser doInBackground(String... url) {
try {
XMLParser parser = new XMLParser();
xml = parser.getXmlFromUrl(url[0]);
// xml = parser.getXmlFromUrl(URL); // getting XML
return parser;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
// This method runs on the main thread when the async task completes.
// Make sure you only update your UI from this method!
protected void onPostExecute(XMLParser parser) {
if (parser == null) {
// Download failed, display error message or something
return;
}
// 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>
mMenuItems.clear();
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)); // "Rs. " +
map.put(KEY_DESC, parser.getValue(e, KEY_DESC));
// adding HashList to ArrayList
mMenuItems.add(map);
}
// all done, notify listview adapter to update
mAdapter.notifyDataSetChanged();
}
}
}
This question already has answers here:
How can I fix 'android.os.NetworkOnMainThreadException'?
(66 answers)
Closed 9 years ago.
Below is my code:
private static final String TAG_TYPE = "movie_type";
private static final String TAG_NAME = "movie_name";
private static final String TAG_LENGTH = "movie_length";
private static final String TAG_SCHEDULES = "movie_schedules";
private static final String TAG_CINEMA = "movie_cinema_number";
private static final String TAG_URL = "movie_image_url";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
try {
String readMovieSchedules = readMovieSchedules();
// Hashmap for ListView
ArrayList<HashMap<String, String>> movieList = new ArrayList<HashMap<String, String>>();
JSONArray jsonArray = new JSONArray(readMovieSchedules);
Log.i(MainActivity.class.getName(),
"Number of entries " + jsonArray.length());
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject jsonObject = jsonArray.getJSONObject(i);
Log.i(MainActivity.class.getName(), jsonObject.getString("movie_name"));
// Storing each json item in variable
String name = jsonObject.getString(TAG_NAME);
String type = jsonObject.getString(TAG_TYPE);
String length = jsonObject.getString(TAG_LENGTH);
String cinema = jsonObject.getString(TAG_CINEMA);
String schedules = jsonObject.getString(TAG_SCHEDULES);
String url = jsonObject.getString(TAG_URL);
// creating new HashMap
HashMap<String, String> map = new HashMap<String, String>();
// adding each child node to HashMap key => value
map.put(TAG_NAME, name);
map.put(TAG_TYPE, type);
map.put(TAG_LENGTH, length);
map.put(TAG_CINEMA, cinema);
map.put(TAG_SCHEDULES, schedules);
map.put(TAG_URL, url);
// adding HashList to ArrayList
movieList.add(map);
//String strURL = TAG_URL.replaceAll(" ", "%20");
/**
* Updating parsed JSON data into ListView
* */
ListAdapter adapter = new SimpleAdapter(MainActivity.this, movieList,
R.layout.list_item,
new String[] { TAG_NAME, TAG_CINEMA, TAG_SCHEDULES },
new int[] { R.id.name, R.id.cinema, R.id.schedules });
//new String[] {},
//new int[] {});
setListAdapter(adapter);
// selecting single ListView item
ListView lv = getListView();
// Launching new screen on Selecting Single ListItem
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.cinema)).getText().toString();
String description = ((TextView) view.findViewById(R.id.schedules)).getText().toString();
//String url = ((TextView) view.findViewById(R.id.image_)).getText().toString();
// Starting new intent
Intent in = new Intent(getApplicationContext(), SingleMenuItemActivity.class);
in.putExtra(TAG_NAME, name);
in.putExtra(TAG_CINEMA, cost);
in.putExtra(TAG_SCHEDULES, description);
//in.putExtra(TAG_URL, url);
startActivity(in);
}
});
}
} catch (Exception e) {
e.printStackTrace();
}
}
This code is working on SDK 8, but not working on 17. I'm stuck with this problem. Does anyone here know how to debug this? I'd gladly appreciate your help. thanks.
You can't make network calls on the main thread since API 11 (3.0). Read more here:
http://www.androiddesignpatterns.com/2012/06/app-force-close-honeycomb-ics.html
You have to put your code inside an AsyncTask , it is forbidden to download anything on the main UI thread since API 14 I believe.
It would be something like this:
public class someTask extends AsyncTask<String, Void, String> {
public MainActivity activity;
public someTask(MainActivity a)
{
activity = a;
}
#Override
protected String doInBackground(String... urls) {
String stringtoparse=null;
for (String url : urls) {
stringtoparse= readMovieSchedules(url); // getting XML from URL
}
return stringtoparse;
}
#Override
protected void onPreExecute(){
}
#Override
protected void onPostExecute(String readMovieSchedules) {
// Hashmap for ListView
ArrayList<HashMap<String, String>> movieList = new ArrayList<HashMap<String, String>>();
JSONArray jsonArray = new JSONArray(readMovieSchedules);
Log.i(MainActivity.class.getName(),
"Number of entries " + jsonArray.length());
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject jsonObject = jsonArray.getJSONObject(i);
Log.i(MainActivity.class.getName(), jsonObject.getString("movie_name"));
// Storing each json item in variable
String name = jsonObject.getString(TAG_NAME);
String type = jsonObject.getString(TAG_TYPE);
String length = jsonObject.getString(TAG_LENGTH);
String cinema = jsonObject.getString(TAG_CINEMA);
String schedules = jsonObject.getString(TAG_SCHEDULES);
String url = jsonObject.getString(TAG_URL);
// creating new HashMap
HashMap<String, String> map = new HashMap<String, String>();
// adding each child node to HashMap key => value
map.put(TAG_NAME, name);
map.put(TAG_TYPE, type);
map.put(TAG_LENGTH, length);
map.put(TAG_CINEMA, cinema);
map.put(TAG_SCHEDULES, schedules);
map.put(TAG_URL, url);
// adding HashList to ArrayList
movieList.add(map);
}
}
You have to modify the readMovieSchedules() to take the url as an argument like this readMovieSchedules(url) and I think it'll work just fine, you would call the task like this:
getMovieSched task = new someTask(MainActivity.this);
task.execute(url);
ASyncTask is specifically made for scenarios like this. It allows you to communicate over the network in a seperate thread without you needing to work with threads.
ASyncTask has these methods :
onPreExecute() : this is invoked before the main processing happens ... one use of it would be to start the progress dialog notifying the user of the transaction.
doInBackground() : this is where you perform data exchange from the network . no UI fiddling around here.
onProgressUpdate() : can be used to notify progress of the transaction
onPostExecute() : dismiss the progressDialogs/bars and update your views from the fetched data!
another solution would be to use runOnUiThread() but this is discouraged!
class nwthread extends AsyncTask<Void,Void,Void>
{
#Override
protected void onPreExecute() {
//progress dialog invoke ( notifies the user about whats going on better than making them stare on a blank screen)
super.onPreExecute();
}
#Override
protected Void doInBackground(Void... params) {
//make http request/parse json here
return null;
}
#Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
//dismiss progress dialog
// update the UI here ... ie declare adapters / bind them, update other views
}
}
finally invoke nwthread.execute(); after setContentView();
I have a listview which is inflated by custom array adapter and onclick takes it to another activity with the data related to that row .After clicking on delete its supposed to delete the item from the list and get back to the list.
I am using the code below for this :
int deleteposition=CustomizedListView.deleteposition;
CustomizedListView.list.removeViewAt(deleteposition);
CustomizedListView.adapter.notifyDataSetChanged();
finish();
But there is an error at this line :
CustomizedListView.list.removeViewAt(deleteposition);
Please Tell me how to fix it ?
Logcat Details:
java.lang.UnsupportedOperationException: removeViewAt(int) is not supported in AdapterView
at android.widget.AdapterView.removeViewAt(AdapterView.java:511)
at com.example.androidhive.openedmsg$1.onClick(openedmsg.java:35)
at android.view.View.performClick(View.java:3549)
at android.view.View$PerformClick.run(View.java:14393)
at android.os.Handler.handleCallback(Handler.java:605)
at android.os.Handler.dispatchMessage(Handler.java:92)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:4945)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)
at dalvik.system.NativeStart.main(Native Method)
The entire Code :
CustomizedListView.class
public class CustomizedListView extends Activity {
// All static variables
static final String URL = "https://itunes.apple.com/us/rss/topalbums/limit=20/json";
// 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";
static ListView list;
static LazyAdapter adapter;
HashMap<String, String> map;
public static String newactivityno;
public static int deleteposition;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
ArrayList<HashMap<String, String>> songsList = new ArrayList<HashMap<String, String>>();
JSONObject json = JSONfunctions.getJSONfromURL(URL);
try {
JSONObject arr2 = json.getJSONObject("feed");
JSONArray arr = arr2.getJSONArray("entry");
for (int i = 0; i < arr.length(); i++) {
JSONObject e1 = arr.getJSONObject(i);
JSONArray arr3 = e1.getJSONArray("im:image");
JSONObject arr8 = e1.getJSONObject("im:name");
JSONObject arr10 = e1.getJSONObject("im:artist");
JSONObject e12 = arr3.getJSONObject(0);
// creating new HashMap
map = new HashMap<String, String>();
map.put(KEY_THUMB_URL, e12.getString("label"));
map.put(KEY_ARTIST, arr8.getString("label"));
map.put(KEY_TITLE, arr10.getString("label"));
// adding HashList to ArrayList
songsList.add(map);
}
} catch (JSONException e) {
// Log.e("log_tag", "Error parsing data "+e.toString());
Toast.makeText(getBaseContext(),
"Network communication error!", 5).show();
}
list=(ListView)findViewById(R.id.list);
// Getting adapter by passing xml data ArrayList
adapter=new LazyAdapter(this, songsList);
list.setAdapter(adapter);
// Click event for single list row
list.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
#SuppressWarnings("unchecked")
HashMap<String, String> o= (HashMap<String, String>) list.getItemAtPosition(position);
// Toast.makeText(CustomizedListView.this, "ID '" + o.get("title") + "' was clicked.", Toast.LENGTH_SHORT).show();
deleteposition=position;
newactivityno= o.get("title");
Intent ii= new Intent(getBaseContext(),newactivity.class);
startActivity(ii);
}
});
}
}
newactivity.class
public class newactivity extends Activity{
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.newlayout);
TextView tv1=(TextView)findViewById(R.id.textView11);
TextView tv2=(TextView)findViewById(R.id.textView12);
Button bn=(Button)findViewById(R.id.button1);
tv2.setText(CustomizedListView.newactivityno);
bn.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
int deleteposition=CustomizedListView.deleteposition;
CustomizedListView.list.removeViewAt(deleteposition);
CustomizedListView.adapter.notifyDataSetChanged();
finish();
}
});
}
}
You are approaching this problem in the wrong manner. Rather than remove the View from the AdapterView, simply remove the data from the data set and call notifyDataSetChanged(). (This will remove the unwanted View automatically.)
I'm developing my first Android application and i want to show a progress dialog until a xml file is being processed in doInBackground method. This activity is loaded in response to an onclick event. Unexpectedly, activity takes several seconds to show up and the progress dialog is shown for a very little time (several milliseconds).
This is my code. I have used AsyncTask as an inner class. I just can't find where i have gone wrong.
public class WhatToSee extends ListActivity {
ListView whatToSee;
ArrayList<HashMap<String, String>> whatToSeeInfo = new ArrayList<HashMap<String, String>>();
WhatToSeeAdapter adapter;
String cityName;
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.whattosee);
cityName = getIntent().getStringExtra("name");
whatToSee = (ListView) findViewById(android.R.id.list);
adapter= new WhatToSeeAdapter(this, whatToSeeInfo);
whatToSee.setAdapter(adapter);
new WhatToSeeLoader().execute();
}
public class WhatToSeeLoader extends AsyncTask<Void, String, String> {
ProgressDialog progress = new ProgressDialog(WhatToSee.this);
String url = "http://wearedesigners.net/clients/clients12/tourism/fetchWhatToSeeList.php";
final String TAG_MAIN = "item";
final String TAG_ID = "itemId";
final String TAG_NAME = "itemName";
final String TAG_DETAIL = "itemDetailText";
final String TAG_MAP = "itemMapData";
final String TAG_ITEM_IMAGE = "itemImages";
final String TAG_MAP_IMAGE = "mapImage";
XMLParser parser = new XMLParser();
String xml = parser.getXmlFromUrl(url); // getting XML
Document doc = parser.getDomElement(xml); // getting DOM element
NodeList nl = doc.getElementsByTagName(TAG_MAIN);
#Override
protected void onPreExecute() {
// TODO Auto-generated method stub
super.onPreExecute();
progress.setMessage("Loading What To See List");
progress.setIndeterminate(true);
progress.show();
}
#Override
protected String doInBackground(Void... params) {
// TODO Auto-generated method stub
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(TAG_ID, parser.getValue(e, TAG_ID));
map.put(TAG_NAME, parser.getValue(e, TAG_NAME));
map.put(TAG_DETAIL, parser.getValue(e, TAG_DETAIL));
map.put(TAG_MAP, parser.getValue(e, TAG_MAP));
map.put(TAG_MAP_IMAGE, parser.getValue(e, TAG_MAP_IMAGE));
map.put(TAG_ITEM_IMAGE, parser.getValue(e, TAG_ITEM_IMAGE));
// adding HashList to ArrayList
whatToSeeInfo.add(map);
}
return null;
}
#Override
protected void onPostExecute(String result) {
// TODO Auto-generated method stub
super.onPostExecute(result);
adapter.notifyDataSetChanged();
progress.dismiss();
}
}
}
Can someone please help me with this?
Thank you in advance.
Most probably call String xml = parser.getXmlFromUrl(url); // getting XML slows down Your code. It get executed in main thread and I expect it (from its name) to do some network related staff which basically should be done not in UI thread (e.g. in Yours doInBackground method).
So, to fix try to move that initialization staff related to xml inside doInBackground().