我正在通过制作使用yahoo weather来显示今天天气的应用程序来学习使用REST API。我创建了一个AsyncTask,一个自定义适配器和一个在MainActivity中调用的WeatherData类。我在使用这个WeatherData类和自定义适配器时遇到了一些麻烦。
在适配器中,尝试从天气数据类调用JSON对象时收到错误消息。它说不能从静态上下文中引用非静态字段“天气”和“日期”。我尝试阅读静态上下文,但确实使我感到困惑,它是什么以及它的作用。
第二个问题是,当我尝试将日期和天气添加到我的天气数据ArrayList时,我的AsyncTask现在也给出了错误。它说WeatherData中的WeatherData(JSONobject)不能应用于JSONObject,java.lang.String。我认为这与以下事实有关:我将天气和日期用作WeatherData类中的对象,然后尝试将它们用作数组列表中的字符串。我试图通过简单地将它们更改为WeatherData类中的字符串来修复它,但是随后出现各种新错误。有人可以帮助我解决我的问题吗?
因此,这是我的MainActivity的一部分,我在其中调用数据:
public void getData(View view) {
ClassAsyncTask task = new ClassAsyncTask(this);
task.execute(chosenloc);
}
public void setData(ArrayList<WeatherData> weatherdata) {
// Construct the data source
ArrayList<WeatherData> arrayOfWeather = new ArrayList<WeatherData>();
// Create the adapter to convert the array to views
CustomArrayAdapter adapter = new CustomArrayAdapter(this, arrayOfWeather);
// Attach the adapter to a Listview
ListView listView = (ListView) findViewById(R.id.weatherListView);
listView.setAdapter(adapter);
}
这是我的自定义适配器:
public class CustomArrayAdapter extends ArrayAdapter<WeatherData> {
public CustomArrayAdapter(Context context, ArrayList<WeatherData> weatherdata){
super(context, 0, weatherdata);
}
@Override
public View getView(int position, View convertView, ViewGroup parent){
// Get the data item for this position
WeatherData weather = getItem(position);
// Check if an exising view is being reused, otherwise inflate the view
if (convertView == null){
convertView = LayoutInflater.from(getContext()).inflate(R.layout.custom_array_layout, parent, false);
}
// Lookup view for data population
TextView date = (TextView) convertView.findViewById(R.id.date);
TextView weather = (TextView) convertView.findViewById(R.id.weather);
// Populate the data into the template view using the data object
date.setText(WeatherData.date);
weather.setText(WeatherData.weather);
// Return the completed view to render on screen
return convertView;
}
}
我的WeatherData类:
public class WeatherData {
// Fields
public JSONObject date;
public String weather;
// Constructor
public WeatherData(JSONObject object) {
try {
JSONArray dates = object.getJSONArray("date");
JSONArray weather = object.getJSONArray("text");
} catch (JSONException e) {
e.printStackTrace();
}
}
// Method to convert an array of JSON objects into a list of objects
public static ArrayList<WeatherData> fromJson(JSONArray jsonObjects){
ArrayList<WeatherData> weather = new ArrayList<WeatherData>();
for (int i = 0; i < jsonObjects.length(); i++) {
try {
weather.add(new WeatherData(jsonObjects.getJSONObject(i)));
} catch (JSONException e) {
e.printStackTrace();
}
}
return weather;
}
}
最后,我的AsyncTask解析JSON的部分:
protected void onPostExecute(String result){
super.onPostExecute(result);
// Alert user if nothing was found
if(result.length() == 0){
Toast.makeText(context, "Nothing was found", Toast.LENGTH_SHORT).show();
}
else {
// Parse JSON
ArrayList<WeatherData> weatherdata = new ArrayList<>();
try {
JSONObject respObj = new JSONObject(result);
JSONObject forecastObj = respObj.getJSONObject("forecast");
JSONArray dates = forecastObj.getJSONArray("date");
JSONArray weatherArray = forecastObj.getJSONArray("text");
for (int i = 0; i<dates.length(); i++){
JSONObject date = dates.getJSONObject(i);
String weather = date.getString("text");
weatherdata.add(new WeatherData(date, weather));
}
} catch (JSONException e) {
e.printStackTrace();
}
// Update MainActivity
this.activity.setData(weatherdata);
}
}
最佳答案
您有很多语义错误,理解静态和非静态的差异和细微差别非常重要,但是要修复您的代码,只需注意在何处使用的变量即可。我不会为您阅读Yahoo weather API,因此我将以一种通用的方式在此处显示一些内容。
固定代码如下:
这应该是您的getView
// Get the data item for this position
WeatherData weather = getItem(position);
// Check if an exising view is being reused, otherwise inflate the view
if (convertView == null){
convertView = LayoutInflater.from(getContext()).inflate(R.layout.custom_array_layout, parent, false);
}
// CHANGED HERE the textView "weather` had the same name of the "WeatherData" defined a few lines above
// Lookup view for data population
TextView textDate = (TextView) convertView.findViewById(R.id.date);
TextView textWeather = (TextView) convertView.findViewById(R.id.weather);
// CHANGED HERE to properly call the textView methods and to read the fields from the instance of "WeatherData"
// Populate the data into the template view using the data object
textDate.setText(weather.date);
textWeather.setText(weather.weather);
// Return the completed view to render on screen
return convertView;
您的“ WeatherData”构造函数也不合逻辑,将导致NPE。我不知道您要在其中实现什么,但是在编写
JSONArray dates = object...
时,您提取的信息将被添加到该JsonArray
中,然后被丢弃。字段public JSONObject date
或public String weather
从未初始化,并且不包含任何有用的信息。您可能想做的是这样的:// Fields
public String val1;
public String val2;
public String val3;
... any value necessary
// Constructor
public WeatherData(JSONObject object) {
try {
val1 = object.optString("val1");
val2 = object.optString("val2");
val3 = object.optString("val3");
... parse here EVERYTHING from the object
} catch (JSONException e) {
e.printStackTrace();
}
}
另外,在您的
postExecute
上,您试图创建新的WeatherData
,将两个值传递给它,例如new WeatherData(date, weather)
。同样,读取WeatherData
构造函数,它仅使用1个值,即JsonObject object
。最后是一种性能,您不应将
string
返回到onPostExecute。您应该执行一个返回ArrayList<WeatherData> result
的AsyncTask。然后,所有解析代码都应在background
执行中。编辑:示例asyncTask
public class MyAsyncTask extends AsyncTask<String, Integer, List<WeatherObject>>{
@Override protected List<WeatherObject> doInBackground(String... params) {
// here you call the API and parse the results
// return ArrayList<WeatherObject> if successful, or `null` if failed
return null;
}
@Override protected void onPostExecute(List<WeatherObject> weatherObjectList) {
// here you simply check for null and use the List
if(weatherObjectList == null){
// fail to load data
} else {
// set data to adapter
}
}
}
关于java - 对非静态字段和JSON对象感到困惑,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/36101895/