尝试显示我的应用的天气图标时遇到问题

Posted

技术标签:

【中文标题】尝试显示我的应用的天气图标时遇到问题【英文标题】:Having problem trying to display my app's weather icons 【发布时间】:2021-09-22 01:37:28 【问题描述】:

这是大约 20 天前最初被问到的,我试图根据城市的响应在我的应用程序上显示天气图标(来自可绘制文件夹) 来自天气官方 API 文档https://openweathermap.org/weather-conditions 中列出的天气条件数量(您始终可以通过查看编辑历史来查看)。 API 中有 9 种主要天气条件。

这仍然是我的目标:

首次打开应用时,不显示图标。

如果用户搜索一个城市并且他得到的响应是晴朗的天空,则显示晴朗的天空图标;

否则,如果响应是 Few Clouds in that city,则显示 Few Clouds 图标

否则,如果响应是该城市的散云,则显示散云图标

否则,如果响应是该城市的断云,则显示断云图标

否则,如果响应是该城市的阵雨,则显示阵雨图标

否则,如果响应是该城市的雨,则显示雨图标

否则,如果该城市的响应是雷暴,则显示雷暴图标

否则,如果响应是该城市的雪,则显示雪图标

否则,如果响应是该城市的 Mist,则显示 Mist 图标。

在 Magdalena Rowicka 的帮助下,我已经完成了一些事情,但是即使我自己尝试解决了这个问题,问题仍然没有完全解决,这就是我重新悬赏帖子的原因。

我做的第一件事是使用以下数据集创建一个单独的枚举类:

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

然后我在片段上声明我的文本视图的地方添加了这段代码final ImageView imageofWeather = rootView.findViewById(R.id.imageView2);

然后我添加了这个int drawableResource; // 这里定义默认图标例如 R.drawable.default_weather_icon 在片段上的viewModel.getWeatherDataLiveData().observe(getViewLifecycleOwner(), data -> 之后。

然后我终于添加了这段代码:

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);
            

在fragment中的if语句下直接访问API并显示天气图标。 (相应的 9 个图标目前在 firstfragment 类的编号行上可见)。

当前设置的问题在于:

对于每个 case 语句,我都会收到以下错误:

分配给“drawableResource”的值 R.drawable.sun(和其余部分) 从未使用过。

线条图像ofWeather.setImageDrawable(drawableResource);显示此错误:

必需类型:Drawable,提供:int

如果有人可以提供帮助,我一定会很感激。

这是我的片段代码:

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);
    

【问题讨论】:

您好,请检查您是否已解决问题,否则我很乐意为您提供帮助。您的屏幕上是否有城市列表,并且每个城市都有基于天气的各自图标?还是屏幕上只显示一个城市和相应的天气图标? @Basu 有人正在帮助我。但如果她无法做到这一点,我会告诉你,谢谢。我可以得到任何我想要的城市,但必须一次一个,并带有相应的天气图标 @Basu 我已经重新加载了代码,因为它还没有完全解决 嗨,理查德。我已经看过代码并发现了错误。我将在几分钟内发送答案。如果我需要更多信息会告诉我 【参考方案1】:

也许可以这样尝试:

    创建一个带有枚举的天气类,指定要显示的图标。 下载数据后,转换为创建的类 一个单独的函数,它将决定为给定枚举显示什么

编辑:

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

在 onCreateView 中

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

然后选择正确的图标

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);

【讨论】:

对不起代码,但我很长时间没有使用 Java,例如```私有无效displayIcon(IconState iconState)swich()案例IconState.Sun:iconWeather.setDrawable(R.drawable.icon_sun);休息; ``` 拜托我是一个还在学习编码的新手,我很难理解你的建议。尝试了您发送的 sn-p 并失败,出现 6 个编译错误 好的,我知道这里发生了什么。告诉我你把天气放在哪里?这是“示例”类,“天气”字段,它是 Weather 对象的列表? 将 imageOfWeather 更改为 imageofWeather(这是您的名字参考),尝试添加所有 case 语句,将默认图标添加到 drawableResource e。 G。 int drawableResource = R.drawable.sun_icon 。其余的错误,请尝试在谷歌研究。像 4 年前一样,我是 Java 中的最后一个代码?复制错误并过去到谷歌我确定你在堆栈上找到了一些东西 在您的代码 onCreateView 方法中,在检查数据是否不为空之前,您定义 drawableResource (int drawableResource;) 更改为某些资源 e。 G。 int drawableResource = R.drawable.sun_icon;【参考方案2】:

线 imageofWeather.setImageDrawable(drawableResource);显示此错误:

Required type: Drawable, Provided: int

这意味着setImageDrawable() 需要(期望)一个Drawable 参数,但提供的(找到)参数是一个int

要解决此问题,请改用setImageResource(),它采用int 可绘制资源而不是Drawable

对于每个 case 语句,我都会收到以下错误:

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

这是由于之前的错误引发的,它认为drawableResource 未被setImageDrawable() 的行使用,因此它警告您您为其分配了一个值但从未使用过它。

应该通过修复第一个警告来修复此警告;不过,我建议用一个私有构造函数重写enum,该构造函数接受一个int 可绘制资源值,它将处理switch 语句而不是让片段这样做。

新的枚举:

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;
    


然后,您可以删除它并通过使用枚举的getDrawable() 方法获取drawable 来简化它,而不是片段中的switch 语句,如下所示:

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

【讨论】:

好的。非常感谢您对它的详细解释。完成您的建议后,它没有显示任何错误,但枚举类为每个字段提供此警告:即从未使用字段“Sun”。 @RichardWilson 这只是一个编译时警告,因为它看到你没有直接使用Sun 资源(或任何其他资源),即你没有在编译时使用setImageResource(R.drawable.sun)时间,因为变量drawableResource 的值实际上并不是在编译时确定的,而是在运行时(即应用程序启动时)确定的;但实际上在运行时您确实通过变量 drawableResource 使用这些资源 好的,当我这样运行应用程序时,在运行时出现以下错误: java.lang.NullPointerException: Attempt to invoke virtual method 'int com.viz.lightweatherforecast.Retrofit.WeatherIcon.getDrawable ()' 在空对象引用上 @RichardWilson 所以,原来data.getWeather().get(0).getIcon()null.. API 可能可以为空.. 使用if (icon != null) int drawableResource = icon.getDrawable(); imageofWeather.setImageResource(drawableResource); 怎么样? 现在它没有显示任何错误,也没有显示图标。即一个显示小雨的城市,什么也没有【参考方案3】:

您必须在清单文件中创建activity-alias,您可以在其中根据天气条件设置图标。

<?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>

在 MainActivity 文件中,您必须根据天气情况更改图标。

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();

您可以在此链接中找到整篇文章: https://www.geeksforgeeks.org/how-to-change-app-icon-of-android-programmatically-in-android/

【讨论】:

【参考方案4】:

请试试这个代码。

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);
    

【讨论】:

在尝试代码后,我得到以下两个编译错误:1.无法解析符号'context'和2.'switch'中的分支是默认分支的副本。 我已更新错误 1 ​​的代码(您应该发送上下文)。对于错误2,检查两个天气图标是否相同。 很抱歉,@zain 已经帮助了我。不过还是谢谢

以上是关于尝试显示我的应用的天气图标时遇到问题的主要内容,如果未能解决你的问题,请参考以下文章

如何在雅虎天气预报的每一天加载天气图标?

如何显示openweathermap天气图标

如何在 Recyclerview 中显示图像 - Recyclerview 图像显示错误

我在哪里可以找到免费的天气图标? [关闭]

百科知识 天气图标示例

百科知识 天气图标示例