Skip to main content

android - How to create a weather widget

widget_layout.xml

<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="5dp"
    >
    <TextView
        android:id="@+id/tv_temperature"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:text="Temp"
        android:background="@drawable/bg_red"
        android:textColor="@android:color/white"
        android:fontFamily="sans-serif-condensed"
        android:textSize="16dp"
        android:clickable="true"
        />
    <TextView
        android:id="@+id/tv_humidity"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:padding="7dp"
        android:text="H"
        android:layout_marginLeft="-8dp"
        android:gravity="center"
        android:textColor="#ffffff"
        android:background="@drawable/bg_humidity"
        android:layout_toRightOf="@id/tv_temperature"
        android:clickable="true"
        />
</RelativeLayout>
WeatherWidget.java

package com.cfsuman.me.weather;

import android.app.PendingIntent;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.StrictMode;
import android.util.Log;
import android.widget.RemoteViews;
import android.widget.Toast;

import org.json.JSONException;
import org.json.JSONObject;
import java.net.InetAddress;


public class WeatherWidget extends AppWidgetProvider {
    // To identify the widget views click
    private static final String TEMPERATURE_CLICKED = "Temperature";
    private static final String HUMIDITY_CLICKED = "Humidity";

    // Construct the url to fetch weather JSON data from web
    private String mCity = "khulna";
    private String mCountry = "bd"; // Bangladesh
    // mURLString = "http://api.openweathermap.org/data/2.5/weather?q=khulna,bd&APPID=YourAppID";
    private String mURLRoot = "http://api.openweathermap.org/data/2.5/weather?q=";
    private String mAppID = "&APPID=YourAppID";
    private String mURLString = mURLRoot+mCity+","+mCountry+mAppID;

    public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds){
        /*
            AppWidgetManager
                Updates AppWidget state; gets information about installed AppWidget
                providers and other AppWidget related state.

            ComponentName
                Identifier for a specific application component (Activity, Service, BroadcastReceiver,
                or ContentProvider) that is available. Two pieces of information, encapsulated here,
                are required to identify a component: the package (a String) it exists in, and the
                class (a String) name inside of that package.

            RemoteViews
                A class that describes a view hierarchy that can be displayed in another process.
                The hierarchy is inflated from a layout resource file, and this class provides some
                basic operations for modifying the content of the inflated hierarchy.
        */
        AppWidgetManager appWidgetManager1= appWidgetManager;
        ComponentName watchWidget = new ComponentName(context, WeatherWidget.class);
        RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.widget_layout);

        Intent intent = new Intent(context, WeatherWidget.class);
        /*
            PendingIntent
                A description of an Intent and target action to perform with it. Instances of this
                class are created with getActivity(Context, int, Intent, int),
                getActivities(Context, int, Intent[], int), getBroadcast(Context, int, Intent, int),
                and getService(Context, int, Intent, int); the returned object can be handed to other
                applications so that they can perform the action you described on your behalf at a later time.
        */
        PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
        remoteViews.setOnClickPendingIntent(R.id.tv_temperature, pendingIntent);

        remoteViews.setOnClickPendingIntent(
                R.id.tv_temperature,
                getPendingSelfIntent(context, TEMPERATURE_CLICKED)
        );

        remoteViews.setOnClickPendingIntent(
                R.id.tv_humidity,
                getPendingSelfIntent(context, HUMIDITY_CLICKED)
        );
        appWidgetManager1.updateAppWidget(watchWidget, remoteViews);
    }

    // Catch the click on widget views
    protected PendingIntent getPendingSelfIntent(Context context, String action) {
        Intent intent = new Intent(context, getClass());
        intent.setAction(action);
        //Toast.makeText(context, "Intent Received: "+action, Toast.LENGTH_SHORT).show();
        return PendingIntent.getBroadcast(context, 0, intent, 0);
    }

    @Override
    public void onReceive(Context context, Intent intent) {
        // Allow the network operation on main thread
        StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitNetwork().build();
        StrictMode.setThreadPolicy(policy);

        super.onReceive(context, intent);

        AppWidgetManager appWidgetManager= AppWidgetManager.getInstance(context);
        RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.widget_layout);
        ComponentName watchWidget = new ComponentName(context, WeatherWidget.class);

        Toast.makeText(context, "Requested", Toast.LENGTH_SHORT).show();

        // Check the internet connection availability
        if(isInternetConnected()){
            Toast.makeText(context, "Fetching Data", Toast.LENGTH_SHORT).show();
            // Update the widget weather data
            // Execute the AsyncTask
            new ProcessJSONData(appWidgetManager,watchWidget,remoteViews).execute(mURLString);
            remoteViews.setInt(R.id.tv_temperature, "setBackgroundResource", R.drawable.bg_green);
        }else {
            Toast.makeText(context, "No Internet", Toast.LENGTH_SHORT).show();
            remoteViews.setInt(R.id.tv_temperature, "setBackgroundResource", R.drawable.bg_red);
        }

        // If the temperature text clicked
        if (TEMPERATURE_CLICKED.equals(intent.getAction())) {
            // Do something
        }

        // If the humidity text clicked
        if(HUMIDITY_CLICKED.equals(intent.getAction())){
            // Do something
        }

        // Apply the changes
        appWidgetManager.updateAppWidget(watchWidget, remoteViews);
    }

    // AsyncTask to fetch, process and display weather data
    private class ProcessJSONData extends AsyncTask<String, Void, String> {
        private AppWidgetManager appWidgetManager;
        private ComponentName watchWidget;
        private RemoteViews remoteViews;

        @Override
        protected void onPreExecute(){
            super.onPreExecute();
        }

        public ProcessJSONData(AppWidgetManager appWidgetManager, ComponentName watchWidget, RemoteViews remoteViews){
            // Do something
            this.appWidgetManager = appWidgetManager;
            this.watchWidget = watchWidget;
            this.remoteViews = remoteViews;
        }

        @Override
        protected String doInBackground(String... strings){
            String stream;
            String urlString = strings[0];

            // Get jason data from web
            HTTPDataHandler hh = new HTTPDataHandler();
            stream = hh.GetHTTPData(urlString);

            // Return the data from specified url
            return stream;
        }

        protected void onPostExecute(String stream){
            super.onPostExecute(stream);

            if(stream !=null){
                try{
                    // Process JSON data
                    // Get the full HTTP Data as JSONObject
                    JSONObject reader= new JSONObject(stream);
                    // Get the JSONObject "coord"...........................
                    JSONObject coord = reader.getJSONObject("main");
                    // Get the value of key "temp" under JSONObject "main"
                    String temperature = coord.getString("temp");
                    // Get the value of key "humidity" under JSONObject "main"
                    String humidity = coord.getString("humidity");
                    String city = reader.getString("name");
                    Double celsius = getCelsiusFromKelvin(temperature);
                    temperature ="" + celsius + " " + (char) 0x00B0+"C";
                    Log.d("Temp",temperature);

                    // Display weather data on widget
                    remoteViews.setTextViewText(R.id.tv_temperature, temperature);
                    remoteViews.setTextViewText(R.id.tv_humidity, "H: " + humidity + " %");

                    // Apply the changes
                    appWidgetManager.updateAppWidget(watchWidget, remoteViews);
                }catch(JSONException e){
                    e.printStackTrace();
                }
            }
        } // onPostExecute() end
    } // ProcessJSON class end

    // Method to get celsius value from kelvin
    public Double getCelsiusFromKelvin(String kelvinString){
        Double kelvin = Double.parseDouble(kelvinString);
        Double numberToMinus = 273.15;
        Double celsius = kelvin - numberToMinus;
        // Rounding up the double value
        // Each zero (0) return 1 more precision
        // Precision means number of digits after dot
        celsius = (double)Math.round(celsius * 10) / 10;
        return celsius;
    }

    // Custom method to check internet connection
    public Boolean isInternetConnected(){
        boolean status = false;
        try{
            InetAddress address = InetAddress.getByName("google.com");

            if(address!=null)
            {
                status = true;
            }
        }catch (Exception e) // Catch the exception
        {
            e.printStackTrace();
        }
        return status;
    }
}
HTTPDataHandler.java

package com.cfsuman.me.weather;

import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;

public class HTTPDataHandler {

    static String stream = null;

    public HTTPDataHandler(){
    }

    public String GetHTTPData(String urlString){
        try{
            URL url = new URL(urlString);
            HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();

            // Check the connection status
            if(urlConnection.getResponseCode() == 200)
            {
                // if response code = 200 ok
                InputStream in = new BufferedInputStream(urlConnection.getInputStream());

                // Read the BufferedInputStream
                BufferedReader r = new BufferedReader(new InputStreamReader(in));
                StringBuilder sb = new StringBuilder();
                String line;
                while ((line = r.readLine()) != null) {
                    sb.append(line);
                }
                stream = sb.toString();
                // End reading...............

                // Disconnect the HttpURLConnection
                urlConnection.disconnect();
            }
            else
            {
                // Do something
            }
        }catch (MalformedURLException e){
            e.printStackTrace();
        }catch(IOException e){
            e.printStackTrace();
        }finally {

        }
        // Return the data from specified url
        return stream;
    }
}
xml/widget_provider.xml

<appwidget-provider
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:minWidth="80dp"
    android:minHeight="40dp"
    android:updatePeriodMillis="1800000"
    android:initialLayout="@layout/widget_layout"
    android:previewImage="@drawable/widget_preview"
    >
</appwidget-provider>
AndroidManifest.xml

<manifest
    xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.cfsuman.me.weather"
    >

    <uses-permission android:name="android.permission.INTERNET"/>

    <application android:allowBackup="true"
        android:label="@string/app_name"
        android:icon="@mipmap/ic_launcher"
        android:supportsRtl="true"
        android:theme="@style/AppTheme"
        >
        <receiver android:name=".WeatherWidget" >
            <intent-filter>
                <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
            </intent-filter>
            <meta-data
                android:name="android.appwidget.provider"
                android:resource="@xml/widget_provider" />
        </receiver>
    </application>
</manifest>
drawable/bg_red.xml

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item>
        <shape android:shape="oval">
            <size android:height="75dp" android:width="75dp"/>
            <solid android:color="#ff0900"/>
            <stroke android:width="5dp" android:color="#aeab98"/>
        </shape>
    </item>
</selector>
drawable/bg_green.xml

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item>
        <shape android:shape="oval">
            <size android:height="75dp" android:width="75dp"/>
            <solid android:color="#178b34"/>
            <stroke android:width="5dp" android:color="#aeab98"/>
        </shape>
    </item>
</selector>
drawable/bg_humidity.xml

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item>
        <shape android:shape="oval">
            <solid android:color="#aeab98"/>
            <corners android:radius="15dp"/>
        </shape>
    </item>
</selector>
More android examples

Popular posts from this blog

How to use NumberPicker in Android

Table of contentsNumberPicker ExamplesetOnValueChangedListeneronValueChange()setWrapSelectorWheel()setMinValue()setMinValue()setMaxValue()NumberPicker with String ArraysetDisplayedValues()String Array1. NumberPicker Example activity_main.xml <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/rl" android:layout_width="match_parent" android:layout_height="match_parent" android:padding="16dp" tools:context=".MainActivity" android:background="#ffffff" > <TextView android:id="@+id/tv" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="25dp" android:text="Select a number..." /> <NumberPicker android:id="@+id/np" …

TextView new line (multiline) in android

TextView new line (multiline) TextView display text on android app. by default, TextView show text on a single line, and if it is long then TextView take more lines to display its text. android developers can generate a new line on TextView both programmatically and syntactically. android developers can make a multiline TextView without splitting text to multiline by android:minLines attribute.

the following android example code demonstrate us how can we syntactically create a new line on TextView widget by xml layout file and string resource file.

the simplest way to create a new line on TextView is android:text attribute. android:text attribute allow us to display text on android app. we can add a simple '\n' to TextView text where we want to start a new line. in this way we can create a multiline TextView widget in android app. we can assign android:text attribute value by this way android:text="Line1 \n Line2 \n Line3" for a TextView widget. this value will…

How to change TextView font size in android

TextView font size TextView widget display text on android application. we can set or change TextView font size statically by declarative syntax in xml layout file or programmatically at run time in java file. even we can use an xml file source to define font size.

the following example code demonstrate us how can we define TextView font size in xml layout file and how can we uses dimens.xml to reference font size. in this example we did not changes any coding in java file, so here we only include the layout xml file and dimens.xml file. activity_main.xml <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:layout_margin="25dp" tools:context=".MainActivity" > <TextView android:id=&…