I'm doing an App that scrapes a website an get some images, that works fine, I created an ThreadPoolExecutor and some callable but when I try to get the results from a Callable that I created I'm unnable to, it goes to the ExecutionException.
This is the Scraper Class:
public class ImageScraper implements Callable<String>{
Context context = null;
public Logo logoActivity;
Document[] doc = new Document[1];
List<ImageObject> imageList = new ArrayList<ImageObject>();
int pagAnterior;
String url;
int pag;
public ImageScraper(Logo act, String url, int pag, int pagAnterior) {
this.logoActivity = act;
this.url = url;
this.pag = pag;
this.pagAnterior = pagAnterior;
context = act.getApplication();
}
#Override
public String call() throws Exception {
getResponse(url,pag);
getImages(doc[0]);
Log.i("listaaa", "listaa : "+imageList.size());
String something = "got something";
return something;
}
public void getImages(Document docfinal) {
Log.i("Documento1", "documento1 : "+docfinal);
Elements entradas = docfinal.select("img[src]");
Elements titulo = doc[0].select("title");
String tituloPagina = titulo.text();
String urlImage = "";
if(!tituloPagina.toLowerCase().contains("page "+pagAnterior)) {
for (Element elem : entradas) {
if (elem.attr("abs:src").toLowerCase().contains("mfiles")) {
urlImage = elem.attr("abs:src").replace("thumb-", "");
Log.i("GridVerticalFragment", "Pillando url: " + urlImage);
ImageObject image = new ImageObject(urlImage);
Log.i("GridVerticalFragment", "Url Pillada: " + image.getUrl());
imageList.add(image);
}
}
}
Log.i("Logo", "Lista2: "+imageList.size());
}
public void getResponse(String urlRoot, int pagina) {
Log.i("GridVerticalLayaout", "Pagina: "+pagina);
String url;
String urlFinal = "";
if(pagina==0){
url = urlRoot;
urlFinal = url;
}else{
url = urlRoot.concat("?page="+Integer.toString(pagina));
urlFinal = url;
}
RequestQueue rq = Volley.newRequestQueue(context);
Log.i("GridVerticalLayaout", "fuuck: "+url);
Log.i("GridVerticalLayaout", "lool: "+urlFinal);
StringRequest stringRequest = new StringRequest(Request.Method.GET, urlFinal,
new Response.Listener<String>() {
#Override
public void onResponse(String response) {
// Do something with the response
doc[0] = Jsoup.parse(response);
getImages(doc[0]);
}
},
new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
// Handle error
Log.e("ERROR", "Error occurred ", error);
}
});
rq.add(stringRequest );
}
}
And this is the main class:
public class Logo extends AppCompatActivity {
public List<ImageObject> GlobalImageList = new ArrayList<ImageObject>() ;
Document[] doc = new Document[1];
String url;
int pagAnterior = 0;
int i = 0;
Context context = null;
public ThreadPoolExecutor executor;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_logo);
getSupportActionBar().hide();
Collection<Callable<String>> callableList = new ArrayList<>();
context = getApplication();
int NUMBER_OF_CORES = Runtime.getRuntime().availableProcessors();
executor = new ThreadPoolExecutor(
NUMBER_OF_CORES*2,
NUMBER_OF_CORES*2,
60L,
TimeUnit.SECONDS,
new LinkedBlockingQueue<Runnable>()
);
while(i<4){
callableList.add(new ImageScraper(this,"www.google.es,i,i-1););
i++;
}
List<Future<String>> result = null;
try {
result = executor.invokeAll(callableList);
} catch (InterruptedException e) {
Log.i("Fallo", "Fallo");
e.printStackTrace();
}
for (Future a : result) {
String SingleImageList = null;
try {
SingleImageList = (String) a.get();
Log.i("Single", "Single"+SingleImageList);
} catch (InterruptedException e) {
Log.i("Fallo3", "Fallo3");
e.printStackTrace();
} catch (ExecutionException e) {
Log.i("Fallo2", "Fallo2");
e.printStackTrace();
}
}
}
}
This doesn't return anything but the scraper do his job,( the getImages() and getResponse() do the job and updates the list , instead if in this part of the code in MainClass:
while(i<4){
callableList.add(new ImageScraper(this,"www.google.es,i,i-1););
i++;
}
If I change that for this( the class is not called the callable is created in the class), it works, the string is returned:
while(i<4){
callableList.add(new Callable<String>() {
public String call() throws Exception {
return "haha";
}
});
i++;
}
Someone can help me with this? I've been reading a lot and according to what I've read, what I have in the Scraper class is fine, but I still don't get it.
Sorry for the bad english, Im trying to :), I don't want to return an string I want to return an ArrayList, im returning a string in the code because thought it was a problem for returning ArrayList, but it seems like that is not that, and again, Thanks!
Please check this line of code
while(i<4){
callableList.add(new ImageScraper(this,"www.google.es,i,i-1););
i++;
}
You are not closing the double quotes!
Instead, try this code
while(i<4){
callableList.add(new ImageScraper(this,"www.google.es",i,i-1););
i++;
}
Related
I am adding String returned by Callback method from Volley's onRespond method.
I have already initialized GetterAndSetter Method inside OnCreate Method.
this is my code:
onRespond(){
...
AddtoList(CreateURL, new VolleyCallback() {
#Override
public void onSuccess(String result) {
getterAndSetter.addString(result);
}
});
....
}
My GetterAndSetter Class:
public class GetterAndSetter {
ArrayList<String> strings = new ArrayList<>();
public void addString(String string) {
this.strings.add(string);
}
public ArrayList<String> getList(){
return this.strings;
}
}
I tries to get all the strings added inside of this getterandsetter's ArrayList via following code inside my another method :
void LoadImages(MainActivity mainActivity){
...
List<String> details = getterAndSetter.getList();
Log.d("gs", getterAndSetter.getList().toString());
...
}
As seen above, I tried to print log, but it print "[]"(Empty String). I have seen alot of Answers on Stackoverflow, but can't solve my problem.
Update : I am adding more code so that you guys can understand the problem.
My OnCreate Method :
#Override
protected void onCreate(Bundle savedInstanceState) {
...
getterAndSetter = new GetterAndSetter();
LoadImages(this);
}
LoadImages :
private void LoadImages(MainActivity mainActivity) {
StringRequest stringRequest = new StringRequest(URL, new Response.Listener<String>() {
#Override
public void onResponse(String response) {
mView.dismiss();
Log.d("Respone", "onResponse: " + response);
// Used to Get List of Images URLs
getResponse = ParseJSON(response);
List<String> urlList = getResponse.get(0);
List<String> titles = getResponse.get(1);
List<String> details = getterAndSetter.getList();
Log.d("gs", getterAndSetter.getList().toString());
for (String urls : urlList) {
Log.d("urls", urls);
}
for (String title : titles) {
Log.d("tts", title);
}
for (String dt : details) {
Log.d("dts", dt);
}
}
}, error -> {
Log.d(TAG, "onErrorResponse: Error Occured...");
});
RequestQueue requestQueue = Volley.newRequestQueue(this);
requestQueue.add(stringRequest);
}
ParseJSON method :
ArrayList<ArrayList<String>> ParseJSON(String URL) {
try {
JSONObject root = new JSONObject(URL);
JSONObject photos = root.getJSONObject("photos");
JSONArray photo = photos.getJSONArray("photo");
ArrayList<String> listURLS = new ArrayList<>();
ArrayList<String> Titles = new ArrayList<>();
ArrayList<ArrayList<String>> result = new ArrayList<>();
for (int i = 0; i < photo.length(); i++) {
JSONObject photosJSONObject = photo.getJSONObject(i);
String FarmID = photosJSONObject.getString("farm");
String ServerID = photosJSONObject.getString("server");
String ID = photosJSONObject.getString("id");
String SecretID = photosJSONObject.getString("secret");
String ImageTitle = photosJSONObject.getString("title");
listURLS.add(i, CreatePhotoURL(FarmID, ServerID, ID, SecretID));
Titles.add(i, ImageTitle);
String CreateURL = "https://api.flickr.com/services/rest/?method=flickr.photos.getInfo&api_key=" + API_Key + "&photo_id=" + ID + "&format=json&nojsoncallback=1";
AddtoList(CreateURL, new VolleyCallback() {
#Override
public void onSuccess(String result) {
getterAndSetter.addString(result);
}
});
result.add(listURLS);
result.add(Titles);
}
return result;
} catch (JSONException e) {
e.printStackTrace();
}
return null;
}
AddtoList Method :
public void AddtoList(String CreateURL, VolleyCallback volleyCallback) {
RequestQueue requestQueue = Volley.newRequestQueue(this);
StringRequest stringRequest = new StringRequest(CreateURL, new Response.Listener<String>() {
#Override
public void onResponse(String response) {
JSONObject root;
try {
root = new JSONObject(response);
JSONObject photo = root.getJSONObject("photo");
String username = photo.getJSONObject("owner").getString("username");
String DateTaken = photo.getJSONObject("dates").getString("taken");
String Views = photo.getString("views");
String str = "Date Taken : " + DateTaken + "\n" + "Views : " + Views + "\n" + "User Name : " + username + "\n";
volleyCallback.onSuccess(str);
} catch (JSONException e) {
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Log.d(TAG, "onErrorResponse: " + error.toString());
}
});
requestQueue.add(stringRequest);
}
My CallBack
public interface VolleyCallback {
void onSuccess(String result);
}
The problem is that you're trying to print the list BEFORE the callback is being invoked by Volley.
You parse a Json and for each element, you make a new request. After parsing the Json you print the list, it's empty because of the calls you make aren't ended at the moment you print the list.
You need to wait until all the request you start from inside the loop have ended.
This is likely a basic Java question. All in same activity, I declare a String[] data, later update it succesfully, but when I attempt to set a textview to the updated data[1] from the calling funtion that updated data[1] - nothing showing. Here is the stripped down code.
public class MyClass extends AppCompatActivity {
String[] data = new String[4];
public void populateGrid() {}
getIndexData(indices);
final TextView test = (TextView) findViewById(R.id.textView0B);
test.post(new Runnable() {
#Override
public void run() {
test.setText(data[1]);
}
});
public void getIndexData(final String[] indices){
//lots of work accomplished, data[1] is updated, Log.d() logs good!
// Tried passing data[] as a parameter from populateGrid(), but that didn't work.
// Tried returning data[] to populateGrid(), also didn't work.
}
}
What is the proper method for accomplishing this task?
As requested, getIndexData()
public void getIndexData(final String indices){
mOkHttpClient = new OkHttpClient();
HttpUrl reqUrl = HttpUrl.parse("http://www.alphavantage.co/query?function=TIME_SERIES_DAILY&symbol=" +
indices +
"&outputsize=compact&apikey=" +
apiKey);
Request request = new Request.Builder().url(reqUrl).build();
mOkHttpClient.newCall(request).enqueue(new Callback() {
#Override
public void onFailure(Call call, IOException e) {
// Show user error message if not connected to internet, et. al.
runOnUiThread(new Runnable() {
#Override
public void run() {
Context context = getApplicationContext();
CharSequence text = getResources().getString(R.string.Toast_1);
int duration = Toast.LENGTH_LONG;
Toast toast = Toast.makeText(context, text, duration);
toast.show();
}
});
}
#Override
public void onResponse(Call call, Response response) throws IOException {
int j = 0;
String responseBody = response.body().string();
if (responseBody.contains("\"Error Message\"")) {
data[j] = "No Data";
data[j+1] = "No Data";
data[j+2] = "No Data";
data[j+3] = "No Data";
} else { // Extract data points from json object.
try {
JSONObject baseObject = new JSONObject(responseBody);
JSONObject timeSeriesObj = baseObject.optJSONObject("Time Series (Daily)");
Iterator<String> iterator = timeSeriesObj.keys();
List<Map<String, String>> tickerData = new ArrayList<Map<String, String>>();
while (iterator.hasNext()) {
String key = iterator.next();
if (key != null) {
HashMap<String, String> m = new HashMap<String, String>();
JSONObject finalObj = timeSeriesObj.optJSONObject(key);
m.put("1. open", finalObj.optString("1. open"));
m.put("2. high", finalObj.optString("2. high"));
m.put("3. low", finalObj.optString("3. low"));
m.put("4. close", finalObj.optString("4. close"));
m.put("5. volume", finalObj.optString("5. volume"));
tickerData.add(m);
}
}
int k = 0;
String str = tickerData.get(0).toString();
data[k] = StringUtils.substringBetween(str, "open=", ", ");
//Log.d("data[0]= ", data[0]);
data[k+1] = StringUtils.substringBetween(str, "close=", ", ");
Log.d("data[1]", data[1]); // logs 2431.7700
data[k+2] = "";
data[k+3] = "";
} catch (JSONException e) {
e.printStackTrace();
}
}
}
});
}
It would be something like this:
public class MyClass extends AppCompatActivity {
String[] data = new String[4];
public void populateGrid() {
getIndexData(indices);
}
public void getIndexData(final String indices) {
// set up http request
mOkHttpClient.newCall(request).enqueue(new Callback() {
#Override
public void onFailure(Call call, IOException e) {
// ...
}
#Override
public void onResponse(Call call, Response response) throws IOException {
// process the response, populate data etc.
final TextView test = (TextView) findViewById(R.id.textView0B);
test.post(new Runnable() {
#Override
public void run() {
test.setText(data[1]);
}
});
}
}
}
}
I have created a restful web service using this tutorial http://www.tutecentral.com/restful-api-for-android-part-1/ after running this i got an auto generated java file which contains the following code.
public class RestAPI {
private final String urlString = "http://125.0.0.174/Handler1.ashx";
private static String convertStreamToUTF8String(InputStream stream) throws IOException {
String result = "";
StringBuilder sb = new StringBuilder();
try {
InputStreamReader reader = new InputStreamReader(stream, "UTF-8");
char[] buffer = new char[4096];
int readedChars = 0;
while (readedChars != -1) {
readedChars = reader.read(buffer);
if (readedChars > 0)
sb.append(buffer, 0, readedChars);
}
result = sb.toString();
} catch (UnsupportedEncodingException e){
e.printStackTrace();
}
return result;
}
private String load(String contents) throws IOException {
URL url = new URL(urlString);
HttpURLConnection conn = (HttpURLConnection)url.openConnection();
conn.setRequestMethod("POST");
conn.setConnectTimeout(60000);
Log.e("load r2","load r2");
conn.setDoOutput(true);
conn.setDoInput(true);
OutputStreamWriter w = new OutputStreamWriter(conn.getOutputStream());
w.write(contents);
w.flush();
InputStream istream = conn.getInputStream();
String result = convertStreamToUTF8String(istream);
return result;
}
private Object mapObject(Object o) {
Object finalValue = null;
if (o.getClass() == String.class) {
finalValue = o;
}
else if (Number.class.isInstance(o)) {
finalValue = String.valueOf(o);
} else if (Date.class.isInstance(o)) {
SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yyyy hh:mm:ss", new Locale("en", "USA"));
finalValue = sdf.format((Date)o);
}
else if (Collection.class.isInstance(o)) {
Collection<?> col = (Collection<?>) o;
JSONArray jarray = new JSONArray();
for (Object item : col) {
jarray.put(mapObject(item));
}
finalValue = jarray;
} else {
Map<String, Object> map = new HashMap<String, Object>();
Method[] methods = o.getClass().getMethods();
for (Method method : methods) {
if (method.getDeclaringClass() == o.getClass()
&& method.getModifiers() == Modifier.PUBLIC
&& method.getName().startsWith("get")) {
String key = method.getName().substring(3);
try {
Object obj = method.invoke(o, null);
Object value = mapObject(obj);
map.put(key, value);
finalValue = new JSONObject(map);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
return finalValue;
}
public JSONObject GetDoctors(String Terr_Code) throws Exception {
JSONObject result = null;
JSONObject o = new JSONObject();
JSONObject p = new JSONObject();
o.put("interface","RestAPI");
o.put("method", "GetDoctors");
p.put("Terr_Code",mapObject(Terr_Code));
o.put("parameters", p);
String s = o.toString();
String r = load(s);
result = new JSONObject(r);
return result;
}
public JSONObject GetUserDetail(String IMEINO) throws Exception {
JSONObject result = null;
JSONObject o = new JSONObject();
JSONObject p = new JSONObject();
o.put("interface","RestAPI");
o.put("method", "GetUserDetail");
p.put("IMEINO",mapObject(IMEINO));
o.put("parameters", p);
String s = o.toString();
String r = load(s);
result = new JSONObject(r);
return result;
}
}
I'm calling this class in async task and everything is working good but I want to use it through volley as async task is slow.
this class has only one url I don't understand how to call this url for individual methods I tried the below code but I'm getting bad url exception. Please show me how access the methods of rest api with separate urls.
public void requestJSON() {
String tag_json_obj = "json_obj_req";
final ProgressDialog pDialog = new ProgressDialog(context);
pDialog.setMessage("Loading...");
pDialog.show();
JsonObjectRequest jsonObjReq = new JsonObjectRequest(Method.GET, null,
null, new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
try {
RestAPI restAPI = new RestAPI();
response = restAPI.GetDoctors(terrcode);
}
catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
display.setText(response.toString());
pDialog.hide();
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
display.setText(error.toString());
pDialog.hide();
}
});
// Adding request to request queue
VolleySingleton.getInstance().addToRequestQueue(jsonObjReq,
tag_json_obj);
}
Use Volley as VolleyService :
public class VolleyService {
private static VolleyService instance;
private RequestQueue requestQueue;
private ImageLoader imageLoader;
private VolleyService(Context context) {
requestQueue = Volley.newRequestQueue(context);
imageLoader = new ImageLoader(requestQueue, new ImageLoader.ImageCache() {
private final LruCache<String, Bitmap> cache = new LruCache<String, Bitmap>(20);
#Override
public Bitmap getBitmap(String url) {
return cache.get(url);
}
#Override
public void putBitmap(String url, Bitmap bitmap) {
cache.put(url,bitmap);
}
});
}
public static VolleyService getInstance(Context context) {
if (instance == null) {
synchronized(VolleyService.class) {
if (instance == null) {
instance = new VolleyService(context);
}
}
}
return instance;
}
public RequestQueue getRequestQueue() {
return requestQueue;
}
public ImageLoader getImageLoader() {
return imageLoader;
}
}
Then use your VolleyService in Activity or Fragment as this :
RequestQueue queue = VolleyService.getInstance(this.getContext()).getRequestQueue();
StringRequest request = new StringRequest(url, new Response.Listener<String>() {
#Override
public void onResponse(String response) {
// we got the response, now our job is to handle it
try {
//Here you parse your JSON - best approach is to use GSON for deserialization
getJsonFromResponse(response);
} catch (RemoteException | OperationApplicationException e) {
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
//something happened, treat the error.
Log.e("Error", error.toString());
}
});
queue.add(request);
I have an android app with widget which should parse some rss and get some data.
Here is my onReceive method:
#Override
public void onReceive(Context context, Intent intent) {
super.onReceive(context,intent);
if (intent.getAction().equals(ACTION_TOAST)) {
new RetrieveTask().execute(context);
}
}
And async method itself:
class RetrieveTask extends AsyncTask<Context,Void, List<String>> {
private Exception exception;
private Context context;
private RemoteViews views;
#Override
protected List<String> doInBackground(Context... params) {
List<String> output = new ArrayList<String>();
try {
int k = 15;
doc = Jsoup.connect("http://vlg-media.ru/transport").get();
String img = "";
int i = 0;
Title = doc.select(".art_img");
for (Element titles : Title) {
String IMG = URL;
String HREF;
//Element Img = titles.select(".art_image").first();
IMG = "http://vlg-media.ru" + titles.select("img").attr("src").toString();
IMG = IMG.replace("small", "medium");
HREF = "http://vlg-media.ru" + titles.select("a").attr("href").toString();
// Element Title = titles.select(".con_titlelink").first();
String title = titles.select("img").attr("alt").toString();
m = new HashMap<String, Object>();
m.put(ATTRIBUTE_NAME_TITLE, title);
//добавление данных в наш контейнер
data.add(m);
publishProgress();
i++;
//}
if (i == k)
break;
}
//}
} catch (Exception ex) {
this.exception = ex;
return null;
}
return output;
}
protected void onPostExecute(List<String> output) {
//to make sure it run
Toast.makeText(context,"Done",Toast.LENGTH_LONG).show();
}
}
After doInBackground happens nothing. onPostExecute never run.
I just need to run async parser in my AppWidgetProvider. Don't know where is the problem.
you never assign the Context object. In your case is just
context = params[0];
as first line of doInBackground
I'm learning about HTML and parsing data with XML DOM. For this, I've created an App that reads the Wheater from Yahoo's wheater API.
When executing the app, shows an error in the logcat that says: java.lang.RuntimeException: Can't create handler inside thread that has not caller Looper.prepare().
I don't know what this means, or if the code is right.
This is the link to the XML file of Yahoo's wheater API:
http://weather.yahooapis.com/forecastrss?w=766273&u=c
And this is my code:
public class WeatherActivity extends Activity {
private static final String WEATHER_URL = "http://weather.yahooapis.com/forecastjson?w=";
private static final String MADRID_CODE = "766273";
private static final String LOCATION_NAME = "location";
private static final String CITY_NAME = "city";
private static final String CONDITION_NAME = "condition";
private static final String TEMPERATURE_NAME = "temperature";
private static final String FORECAST_NAME = "forecast";
private static final String DAY_NAME = "day";
private static final String HIGH_TEMPERATURE_NAME = "high_temperature";
private static final String LOW_TEMPERATURE_NAME = "low_temperature";
private static final String TODAY = "Today";
private static final String TOMORROW = "Tomorrow";
private Button mButton;
private TextView mCity;
private TextView mToday;
private TextView mTomorrow;
private class WeatherInfo {
String city;
int temperatureNow;
int lowTemperature;
int highTemperature;
int lowTemperatureTomorrow;
int highTemperatureTomorrow;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mCity = (TextView) findViewById(R.id.city);
mToday = (TextView) findViewById(R.id.today);
mTomorrow = (TextView) findViewById(R.id.tomorrow);
mButton = (Button) findViewById(R.id.button);
mButton.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
launch();
}
});
}
private void launch(){
try {
new WeatherAsyncTask().execute(MADRID_CODE);
} catch (IllegalArgumentException e) {
e.printStackTrace();
Toast.makeText(WeatherActivity.this, e.getMessage(), Toast.LENGTH_SHORT).show();
}
}
private class WeatherAsyncTask extends AsyncTask<String, Void, WeatherInfo>{
#Override
protected WeatherInfo doInBackground(String... params) {
String code = params[0];
if (TextUtils.isEmpty(code))
throw new IllegalArgumentException("Code cannot be empty");
URL url = null;
HttpURLConnection connection = null;
try {
url = new URL(WEATHER_URL + code);
connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
InputStream is = connection.getInputStream();
WeatherInfo info = readWeatherInfo(is);
return info;
} catch (IOException e) {
e.printStackTrace();
Toast.makeText(WeatherActivity.this, e.getMessage(), Toast.LENGTH_SHORT).show();
} finally {
if (connection != null)
connection.disconnect();
}
return null;
}
#Override
protected void onPostExecute(WeatherInfo result) {
super.onPostExecute(result);
showResult(result);
}
private WeatherInfo readWeatherInfo(InputStream is){
if (is == null)
return null;
WeatherInfo info = new WeatherInfo();
try {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document dom = builder.parse(is);
Element root = dom.getDocumentElement();
NodeList items = root.getElementsByTagName("item");
for (int i=0; i<items.getLength(); i++) {
Node item = items.item(i);
NodeList datos = item.getChildNodes();
for (int j=0; j<datos.getLength(); j++) {
Node dato = datos.item(j);
String etiqueta = dato.getNodeName();
if (etiqueta.equals(LOCATION_NAME)) {
String texto = obtenerTexto(dato);
if (texto.equals(TEMPERATURE_NAME)) {
info.city = texto;
}
}
else if (etiqueta.equals(CONDITION_NAME)) {
String texto = obtenerTexto(dato);
if (texto.equals(CITY_NAME)) {
info.temperatureNow = Integer.parseInt(texto);
}
}
else if (etiqueta.equals(FORECAST_NAME)) {
String texto = obtenerTexto(dato);
String day = null;
int high = -111;
int low = -111;
if (texto.equals(DAY_NAME)){
day = texto;
} else if (texto.equals(HIGH_TEMPERATURE_NAME)){
high = Integer.parseInt(texto);
} else if (texto.equals(LOW_TEMPERATURE_NAME)){
low = Integer.parseInt(texto);
}
if (day.equals(TODAY)){
info.highTemperature = high;
info.lowTemperature = low;
} else if (day.equals(TOMORROW)){
info.highTemperatureTomorrow = high;
info.lowTemperatureTomorrow = low;
}
}
}
}
}
catch (Exception ex)
{
throw new RuntimeException(ex);
}
return info;
}
private String obtenerTexto(Node dato) {
StringBuilder texto = new StringBuilder();
NodeList fragmentos = dato.getChildNodes();
for (int k=0;k<fragmentos.getLength();k++) {
texto.append(fragmentos.item(k).getNodeValue());
}
return texto.toString();
}
}
private void showResult(WeatherInfo info){
mCity.setText("Temperature in " + info.city);
mToday.setText("Today: " + info.temperatureNow + " F (min: " + info.lowTemperature + " F / max: " + info.highTemperature + " F).");
mTomorrow.setText("Tomorrow: min: " + info.lowTemperatureTomorrow + " F / max: " + info.highTemperatureTomorrow + " F.");
}
}
You cannot show a Toast in the doInBackground of an ASyncTask
Try wrapping it in a runOnUIThread() like:
runOnUiThread(new Runnable() {
#Override
public void run() {
Toast.makeText(WeatherActivity.this, e.getMessage(), Toast.LENGTH_SHORT).show();
}
});
You can use preimplemented method onProgressUpdate() of AsyncTask which allows you to post Toasts. To do this, you have to change your AsyncTask declaration into
private class WeatherAsyncTask extends AsyncTask<String, String, WeatherInfo>
and add method
#Override
protected void onProgressUpdate(String... values)
{
super.onProgressUpdate(values);
Toast.makeText(WeatherActivity.this, values[0], Toast.LENGTH_SHORT).show();
}
and inside your AsyncTask you can catch your exception and do this
catch (IOException e)
{
e.printStackTrace();
publishProgress(e.getMessage());
}
All this is available by default in AsyncTask without the need of creating new runnables.