RecyclerView 覆盖列表项
RecyclerView overwriting list items
我正在开发任务管理器应用程序。基本上 google 地方 api 我选择位置将其保存到 sqlite
数据库并将其填充到 RecyclerView
中。对于每个位置,我使用 retrofit2
和 openweather
api 来获取该位置的当前天气并将其显示在 RecyclerView
中。这是在位于 onBindViewHolder
方法中的 recyclerview 适配器中的异步任务中完成的。现在,当我创建一个任务时,它可以毫无问题地将数据获取到该位置。当我添加更多任务时,问题就开始了。基本上,当我在新位置添加新任务时,它会覆盖上次添加任务的当前天气,如下图所示。
https://s9.postimg.org/l6tmi3wm7/Screenshot_20160830_143608.png
我怎样才能让它不覆盖以前的任务?
public class TaskAdapter extends RecyclerView.Adapter<TaskAdapter.ViewHolder> {
private List<Task> taskList;
private final String API_KEY = "8617b30a6fc114ad2ad929c111b76edf";
private final String UNITS = "metric";
private double latitude, longitude;
private Task task;
private WeatherInfo weatherInfo;
private Context context;
public class ViewHolder extends RecyclerView.ViewHolder {
private TextView taskName, destination, currentWeather;
private ImageView weatherImg;
public ViewHolder(View view) {
super(view);
taskName = (TextView) view.findViewById(R.id.task);
destination = (TextView) view.findViewById(R.id.date);
currentWeather = (TextView) view.findViewById(R.id.weather);
weatherImg = (ImageView) view.findViewById(R.id.weather_icon);
}
}
public TaskAdapter(List<Task> taskList) {
this.taskList = taskList;
}
public void add(int position, Task item) {
taskList.add(position, item);
notifyItemInserted(position);
}
public void remove(Task item) {
int position = taskList.indexOf(item);
taskList.remove(position);
notifyItemRemoved(position);
}
public Task getTask(int position) {
return taskList.get(position);
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
context = parent.getContext();
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.row_rv, parent, false);
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
task = taskList.get(position);
latitude = task.getDestinationLatitude();
longitude = task.getDestinationLongitude();
new getWeatherDataAsync(holder).execute();
holder.taskName.setText(task.getTaskName());
holder.destination.setText(task.getDestinationName());
}
@Override
public int getItemCount() {
return taskList.size();
}
private class getWeatherDataAsync extends AsyncTask<Void, Void, Void> {
private ViewHolder holder;
private ProgressDialog progressDialog;
public getWeatherDataAsync(ViewHolder holder) {
this.holder = holder;
}
@Override
protected void onPreExecute() {
progressDialog=ProgressDialog.show(context,"Loading...","Getting weather.");
}
@Override
protected Void doInBackground(Void... vHolders) {
try {
WeatherApi weatherApi = WeatherApi.retrofit.create(WeatherApi.class);
Call<WeatherInfo> call = weatherApi.getWeatherData(latitude, longitude, API_KEY, UNITS);
weatherInfo = call.execute().body();
//
} catch (IOException e) {
Log.e("get weather coordinates", "something went wrong: " + e.getMessage());
}
return null;
}
@Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
if (weatherInfo != null) {
holder.currentWeather.setText(String.valueOf(weatherInfo.getMain().getTemp()) + "\u2103");
getWeatherIcon(holder);
} else {
holder.currentWeather.setText("N/A \u2103");
Picasso.with(context).load("file:///android_asset/md-weather-iconset/weather-none-available.png").into(holder.weatherImg);
}
progressDialog.dismiss();
}
}
/**
* Display the correct weather icon from assets based on the data returned from the Retrofit query.
* @param viewHolder
*/
private void getWeatherIcon(ViewHolder viewHolder){
String base="file:///android_asset/md-weather-iconset";
switch (weatherInfo.getWeather().get(0).getIcon()) {
case "01d":
Picasso.with(context).load(base+"/weather-clear.png").into(viewHolder.weatherImg);
break;
case "02d":
Picasso.with(context).load(base+"/weather-few-clouds.png").into(viewHolder.weatherImg);
break;
case "03d":
Picasso.with(context).load(base+"/weather-clouds.png").into(viewHolder.weatherImg);
break;
case "04d":
Picasso.with(context).load(base+"/weather-clouds.png").into(viewHolder.weatherImg);
break;
case "09d":
Picasso.with(context).load(base+"/weather-showers-day.png").into(viewHolder.weatherImg);
break;
case "10d":
Picasso.with(context).load(base+"/weather-rain-day.png").into(viewHolder.weatherImg);
break;
case "11d":
Picasso.with(context).load(base+"/weather-storm-day.png").into(viewHolder.weatherImg);
break;
case "13d":
Picasso.with(context).load(base+"/weather-snow.png").into(viewHolder.weatherImg);
break;
case "50d":
Picasso.with(context).load(base+"/weather-mist.png").into(viewHolder.weatherImg);
break;
case "01n":
Picasso.with(context).load(base+"/weather-clear-night.png").into(viewHolder.weatherImg);
break;
case "02n":
Picasso.with(context).load(base+"/weather-few-clouds-night.png").into(viewHolder.weatherImg);
break;
case "03n":
Picasso.with(context).load(base+"/weather-clouds-night.png").into(viewHolder.weatherImg);
break;
case "04n":
Picasso.with(context).load(base+"/weather-clouds-night.png").into(viewHolder.weatherImg);
break;
case "09n":
Picasso.with(context).load(base+"/weather-showers-night.png").into(viewHolder.weatherImg);
break;
case "10n":
Picasso.with(context).load(base+"/weather-rain-night.png").into(viewHolder.weatherImg);
break;
case "11n":
Picasso.with(context).load(base+"/weather-storm-night.png").into(viewHolder.weatherImg);
break;
case "13n":
Picasso.with(context).load(base+"/weather-snow.png").into(viewHolder.weatherImg);
break;
case "50n":
Picasso.with(context).load(base+"/weather-mist.png").into(viewHolder.weatherImg);
break;
}
}
}
首先你能说清楚你的预期输出是什么吗?也许显示您的预期输出和您获得的输出的图像就足够了。我还建议您不要从适配器内部的网络获取,而是获取片段中的所有天气数据并将信息传递给 adapter.Lets 假设您有一个 Activity 持有 recyclerview。使用接口从适配器调用异步任务。
同时将纬度和经度存储在 viewholder 中,然后再次尝试查看是否有效。
您正在使用 onBindViewHolder()
启动异步任务并将对 holder
的引用传递给它。不幸的是,这不是 RecyclerView 应该工作的方式。 RecyclerView 使用 ViewHolder 模式重用已实例化但不再可见的布局,这就是为什么 holder 在网络响应启动时可能代表完全不同的项目。
您应该做的是将调用异步调用移动到其他地方(例如 Fragment/Activity/Presenter),从回调中更新您的 taskList
集合并使用以下方法之一通知适配器数据集已更改:
看看 RecyclerView.Adapter 文档:
问题是
private WeatherInfo weatherInfo;
在 AsyncTask 中创建 WeatherInfo 对象。这将解决您的问题。
AsyncTask 被执行,它将创建新的 WeatherInfo 对象。现在将该对象传递给方法 so。
像这样改变方法
getWeatherIcon(ViewHolder viewHolder,WeatherInfo wetherInfo)
这将解决您的问题。
我正在开发任务管理器应用程序。基本上 google 地方 api 我选择位置将其保存到 sqlite
数据库并将其填充到 RecyclerView
中。对于每个位置,我使用 retrofit2
和 openweather
api 来获取该位置的当前天气并将其显示在 RecyclerView
中。这是在位于 onBindViewHolder
方法中的 recyclerview 适配器中的异步任务中完成的。现在,当我创建一个任务时,它可以毫无问题地将数据获取到该位置。当我添加更多任务时,问题就开始了。基本上,当我在新位置添加新任务时,它会覆盖上次添加任务的当前天气,如下图所示。
https://s9.postimg.org/l6tmi3wm7/Screenshot_20160830_143608.png
我怎样才能让它不覆盖以前的任务?
public class TaskAdapter extends RecyclerView.Adapter<TaskAdapter.ViewHolder> {
private List<Task> taskList;
private final String API_KEY = "8617b30a6fc114ad2ad929c111b76edf";
private final String UNITS = "metric";
private double latitude, longitude;
private Task task;
private WeatherInfo weatherInfo;
private Context context;
public class ViewHolder extends RecyclerView.ViewHolder {
private TextView taskName, destination, currentWeather;
private ImageView weatherImg;
public ViewHolder(View view) {
super(view);
taskName = (TextView) view.findViewById(R.id.task);
destination = (TextView) view.findViewById(R.id.date);
currentWeather = (TextView) view.findViewById(R.id.weather);
weatherImg = (ImageView) view.findViewById(R.id.weather_icon);
}
}
public TaskAdapter(List<Task> taskList) {
this.taskList = taskList;
}
public void add(int position, Task item) {
taskList.add(position, item);
notifyItemInserted(position);
}
public void remove(Task item) {
int position = taskList.indexOf(item);
taskList.remove(position);
notifyItemRemoved(position);
}
public Task getTask(int position) {
return taskList.get(position);
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
context = parent.getContext();
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.row_rv, parent, false);
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
task = taskList.get(position);
latitude = task.getDestinationLatitude();
longitude = task.getDestinationLongitude();
new getWeatherDataAsync(holder).execute();
holder.taskName.setText(task.getTaskName());
holder.destination.setText(task.getDestinationName());
}
@Override
public int getItemCount() {
return taskList.size();
}
private class getWeatherDataAsync extends AsyncTask<Void, Void, Void> {
private ViewHolder holder;
private ProgressDialog progressDialog;
public getWeatherDataAsync(ViewHolder holder) {
this.holder = holder;
}
@Override
protected void onPreExecute() {
progressDialog=ProgressDialog.show(context,"Loading...","Getting weather.");
}
@Override
protected Void doInBackground(Void... vHolders) {
try {
WeatherApi weatherApi = WeatherApi.retrofit.create(WeatherApi.class);
Call<WeatherInfo> call = weatherApi.getWeatherData(latitude, longitude, API_KEY, UNITS);
weatherInfo = call.execute().body();
//
} catch (IOException e) {
Log.e("get weather coordinates", "something went wrong: " + e.getMessage());
}
return null;
}
@Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
if (weatherInfo != null) {
holder.currentWeather.setText(String.valueOf(weatherInfo.getMain().getTemp()) + "\u2103");
getWeatherIcon(holder);
} else {
holder.currentWeather.setText("N/A \u2103");
Picasso.with(context).load("file:///android_asset/md-weather-iconset/weather-none-available.png").into(holder.weatherImg);
}
progressDialog.dismiss();
}
}
/**
* Display the correct weather icon from assets based on the data returned from the Retrofit query.
* @param viewHolder
*/
private void getWeatherIcon(ViewHolder viewHolder){
String base="file:///android_asset/md-weather-iconset";
switch (weatherInfo.getWeather().get(0).getIcon()) {
case "01d":
Picasso.with(context).load(base+"/weather-clear.png").into(viewHolder.weatherImg);
break;
case "02d":
Picasso.with(context).load(base+"/weather-few-clouds.png").into(viewHolder.weatherImg);
break;
case "03d":
Picasso.with(context).load(base+"/weather-clouds.png").into(viewHolder.weatherImg);
break;
case "04d":
Picasso.with(context).load(base+"/weather-clouds.png").into(viewHolder.weatherImg);
break;
case "09d":
Picasso.with(context).load(base+"/weather-showers-day.png").into(viewHolder.weatherImg);
break;
case "10d":
Picasso.with(context).load(base+"/weather-rain-day.png").into(viewHolder.weatherImg);
break;
case "11d":
Picasso.with(context).load(base+"/weather-storm-day.png").into(viewHolder.weatherImg);
break;
case "13d":
Picasso.with(context).load(base+"/weather-snow.png").into(viewHolder.weatherImg);
break;
case "50d":
Picasso.with(context).load(base+"/weather-mist.png").into(viewHolder.weatherImg);
break;
case "01n":
Picasso.with(context).load(base+"/weather-clear-night.png").into(viewHolder.weatherImg);
break;
case "02n":
Picasso.with(context).load(base+"/weather-few-clouds-night.png").into(viewHolder.weatherImg);
break;
case "03n":
Picasso.with(context).load(base+"/weather-clouds-night.png").into(viewHolder.weatherImg);
break;
case "04n":
Picasso.with(context).load(base+"/weather-clouds-night.png").into(viewHolder.weatherImg);
break;
case "09n":
Picasso.with(context).load(base+"/weather-showers-night.png").into(viewHolder.weatherImg);
break;
case "10n":
Picasso.with(context).load(base+"/weather-rain-night.png").into(viewHolder.weatherImg);
break;
case "11n":
Picasso.with(context).load(base+"/weather-storm-night.png").into(viewHolder.weatherImg);
break;
case "13n":
Picasso.with(context).load(base+"/weather-snow.png").into(viewHolder.weatherImg);
break;
case "50n":
Picasso.with(context).load(base+"/weather-mist.png").into(viewHolder.weatherImg);
break;
}
}
}
首先你能说清楚你的预期输出是什么吗?也许显示您的预期输出和您获得的输出的图像就足够了。我还建议您不要从适配器内部的网络获取,而是获取片段中的所有天气数据并将信息传递给 adapter.Lets 假设您有一个 Activity 持有 recyclerview。使用接口从适配器调用异步任务。
同时将纬度和经度存储在 viewholder 中,然后再次尝试查看是否有效。
您正在使用 onBindViewHolder()
启动异步任务并将对 holder
的引用传递给它。不幸的是,这不是 RecyclerView 应该工作的方式。 RecyclerView 使用 ViewHolder 模式重用已实例化但不再可见的布局,这就是为什么 holder 在网络响应启动时可能代表完全不同的项目。
您应该做的是将调用异步调用移动到其他地方(例如 Fragment/Activity/Presenter),从回调中更新您的 taskList
集合并使用以下方法之一通知适配器数据集已更改:
看看 RecyclerView.Adapter 文档:
问题是
private WeatherInfo weatherInfo;
在 AsyncTask 中创建 WeatherInfo 对象。这将解决您的问题。 AsyncTask 被执行,它将创建新的 WeatherInfo 对象。现在将该对象传递给方法 so。
像这样改变方法
getWeatherIcon(ViewHolder viewHolder,WeatherInfo wetherInfo)
这将解决您的问题。