尝试显示我的应用的天气图标时遇到问题
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 已经帮助了我。不过还是谢谢以上是关于尝试显示我的应用的天气图标时遇到问题的主要内容,如果未能解决你的问题,请参考以下文章