notifyDataSetChanged ne fonctionne pas sur RecyclerView
Je suis l'obtention de données de serveur, puis de l'analyser et de le stocker dans une Liste. Je suis l'aide de cette liste pour la RecyclerView de l'adaptateur. Je suis à l'aide de Fragments.
J'utilise un Nexus 5 avec KitKat. Je suis en utilisant la bibliothèque de prise en charge pour cela. Cela fera une différence?
Voici mon code: (à l'Aide de données factices pour la question)
Les Variables Membres:
List<Business> mBusinesses = new ArrayList<Business>();
RecyclerView recyclerView;
RecyclerView.LayoutManager mLayoutManager;
BusinessAdapter mBusinessAdapter;
Mon 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;
}
Après l'obtention de données de serveur, parseResponse()
est appelé.
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();
}
Mon BusinessAdapter:
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;
}
}
Mais je n'ai pas les données affichées dans la vue. Ce que je fais mal?
Voici mon journal,
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
Je ne reçois pas tous les journaux après ce. Ne devrait pas getItemCount()
dans l'adaptateur doit être appelé de nouveau?
Vous devez vous connecter pour publier un commentaire.
Dans votre
parseResponse()
vous créez une nouvelle instance de laBusinessAdapter
classe, mais vous n'êtes pas réellement l'utiliser n'importe où, de sorte que votreRecyclerView
ne sais pas la nouvelle instance existe.Vous devez soit:
recyclerView.setAdapter(mBusinessAdapter)
pour mettre à jour le RecyclerView de la carte de référence pour pointer vers votre nouveaumBusinessAdapter = new BusinessAdapter(mBusinesses);
de continuer à utiliser la carte existante. Puisque vous n'avez pas changé lemBusinesses
de référence, la carte utilise encore ce tableau liste et devrait mettre à jour correctement lorsque vous appeleznotifyDataSetChanged()
.int index = list.indexOf(object)
et de l'index, vous pouvez les informer des données à l'aideadapter.notifyItemChanged(index)
Essayez cette méthode:
un peu de temps, mais il devrait fonctionner.
J'ai eu le même problème. Je viens de résoudre avec déclarer
adapter
public avantonCreate
de classe.après que
à la dernière j'ai appelé:
Peut que cela vous aide.
Juste pour compléter les autres réponses, que je ne pense pas que quiconque mentionné ici:
notifyDataSetChanged()
doit être exécuté sur le thread principal (autresnotify<Something>
méthodes deRecyclerView.Adapter
ainsi, bien sûr)De ce que je comprends, puisque vous avez de l'analyse des procédures et de l'appel à
notifyDataSetChanged()
dans le même bloc, soit vous appelez à partir d'un thread de travail, ou que vous faites JSON analyse sur le thread principal (qui est aussi un non-non, je suis sûr que vous le savez). Donc la bonne façon serait:}
PS chose Étrange est, je ne pense pas que vous obtenez des indications sur le thread principal chose d'IDE ou de l'exécution des journaux. C'est seulement à partir de mes observations personnelles: si je fais appel
notifyDataSetChanged()
à partir d'un thread de travail, je n'ai pas l'obligation de Seul le thread qui a créé un point de vue de la hiérarchie peut toucher son point de vue message ou quelque chose comme ça - il est juste échoue silencieusement (et dans mon cas, un hors-main-fil appel peut même les empêcher de réussir main-d'appels de fil de fonctionner correctement, probablement à cause d'une sorte de " race condition)De plus, ni le RecyclerView.Carte de référence de l'api ni le dev guide mentionner explicitement le thread principal exigence pour l'instant (l'instant en 2017) et aucun des Android Studio peluches inspection règles semblent porter sur cette question.
Mais, voici une explication par l'auteur lui-même
Effacer votre ancien viewmodel et de définir les nouvelles données de la carte et de les appeler
notifyDataSetChanged()
Je vais juste ajouter à la @pradeep kumar réponse. Oui, le
notifyDataSetChanged
ne fonctionne pas vraiment, sans fixer de nouvelles valeurs à la carte. Donc, vous devriez:Ce qui a fonctionné pour moi.