Having problem trying to display my app's weather icons

Viewed 770

This was Initially asked about 20 days ago, I was trying to display weather icons on my app according to its city's response(from the drawable folder) from the number of weather conditions listed on the weather's official API doc https://openweathermap.org/weather-conditions (which you can always view by checking the edit history). There are 9 main weather conditions from the API.

This still remains my goal:

  • When the app is open at first, display no icon.

  • If a user searches for a city and the response he gets is a clear sky, display the Clear Sky icon;

  • Otherwise, if the response is Few Clouds in that city, display the Few Clouds icon

  • Otherwise, if the response is Scattered clouds in that city, display the Scattered clouds icon

  • Otherwise, if the response is Broken Clouds in that city, display the Broken Clouds icon

  • Otherwise, if the response is Shower rain in that city, display the Shower rain icon

  • Otherwise, if the response is Rain in that city, display the Rain icon

  • Otherwise, if the response is Thunderstorm in that city, display the Thunderstorm icon

  • Otherwise, if the response is Snow in that city, display the Snow icon

  • Otherwise, if the response is Mist in that city, display the Mist icon.

With Magdalena Rowicka's help, I've been able to achieve a few things but the issue has still not been fully solved even after trying to fix it myself and that's why I'm re-bountying the post.

The first thing I did was to create a separate enum class with the following sets of data:

public enum WeatherIcon {
    Sun, Cloud1, Cloud2, Cloud3, Rain1, Rain2, Thunder, Snow, Mist
}

Then I added this code final ImageView imageofWeather = rootView.findViewById(R.id.imageView2); in the place where i declared my textviews on fragment.

Then I added this int drawableResource; // here define default icon for example R.drawable.default_weather_icon after the viewModel.getWeatherDataLiveData().observe(getViewLifecycleOwner(), data -> { on fragment.

Then i finally added this code:

switch (data.getWeather().get(0).getIcon()) { 
                    case WeatherIcon.Sun:
                        drawableResource = R.drawable.sun; //reference to drawable id
                        break;
                    case WeatherIcon.Cloud1:
                        drawableResource = R.drawable.broken_clouds; //reference to drawable id
                        break;
                    case WeatherIcon.Cloud2:
                        drawableResource = R.drawable.few_clouds; //reference to drawable id
                        break;
                    case WeatherIcon.Cloud3:
                        drawableResource = R.drawable.scattered_clouds; //reference to drawable id
                        break;
                    case WeatherIcon.Rain1:
                        drawableResource = R.drawable.small_rain; //reference to drawable id
                        break;
                    case WeatherIcon.Rain2:
                        drawableResource = R.drawable.shower_rain; //reference to drawable id
                        break;
                    case WeatherIcon.Thunder:
                        drawableResource = R.drawable.thunderstorm; //reference to drawable id
                        break;
                    case WeatherIcon.Snow:
                        drawableResource = R.drawable.snow; //reference to drawable id
                        break;
                    case WeatherIcon.Mist:
                        drawableResource = R.drawable.mist; //reference to drawable id
                        break;



        imageofWeather.setImageDrawable(drawableResource);
            }

Under the if statement in fragment to access the API directly and display the weather icons. (The respective 9 icons are currently shown visibly on the numbering line of the firstfragment class).

The issues from this current setup is that:

  • For each case statement, I get the following error:

The value R.drawable.sun(and the rest) assigned to 'drawableResource' is never used.

and

  • The line imageofWeather.setImageDrawable(drawableResource); shows this error:

Required type: Drawable, Provided: int

I will surely appreciate it if anyone can help.

Here's My Fragment code:

public class FirstFragment extends Fragment {

    private WeatherDataViewModel viewModel;

    public FirstFragment() {
        // Required empty public constructor
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        View rootView = inflater.inflate(R.layout.fragment_first, container, false);
        // For displaying weather data
        // all field in Java should be type in camelCase, so not current_temp but currentTemp, not Cloud_out but cloudOut
        // Capitalize name is for class not field
        final TextView current_temp = rootView.findViewById(R.id.textView10);
        final TextView current_output = rootView.findViewById(R.id.textView11);
        final TextView rise_time = rootView.findViewById(R.id.textView25);
        final TextView set_time = rootView.findViewById(R.id.textView26);
        final TextView temp_out = rootView.findViewById(R.id.textView28);
        final TextView Press_out = rootView.findViewById(R.id.textView29);
        final TextView Humid_out = rootView.findViewById(R.id.textView30);
        final TextView Ws_out = rootView.findViewById(R.id.textView33);
        final TextView Visi_out = rootView.findViewById(R.id.textView34);
        final TextView Cloud_out = rootView.findViewById(R.id.textView35);
        final ImageView imageofWeather = rootView.findViewById(R.id.imageView2);


        // Get our ViewModel instance
        viewModel = new ViewModelProvider(this).get(WeatherDataViewModel.class);

        // And whenever the data changes, refresh the UI
        viewModel.getWeatherDataLiveData().observe(getViewLifecycleOwner(), data -> {

            int drawableResource; // here define default icon for example R.drawable.default_weather_icon

            if (data != null) {
                current_temp.setVisibility(View.VISIBLE);
                current_temp.setText(data.getMain().getTemp() + " ℃"); // for that you can use strings resource and templates more in https://developer.android.com/guide/topics/resources/string-resource.html#formatting-strings
                current_output.setVisibility(View.VISIBLE);
                current_output.setText(data.getWeather().get(0).getDescription());
                rise_time.setVisibility(View.VISIBLE);
                rise_time.setText(data.getSys().getSunrise() + " ");
                set_time.setVisibility(View.VISIBLE);
                set_time.setText(data.getSys().getSunset() + " ");
                temp_out.setVisibility(View.VISIBLE);
                temp_out.setText(data.getMain().getTemp() + " ℃");
                Press_out.setVisibility(View.VISIBLE);
                Press_out.setText(data.getMain().getPressure() + " hpa");
                Humid_out.setVisibility(View.VISIBLE);
                Humid_out.setText(data.getMain().getHumidity() + " %");
                Ws_out.setVisibility(View.VISIBLE);
                Ws_out.setText(data.getWind().getSpeed() + " Km/h");
                Visi_out.setVisibility(View.VISIBLE);
                Visi_out.setText(data.getVisibility() + " m");
                Cloud_out.setVisibility(View.VISIBLE);
                Cloud_out.setText(data.getClouds().getAll() + " %");

                // get actual weather.
                switch (data.getWeather().get(0).getIcon()) { //or data.getWeather()[0].getIcon() i don't remember how it work in Java
                    case WeatherIcon.Sun:
                        drawableResource = R.drawable.sun; //reference to drawable id
                        break;
                    case WeatherIcon.Cloud1:
                        drawableResource = R.drawable.broken_clouds; //reference to drawable id
                        break;
                    case WeatherIcon.Cloud2:
                        drawableResource = R.drawable.few_clouds; //reference to drawable id
                        break;
                    case WeatherIcon.Cloud3:
                        drawableResource = R.drawable.scattered_clouds; //reference to drawable id
                        break;
                    case WeatherIcon.Rain1:
                        drawableResource = R.drawable.small_rain; //reference to drawable id
                        break;
                    case WeatherIcon.Rain2:
                        drawableResource = R.drawable.shower_rain; //reference to drawable id
                        break;
                    case WeatherIcon.Thunder:
                        drawableResource = R.drawable.thunderstorm; //reference to drawable id
                        break;
                    case WeatherIcon.Snow:
                        drawableResource = R.drawable.snow; //reference to drawable id
                        break;
                    case WeatherIcon.Mist:
                        drawableResource = R.drawable.mist; //reference to drawable id
                        break;



                    imageofWeather.setImageDrawable(drawableResource);
                }

            } else {
                Log.e("TAG", "No City found");
                current_temp.setVisibility(View.GONE);
                current_output.setVisibility(View.GONE);
                rise_time.setVisibility(View.GONE);
                set_time.setVisibility(View.GONE);
                temp_out.setVisibility(View.GONE);
                Press_out.setVisibility(View.GONE);
                Humid_out.setVisibility(View.GONE);
                Ws_out.setVisibility(View.GONE);
                Visi_out.setVisibility(View.GONE);
                Cloud_out.setVisibility(View.GONE);
                Toast.makeText(requireActivity(), "No City found", Toast.LENGTH_SHORT).show();
            }
        });

        return rootView;
    }

    public void getWeatherData(String name) {
        // The ViewModel controls loading the data, so we just
        // tell it what the new name is - this kicks off loading
        // the data, which will automatically call through to
        // our observe() call when the data load completes
        viewModel.setCityName(name);
    }
}
4 Answers

Maybe try like this:

  1. Create a weather class with an enum specifying which icon to display.
  2. after downloading the data, convert to the created class
  3. A separate function that will decide what to display for a given enum

edited:

public class Example{
  // add to your definition
  private WeaterIcon icon;

  public WeaterIcon getIcon() {
      return icon;
  }

  public void setIcon(WeaterIcon icon) {
      this.icon = icon;
  }
}

enum WeaterIcon {
  SUN, FROG, //type all what want
}

in onCreateView

//there are yor reference to xml object
    final ImageView imageOfWeather = rootView.findViewById(R.id.imageView); // add this reference

and choose right icon

int drawableResource; // here define default icon or not
            switch(data.getIcon()) {
                case WeaterIcon.SUN:
                    drawableResource = R.drawable.sun_icon //reference to drawable id
                    break;
                case WeaterIcon.FROG:
                    drawableResource = R.drawable.frog_icon//reference to drawable id
                    break;
                //add all
            }


            imageOfWeather.setImageDrawable(drawableResource);

The line imageofWeather.setImageDrawable(drawableResource); shows this error:

Required type: Drawable, Provided: int

It means that setImageDrawable() requires (expects) a Drawable parameter, but the provided (found) parameter is an int.

To fix this, use setImageResource() instead which takes an int drawable resource instead of a Drawable

For each case statement, I get the following error:

The value R.drawable.sun(and the rest) assigned to 'drawableResource' is never used.

This is raised because of the previous error, where it considers that drawableResource is not used by the line of setImageDrawable(), and therefore it warns you that you assigned it a value but never used it.

This warning should be fixed by fixing the first one; Although, I'd suggest to rewrite the enum with a private constructor that takes in an int drawable resource value, where it'll handle the switch statement instead of making the fragment does that.

The new enum:

public enum WeatherIcon {

    Sun(R.drawable.sun),
    Cloud1(R.drawable.broken_clouds),
    Cloud2(R.drawable.few_clouds),
    Cloud3(R.drawable.scattered_clouds),
    Rain1(R.drawable.small_rain),
    Rain2(R.drawable.shower_rain),
    Thunder(R.drawable.thunderstorm),
    Snow(R.drawable.snow),
    Mist(R.drawable.mist);

    private int drawable;

    WeatherIcon(int drawable) {
        this.drawable = drawable;
    }

    public int getDrawable() {
        return drawable;
    }

}

Then instead of the switch statement in the fragment you can remove it and simplify it by getting the drawable using the enum's getDrawable() method as follows:

WeatherIcon icon = data.getWeather().get(0).getIcon();
int drawableResource = icon.getDrawable();
imageofWeather.setImageResource(drawableResource);

You have to make activity-alias in your manifest file where you are setting icons as per weather conditions.

<?xml version="1.0" encoding="utf-8"?>
<manifest  xmlns:android="http://schemas.android.com/apk/res/android"
package="io.github.erikjhordanrey.livebinding">

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

<application
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:roundIcon="@mipmap/ic_launcher_round"
    android:supportsRtl="true"
    android:theme="@style/AppTheme"
    android:usesCleartextTraffic="true">

    <activity android:name="io.github.erikjhordanrey.livebinding.view.DcCharacterActivity">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <action android:name="android.intent.action.VIEW" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>


    <activity-alias
        android:name=".MainActivityAlias"
        android:enabled="false"
        android:icon="@drawable/R.drawable.sun"
        android:label="@string/app_name"
        android:roundIcon="@drawable/R.drawable.sun"
        android:targetActivity="io.github.erikjhordanrey.livebinding.view.DcCharacterActivity">

        <intent-filter>

            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />

        </intent-filter>

    </activity-alias>

    <activity-alias
        android:name=".MainActivityAlias"
        android:enabled="false"
        android:icon="@drawable/R.drawable.broken_clouds"
        android:label="@string/app_name"
        android:roundIcon="@drawable/R.drawable.broken_clouds"
        android:targetActivity="io.github.erikjhordanrey.livebinding.view.DcCharacterActivity">

        <intent-filter>

            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />

        </intent-filter>

    </activity-alias>

    <activity-alias
        android:name=".MainActivityAlias"
        android:enabled="false"
        android:icon="@drawable/R.drawable.few_clouds"
        android:label="@string/app_name"
        android:roundIcon="@drawable/R.drawable.few_clouds"
        android:targetActivity="io.github.erikjhordanrey.livebinding.view.DcCharacterActivity">

        <intent-filter>

            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />

        </intent-filter>

    </activity-alias>

    <!--and so on....-->
</application>

</manifest>

In MainActivity file you have to change icons as per your weather conditions.

private void newicon() {
      
      // enable old icon
    PackageManager manager=getPackageManager();
    manager.setComponentEnabledSetting(new ComponentName(MainActivity.this,"com.prepare.makedirectory.MainActivity")
            ,PackageManager.COMPONENT_ENABLED_STATE_DISABLED,PackageManager.DONT_KILL_APP);
      
      // enable new icon
    manager.setComponentEnabledSetting(new ComponentName(MainActivity.this,"com.prepare.makedirectory.MainActivityAlias")
            ,PackageManager.COMPONENT_ENABLED_STATE_ENABLED,PackageManager.DONT_KILL_APP);
    Toast.makeText(MainActivity.this,"Enable New Icon" ,Toast.LENGTH_LONG).show();
}

you can find whole Article in this link : https://www.geeksforgeeks.org/how-to-change-app-icon-of-android-programmatically-in-android/

Please try this code.

public class FirstFragment extends Fragment {

    private WeatherDataViewModel viewModel;

    public FirstFragment() {
        // Required empty public constructor
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        View rootView = inflater.inflate(R.layout.fragment_first, container, false);
        // For displaying weather data
        // all field in Java should be type in camelCase, so not current_temp but currentTemp, not Cloud_out but cloudOut
        // Capitalize name is for class not field
        final TextView current_temp = rootView.findViewById(R.id.textView10);
        final TextView current_output = rootView.findViewById(R.id.textView11);
        final TextView rise_time = rootView.findViewById(R.id.textView25);
        final TextView set_time = rootView.findViewById(R.id.textView26);
        final TextView temp_out = rootView.findViewById(R.id.textView28);
        final TextView Press_out = rootView.findViewById(R.id.textView29);
        final TextView Humid_out = rootView.findViewById(R.id.textView30);
        final TextView Ws_out = rootView.findViewById(R.id.textView33);
        final TextView Visi_out = rootView.findViewById(R.id.textView34);
        final TextView Cloud_out = rootView.findViewById(R.id.textView35);
        final ImageView imageofWeather = rootView.findViewById(R.id.imageView2);


        // Get our ViewModel instance
        viewModel = new ViewModelProvider(this).get(WeatherDataViewModel.class);

        // And whenever the data changes, refresh the UI
        viewModel.getWeatherDataLiveData().observe(getViewLifecycleOwner(), data -> {

            Drawble drawableResource; // default added in switch

            if (data != null) {
                current_temp.setVisibility(View.VISIBLE);
                current_temp.setText(data.getMain().getTemp() + " ℃"); // for that you can use strings resource and templates more in https://developer.android.com/guide/topics/resources/string-resource.html#formatting-strings
                current_output.setVisibility(View.VISIBLE);
                current_output.setText(data.getWeather().get(0).getDescription());
                rise_time.setVisibility(View.VISIBLE);
                rise_time.setText(data.getSys().getSunrise() + " ");
                set_time.setVisibility(View.VISIBLE);
                set_time.setText(data.getSys().getSunset() + " ");
                temp_out.setVisibility(View.VISIBLE);
                temp_out.setText(data.getMain().getTemp() + " ℃");
                Press_out.setVisibility(View.VISIBLE);
                Press_out.setText(data.getMain().getPressure() + " hpa");
                Humid_out.setVisibility(View.VISIBLE);
                Humid_out.setText(data.getMain().getHumidity() + " %");
                Ws_out.setVisibility(View.VISIBLE);
                Ws_out.setText(data.getWind().getSpeed() + " Km/h");
                Visi_out.setVisibility(View.VISIBLE);
                Visi_out.setText(data.getVisibility() + " m");
                Cloud_out.setVisibility(View.VISIBLE);
                Cloud_out.setText(data.getClouds().getAll() + " %");

                Drawable drawableResource; // default icon is set in the switch
            switch (data.getWeather().get(0).getIcon())  {
                case WeaterIcon.SUN:
                    drawableResource = ContextCompat.getDrawable(requireActivity(), R.drawable.sun);
                    break;
                case WeatherIcon.Cloud1:
                        drawableResource = ContextCompat.getDrawable(requireActivity(), R.drawable.broken_clouds); //reference to drawable id
                        break;
                case WeatherIcon.Cloud2:
                        drawableResource = ContextCompat.getDrawable(requireActivity(), R.drawable.few_clouds); //reference to drawable id
                        break;
                case WeatherIcon.Cloud3:
                        drawableResource = ContextCompat.getDrawable(requireActivity(), R.drawable.scattered_clouds); //reference to drawable id
                        break;
                case WeatherIcon.Rain1:
                        drawableResource = ContextCompat.getDrawable(requireActivity(), R.drawable.small_rain); //reference to drawable id
                        break;
                case WeatherIcon.Rain2:
                        drawableResource = ContextCompat.getDrawable(requireActivity(), R.drawable.shower_rain); //reference to drawable id
                        break;
                case WeatherIcon.Thunder:
                        drawableResource = ContextCompat.getDrawable(requireActivity(), R.drawable.thunderstorm); //reference to drawable id
                        break;
                case WeatherIcon.Snow:
                        drawableResource = ContextCompat.getDrawable(requireActivity(), R.drawable.snow); //reference to drawable id
                        break;
                case WeatherIcon.Mist:
                        drawableResource = ContextCompat.getDrawable(requireActivity(), R.drawable.mist); //reference to drawable id
                        break;

                //add a default of any background if error occurs
                default:
                    drawableResource = ContextCompat.getDrawable(requireActivity(), R.drawable.any_background);
                    break;
           
                }
             imageOfWeather.setImageDrawable(drawableResource);

            } else {
                Log.e("TAG", "No City found");
                current_temp.setVisibility(View.GONE);
                current_output.setVisibility(View.GONE);
                rise_time.setVisibility(View.GONE);
                set_time.setVisibility(View.GONE);
                temp_out.setVisibility(View.GONE);
                Press_out.setVisibility(View.GONE);
                Humid_out.setVisibility(View.GONE);
                Ws_out.setVisibility(View.GONE);
                Visi_out.setVisibility(View.GONE);
                Cloud_out.setVisibility(View.GONE);
                Toast.makeText(requireActivity(), "No City found", Toast.LENGTH_SHORT).show();
            }
        });

        return rootView;
    }

    public void getWeatherData(String name) {
        // The ViewModel controls loading the data, so we just
        // tell it what the new name is - this kicks off loading
        // the data, which will automatically call through to
        // our observe() call when the data load completes
        viewModel.setCityName(name);
    }
}
Related