notifyDataSetChanged不能在RecyclerView上工作
我从服务器获取数据,然后parsing并将其存储在列表中。 我使用RecyclerView的适配器的这个列表。 我正在使用片段。
我正在用KitKat使用Nexus 5。 我正在使用支持库。 这会有所作为吗?
这里是我的代码:(使用虚拟数据的问题)
成员variables:
List<Business> mBusinesses = new ArrayList<Business>(); RecyclerView recyclerView; RecyclerView.LayoutManager mLayoutManager; BusinessAdapter mBusinessAdapter;
我的onCreateView()
:
@Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // Getting data from server getBusinessesDataFromServer(); View view = inflater.inflate(R.layout.fragment_business_list, container, false); recyclerView = (RecyclerView) view .findViewById(R.id.business_recycler_view); recyclerView.setHasFixedSize(true); mLayoutManager = new LinearLayoutManager(getActivity()); recyclerView.setLayoutManager(mLayoutManager); mBusinessAdapter = new BusinessAdapter(mBusinesses); recyclerView.setAdapter(mBusinessAdapter); return view; }
从服务器获取数据后,调用parseResponse()
。
protected void parseResponse(JSONArray response, String url) { // insert dummy data for demo mBusinesses.clear(); Business business; business = new Business(); business.setName("Google"); business.setDescription("Google HeadQuaters"); mBusinesses.add(business); business = new Business(); business.setName("Yahoo"); business.setDescription("Yahoo HeadQuaters"); mBusinesses.add(business); business = new Business(); business.setName("Microsoft"); business.setDescription("Microsoft HeadQuaters"); mBusinesses.add(business); Log.d(Const.DEBUG, "Dummy Data Inserted\nBusinesses Length: " + mBusinesses.size()); mBusinessAdapter = new BusinessAdapter(mBusinesses); mBusinessAdapter.notifyDataSetChanged(); }
我的商家:
public class BusinessAdapter extends RecyclerView.Adapter<BusinessAdapter.ViewHolder> { private List<Business> mBusinesses = new ArrayList<Business>(); // Provide a reference to the type of views that you are using // (custom viewholder) public static class ViewHolder extends RecyclerView.ViewHolder { public TextView mTextViewName; public TextView mTextViewDescription; public ImageView mImageViewLogo; public ViewHolder(View v) { super(v); mTextViewName = (TextView) v .findViewById(R.id.textView_company_name); mTextViewDescription = (TextView) v .findViewById(R.id.textView_company_description); mImageViewLogo = (ImageView) v .findViewById(R.id.imageView_company_logo); } } // Provide a suitable constructor (depends on the kind of dataset) public BusinessAdapter(List<Business> myBusinesses) { Log.d(Const.DEBUG, "BusinessAdapter -> constructor"); mBusinesses = myBusinesses; } // Create new views (invoked by the layout manager) @Override public BusinessAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { Log.d(Const.DEBUG, "BusinessAdapter -> onCreateViewHolder()"); // create a new view View v = LayoutInflater.from(parent.getContext()).inflate( R.layout.item_business_list, parent, false); ViewHolder vh = new ViewHolder(v); return vh; } // Replace the contents of a view (invoked by the layout manager) @Override public void onBindViewHolder(ViewHolder holder, int position) { // - get element from your dataset at this position // - replace the contents of the view with that element Log.d(Const.DEBUG, "BusinessAdapter -> onBindViewHolder()"); Business item = mBusinesses.get(position); holder.mTextViewName.setText(item.getName()); holder.mTextViewDescription.setText(item.getDescription()); holder.mImageViewLogo.setImageResource(R.drawable.ic_launcher); } // Return the size of your dataset (invoked by the layout manager) @Override public int getItemCount() { Log.d(Const.DEBUG, "BusinessAdapter -> getItemCount()"); if (mBusinesses != null) { Log.d(Const.DEBUG, "mBusinesses Count: " + mBusinesses.size()); return mBusinesses.size(); } return 0; } }
但是我没有看到在视图中显示的数据。 我究竟做错了什么?
这是我的日志,
07-14 21:15:35.669: D/xxx(2259): Dummy Data Inserted 07-14 21:15:35.669: D/xxx(2259): Businesses Length: 3 07-14 21:26:26.969: D/xxx(2732): BusinessAdapter -> constructor
在这之后我没有得到任何日志。 不应该再次调用适配器中的getItemCount()
吗?
在你的parseResponse()
你正在创build一个BusinessAdapter
类的新实例,但是实际上你并没有在任何地方使用它,所以你的RecyclerView
并不知道新的实例存在。
您或者需要:
- 再次调用
recyclerView.setAdapter(mBusinessAdapter)
以更新RecyclerView的适配器引用以指向新的 - 或者只是删除
mBusinessAdapter = new BusinessAdapter(mBusinesses);
继续使用现有的适配器。 由于您尚未更改mBusinesses
引用,所以适配器仍将使用该数组列表,并且在调用notifyDataSetChanged()
时应该正确更新。
试试这个方法:
List<Business> mBusinesses2 = mBusinesses; mBusinesses.clear(); mBusinesses.addAll(mBusinesses2); //and do the notification
有点费时,但是它应该工作。
我有同样的问题。 我只是在类的onCreate
之前声明adapter
public来解决它。
PostAdapter postAdapter;
之后
postAdapter = new PostAdapter(getActivity(), posts); recList.setAdapter(postAdapter);
最后我打电话给:
@Override protected void onPostExecute(Void aVoid) { super.onPostExecute(aVoid); // Display the size of your ArrayList Log.i("TAG", "Size : " + posts.size()); progressBar.setVisibility(View.GONE); postAdapter.notifyDataSetChanged(); }
愿这能帮助你。
只是为了补充其他答案,因为我不认为有人在这里提到这个: notifyDataSetChanged()
应该在主线程上执行 notifyDataSetChanged()
也可以 notify<Something>
RecyclerView.Adapter
notify<Something>
方法)
从我所收集的内容来看,由于您在同一个块中有parsing过程和对notifyDataSetChanged()
的调用, notifyDataSetChanged()
要么从工作线程调用它,要么在主线程上执行JSONparsing(这也是否定的不,因为我相信你知道)。 所以正确的方法是:
protected void parseResponse(JSONArray response, String url) { // insert dummy data for demo // <yadda yadda yadda> mBusinessAdapter = new BusinessAdapter(mBusinesses); // or just use recyclerView.post() or [Fragment]getView().post() // instead, but make sure views haven't been destroyed while you were // parsing new Handler(Looper.getMainLooper()).post(new Runnable() { public void run() { mBusinessAdapter.notifyDataSetChanged(); } });
}
PS奇怪的是,我不认为你从IDE或运行时日志得到有关主线程的任何迹象。 这只是从我个人的观察:如果我从工作者线程调用notifyDataSetChanged()
,我没有得到强制性只有创build一个视图层次结构的原始线程可以触摸它的视图消息或类似的东西 – 它只是失败(在我的情况下,一个脱离主线程调用甚至可以防止后续的主线程调用正常运行,可能是由于某种竞争条件)
此外, RecyclerView.Adapter API参考和相关的官方开发指南都没有明确提及目前的主线程要求(现在是2017年),Android Studio皮棉检测规则也没有涉及到这个问题。
但是, 这是作者自己对此的解释