ViewHolder的数据已经绑定了,为什么widgets不更新?
ViewHolder's data has been bound but why aren't the widgets updating?
我们的 MainActivity 的 TabLayout 实例化了这个 Fragment,它有一个 RecyclerView,每个单独的项目都是一个 CardView。从后端服务器检索数据并更新适配器。 Adapter 绑定到 ViewHolder,ViewHolder 应该使用服务器的数据更新每个 CardView 的小部件。
这是愿景,但 ViewHolder 没有更新 CardView 的 TextView 小部件。它仍然显示布局中的默认硬编码值 xml。
为了测试,我在 Adapter 和 ViewHolder 中添加了断点和 Log 语句并逐步执行。一切看起来都很好。
无论我在哪里放置 Log 语句,它都会记录正确的数据。
如果数据绑定看起来很好并且没有其他错误,那么为什么 ViewHolder 的 bindModel 方法不更新 TextView?
public class ModelsFragment extends Fragment {
private final String API_KEY = "INSERT API KEY HERE";
private static final String ARG_CATEGORY = "model_category";
private String mCategory;
private RecyclerView mModelRecyclerView;
private ModelAdapter mModelAdapter;
private List<Model> mModels;
public static Fragment newInstance(String category) {
Bundle args = new Bundle();
args.putString(ARG_CATEGORY, category);
ModelsFragment modelsFragment = new ModelsFragment();
modelsFragment.setArguments(args);
return modelsFragment;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mCategory = getArguments().getString(ARG_CATEGORY);
final ProgressDialog progressDialog = new ProgressDialog(getActivity(), R.style.ProgressDialogTheme);
progressDialog.setCancelable(false);
progressDialog.setProgressStyle(android.R.style.Widget_ProgressBar);
progressDialog.show();
EdmundsService service = EdmundsServiceGenerator.createService(EdmundsService.class);
Map<String, String> options = new HashMap<>();
options.put("state", "new");
options.put("year", "2016");
options.put("view", "basic");
options.put("api_key", API_KEY);
if (mCategory != null) {
options.put("category", mCategory);
}
// Use the hash map to actually query the backend API server with a GET request.
Call<Models> call = service.getModels(options);
call.enqueue(new Callback<Models>() {
@Override
public void onResponse(Call<Models> call, Response<Models> response) {
if (response.isSuccessful()) {
mModels = response.body().getModels();
progressDialog.dismiss();
updateUI();
Log.i("GET Status", "Successfully retrieved data");
Log.i("GET Status", response.body().getModelsCount().toString());
}
else {
Log.i("GET Status", "Failed to retrieve data");
}
}
@Override
public void onFailure(Call<Models> call, Throwable t) {
Log.e("Error retrieving data", t.getMessage());
}
});
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
mModelRecyclerView = (RecyclerView) inflater.inflate(R.layout.fragment_models, container, false);
mModelRecyclerView.setHasFixedSize(true);
mModelRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
updateUI();
return mModelRecyclerView;
}
private void updateUI() {
mModelAdapter = new ModelAdapter(mModels);
mModelRecyclerView.setAdapter(mModelAdapter);
}
public class ModelHolder extends RecyclerView.ViewHolder {
private Model model;
private TextView mName;
public ModelHolder(LayoutInflater inflater, ViewGroup parent) {
super(inflater.inflate(R.layout.fragment_models_card_view_item, parent, false));
View view = inflater.inflate(R.layout.fragment_models_card_view_item, parent, false);
mName = (TextView) view.findViewById(R.id.card_view_name);
}
public void bindModel(Model model) {
this.model = model;
// This if statement added to prevent null object reference errors.
if (this.model != null) {
// Data correctly logged.
Log.i("Inside IF statement", this.model.getName());
mName.setText(this.model.getName()); // Why doesn't this update?
}
// Data correctly logged.
Log.i("Bound model", String.valueOf(this.model.getName()));
}
}
public class ModelAdapter extends RecyclerView.Adapter<ModelHolder> {
// Set number of Cards in the recycler view.
private List<Model> models;
public ModelAdapter(List<Model> models) {
this.models = models;
}
@Override
public ModelHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return new ModelHolder(LayoutInflater.from(parent.getContext()), parent);
}
@Override
public void onBindViewHolder(ModelHolder holder, int position) {
// For our list of models, get one model by position and bind it to our view holder class.
Model model = models.get(position);
Log.i("Just prior to binding", model.getName());
holder.bindModel(model);
}
@Override
public int getItemCount() {
return models == null ? 0 : models.size();
}
}
}
您在 ModelHolder
中夸大了 2 个视图
public ModelHolder(LayoutInflater inflater, ViewGroup parent) {
super(inflater.inflate(R.layout.fragment_models_card_view_item, parent, false));
View view = inflater.inflate(R.layout.fragment_models_card_view_item, parent, false);
mName = (TextView) view.findViewById(R.id.card_view_name);
}
你传递给super调用的视图就是你正在显示的视图。之后您正在膨胀的视图未显示(并且是您用来查找 mName
的视图),这就是您看不到更改的原因。您应该只膨胀一个视图并将其传递到 ModelHolder
,这样您就可以搜索您的 R.id.card_view_name
视图。
例如。
public ModelHolder(View view) {
super(view);
mName = (TextView) view.findViewById(R.id.card_view_name);
}
并在适配器 onCreateViewHolder
@Override
public ModelHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.fragment_models_card_view_item, parent, false);
return new ModelHolder(view);
}
我们的 MainActivity 的 TabLayout 实例化了这个 Fragment,它有一个 RecyclerView,每个单独的项目都是一个 CardView。从后端服务器检索数据并更新适配器。 Adapter 绑定到 ViewHolder,ViewHolder 应该使用服务器的数据更新每个 CardView 的小部件。
这是愿景,但 ViewHolder 没有更新 CardView 的 TextView 小部件。它仍然显示布局中的默认硬编码值 xml。
为了测试,我在 Adapter 和 ViewHolder 中添加了断点和 Log 语句并逐步执行。一切看起来都很好。
无论我在哪里放置 Log 语句,它都会记录正确的数据。
如果数据绑定看起来很好并且没有其他错误,那么为什么 ViewHolder 的 bindModel 方法不更新 TextView?
public class ModelsFragment extends Fragment {
private final String API_KEY = "INSERT API KEY HERE";
private static final String ARG_CATEGORY = "model_category";
private String mCategory;
private RecyclerView mModelRecyclerView;
private ModelAdapter mModelAdapter;
private List<Model> mModels;
public static Fragment newInstance(String category) {
Bundle args = new Bundle();
args.putString(ARG_CATEGORY, category);
ModelsFragment modelsFragment = new ModelsFragment();
modelsFragment.setArguments(args);
return modelsFragment;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mCategory = getArguments().getString(ARG_CATEGORY);
final ProgressDialog progressDialog = new ProgressDialog(getActivity(), R.style.ProgressDialogTheme);
progressDialog.setCancelable(false);
progressDialog.setProgressStyle(android.R.style.Widget_ProgressBar);
progressDialog.show();
EdmundsService service = EdmundsServiceGenerator.createService(EdmundsService.class);
Map<String, String> options = new HashMap<>();
options.put("state", "new");
options.put("year", "2016");
options.put("view", "basic");
options.put("api_key", API_KEY);
if (mCategory != null) {
options.put("category", mCategory);
}
// Use the hash map to actually query the backend API server with a GET request.
Call<Models> call = service.getModels(options);
call.enqueue(new Callback<Models>() {
@Override
public void onResponse(Call<Models> call, Response<Models> response) {
if (response.isSuccessful()) {
mModels = response.body().getModels();
progressDialog.dismiss();
updateUI();
Log.i("GET Status", "Successfully retrieved data");
Log.i("GET Status", response.body().getModelsCount().toString());
}
else {
Log.i("GET Status", "Failed to retrieve data");
}
}
@Override
public void onFailure(Call<Models> call, Throwable t) {
Log.e("Error retrieving data", t.getMessage());
}
});
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
mModelRecyclerView = (RecyclerView) inflater.inflate(R.layout.fragment_models, container, false);
mModelRecyclerView.setHasFixedSize(true);
mModelRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
updateUI();
return mModelRecyclerView;
}
private void updateUI() {
mModelAdapter = new ModelAdapter(mModels);
mModelRecyclerView.setAdapter(mModelAdapter);
}
public class ModelHolder extends RecyclerView.ViewHolder {
private Model model;
private TextView mName;
public ModelHolder(LayoutInflater inflater, ViewGroup parent) {
super(inflater.inflate(R.layout.fragment_models_card_view_item, parent, false));
View view = inflater.inflate(R.layout.fragment_models_card_view_item, parent, false);
mName = (TextView) view.findViewById(R.id.card_view_name);
}
public void bindModel(Model model) {
this.model = model;
// This if statement added to prevent null object reference errors.
if (this.model != null) {
// Data correctly logged.
Log.i("Inside IF statement", this.model.getName());
mName.setText(this.model.getName()); // Why doesn't this update?
}
// Data correctly logged.
Log.i("Bound model", String.valueOf(this.model.getName()));
}
}
public class ModelAdapter extends RecyclerView.Adapter<ModelHolder> {
// Set number of Cards in the recycler view.
private List<Model> models;
public ModelAdapter(List<Model> models) {
this.models = models;
}
@Override
public ModelHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return new ModelHolder(LayoutInflater.from(parent.getContext()), parent);
}
@Override
public void onBindViewHolder(ModelHolder holder, int position) {
// For our list of models, get one model by position and bind it to our view holder class.
Model model = models.get(position);
Log.i("Just prior to binding", model.getName());
holder.bindModel(model);
}
@Override
public int getItemCount() {
return models == null ? 0 : models.size();
}
}
}
您在 ModelHolder
public ModelHolder(LayoutInflater inflater, ViewGroup parent) {
super(inflater.inflate(R.layout.fragment_models_card_view_item, parent, false));
View view = inflater.inflate(R.layout.fragment_models_card_view_item, parent, false);
mName = (TextView) view.findViewById(R.id.card_view_name);
}
你传递给super调用的视图就是你正在显示的视图。之后您正在膨胀的视图未显示(并且是您用来查找 mName
的视图),这就是您看不到更改的原因。您应该只膨胀一个视图并将其传递到 ModelHolder
,这样您就可以搜索您的 R.id.card_view_name
视图。
例如。
public ModelHolder(View view) {
super(view);
mName = (TextView) view.findViewById(R.id.card_view_name);
}
并在适配器 onCreateViewHolder
@Override
public ModelHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.fragment_models_card_view_item, parent, false);
return new ModelHolder(view);
}