notifyDataSetChanged no funciona en RecyclerView

Estoy obteniendo datos del servidor y luego analizándolos y almacenándolos en una lista. Estoy usando esta lista para el adaptador de RecyclerView. Estoy usando Fragmentos.

Estoy usando un Nexus 5 con KitKat. Estoy usando una biblioteca de soporte para esto. ¿Esto hará una diferencia?

Aquí está mi código: (Usando datos ficticios para la pregunta)

Variables del miembro:

List mBusinesses = new ArrayList(); RecyclerView recyclerView; RecyclerView.LayoutManager mLayoutManager; BusinessAdapter mBusinessAdapter; 

Mi 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; } 

Después de obtener datos del servidor, se llama a 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(); } 

Mi BusinessAdapter:

 public class BusinessAdapter extends RecyclerView.Adapter { private List mBusinesses = new ArrayList(); // 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 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; } } 

Pero no obtengo los datos mostrados en la vista. ¿Qué estoy haciendo mal?

Aquí está mi registro,

 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 

No obtengo ningún registro después de esto. ¿No debería getItemCount() en el adaptador de nuevo?

En su parseResponse() está creando una nueva instancia de la clase BusinessAdapter , pero no la está usando en ningún lugar, por lo que su RecyclerView no sabe que existe la nueva instancia.

Usted necesita:

  • Llame a recyclerView.setAdapter(mBusinessAdapter) nuevamente para actualizar la referencia del adaptador RecyclerView para que apunte a su nuevo
  • O simplemente elimine mBusinessAdapter = new BusinessAdapter(mBusinesses); para continuar usando el adaptador existente. Como no ha cambiado la referencia mBusinesses , el adaptador seguirá usando esa lista de arreglos y debería actualizarse correctamente cuando llame a notifyDataSetChanged() .

Prueba este método:

 List mBusinesses2 = mBusinesses; mBusinesses.clear(); mBusinesses.addAll(mBusinesses2); //and do the notification 

un poco de tiempo, pero debería funcionar.

Tuve el mismo problema Acabo de resolverlo declarando el adapter público antes de onCreate clase.

 PostAdapter postAdapter; 

después de esto

 postAdapter = new PostAdapter(getActivity(), posts); recList.setAdapter(postAdapter); 

al final he llamado:

 @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(); } 

Que esto te ayude.

Solo para complementar las otras respuestas, ya que no creo que nadie haya mencionado esto aquí: notifyDataSetChanged() debería ejecutarse en el hilo principal (otros métodos notify de RecyclerView.Adapter también, por supuesto)

Por lo que veo, ya que tiene los procedimientos de análisis sintáctico y la llamada a notifyDataSetChanged() en el mismo bloque, lo está llamando desde un hilo de trabajo, o está haciendo un análisis JSON en el hilo principal (que también es un no -no como estoy seguro tú lo sabes). Entonces, la forma correcta sería:

 protected void parseResponse(JSONArray response, String url) { // insert dummy data for demo //  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(); } }); 

}

PD Lo raro es que no creo que tengas ninguna indicación sobre el hilo principal de IDE o de los registros de tiempo de ejecución. Esto es solo por mis observaciones personales: si llamo notifyDataSetChanged() desde un hilo de trabajo, no obtengo el obligatorio Solo el hilo original que creó una jerarquía de vista puede tocar su mensaje de vista o algo por el estilo – simplemente falla silenciosamente (y en mi caso, una llamada fuera del hilo principal puede incluso evitar que las llamadas subsiguientes al hilo principal funcionen correctamente, probablemente debido a algún tipo de condición de carrera)

Además, ni la referencia de API RecyclerView.Adapter ni la guía de desarrollo oficial relevante mencionan explícitamente el requisito de hilo principal en este momento (el momento es 2017) y ninguna de las reglas de inspección de pelusas de Android Studio parece concernir este problema tampoco.

Pero, aquí hay una explicación de esto por el propio autor

Borre su viejo modelo de vista y establezca los datos nuevos en el adaptador y llame a notifyDataSetChanged()