com.fortysevendeg.lab.WeatherTask.java Source code

Java tutorial

Introduction

Here is the source code for com.fortysevendeg.lab.WeatherTask.java

Source

/*
 * Copyright (c) 2011 47 Degrees, LLC
 * http://47deg.com
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.fortysevendeg.lab;

import android.content.Context;
import android.os.AsyncTask;
import android.util.Log;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.StatusLine;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;

import javax.xml.xpath.*;
import java.io.*;
import java.net.URLEncoder;

/**
 * Fetches remote weather information given a place
 */
public class WeatherTask extends AsyncTask<String, Void, Integer> {

    /**
     * Default http client used for http requests to the remote weather service
     */
    private static final HttpClient HTTP_CLIENT = new DefaultHttpClient();

    /**
     * Flag utilized to determine if the temperature returned is valid
     */
    public static final int ERROR = Integer.MAX_VALUE;

    /**
     * The context utilized to load vars and config files
     */
    private Context context;

    /**
     * Callback that gets invoked when the weather service returns results
     */
    private WeatherTaskListener weatherTaskListener;

    /**
     * Constructor
     *
     * @param weatherTaskListener Listener Callback that gets invoked when the weather service returns results
     */
    public WeatherTask(Context context, WeatherTaskListener weatherTaskListener) {
        this.context = context;
        this.weatherTaskListener = weatherTaskListener;
    }

    /**
     * Performs work in the background invoking the weather remote service and parses the xml results into temp values
     * @param strings the place params to search form
     * @return the temperature in celsius
     */
    @Override
    protected final Integer doInBackground(String... strings) {
        int temp = ERROR;
        try {
            String xml = fetchWeatherData(strings[0]);
            if (xml != null) {
                XPathFactory factory = XPathFactory.newInstance();
                XPath xpath = factory.newXPath();
                XPathExpression expr = xpath.compile(context.getString(R.string.xpath_weather_service_temperature));
                Object result = expr.evaluate(new InputSource(new StringReader(xml)), XPathConstants.NODESET);
                NodeList nodes = (NodeList) result;
                if (nodes.getLength() > 0) {
                    temp = Integer.valueOf(nodes.item(0).getAttributes().getNamedItem("data").getNodeValue());
                }
            }
        } catch (XPathExpressionException e) {
            Log.wtf(WeatherTask.class.toString(), e);
        } catch (IOException e) {
            Log.wtf(WeatherTask.class.toString(), e);
        }
        return temp;
    }

    /**
     * Invoked in the main UI thread delegating results to the weatherTaskListener
     * @param temperatureCelsius the temperature in celsius
     */
    @Override
    protected final void onPostExecute(final Integer temperatureCelsius) {
        super.onPostExecute(temperatureCelsius);
        weatherTaskListener.onTempFound(temperatureCelsius);
    }

    /**
     * private helper that actually makes the http call and fetches the remote response from Google's weather service
     * @param place the place to look weather info for
     * @return the xml response as a string
     * @throws IOException
     */
    private String fetchWeatherData(String place) throws IOException {
        String url = context.getString(R.string.url_service_weather, URLEncoder.encode(place, "UTF-8"));
        StringBuilder builder = new StringBuilder();
        InputStream content = null;
        HttpGet httpGet = new HttpGet(url);
        HttpResponse response = HTTP_CLIENT.execute(httpGet);
        StatusLine statusLine = response.getStatusLine();
        int statusCode = statusLine.getStatusCode();
        BufferedReader reader = null;
        if (statusCode == HttpStatus.SC_OK) {
            HttpEntity entity = response.getEntity();
            content = entity.getContent();
            reader = new BufferedReader(new InputStreamReader(content));
            String line;
            while ((line = reader.readLine()) != null) {
                builder.append(line);
            }
        } else {
            Log.e(WeatherTask.class.toString(), "Failed to download file");
        }
        Utils.close(content, reader);
        return builder.toString();
    }

    /**
     * Callback interface utilized to delegate temperature results to the AsyncTask invokers
     */
    interface WeatherTaskListener {

        /**
         * Receives the results from the weather service
         * @param temperatureCelsius the temperature in celsius or potentially WeatherTask.ERROR if not a valid temperature or there
         *                           was a problem communicating with the remote weather service
         */
        void onTempFound(int temperatureCelsius);
    }

}