Android: ListFragment refresh utilizando notifyDataSetChanged () con el adaptador personalizado no funciona

Estoy utilizando un ListFragment con un adaptador de lista personalizado y quiero actualizar la lista con un clic en un icono en el ActionBar. Desafortunadamente no funciona y no tengo ni idea de por qué.

Mi ItemListFragment:

@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Log.d("debug","Hallo in ItemListFragment"); //show ActionBar setHasOptionsMenu(true); //get reference to activity myApp = getActivity().getApplication(); //check if intent from ItemListActivity is null Bundle be = getActivity().getIntent().getExtras(); if (be == null){ //if null read local feed feed = ReadFeed(fileName); Log.d("debug", "Lese Feed lokal :"+feed); }else{ //else get extras from the intent feed = (RSSFeed) getActivity().getIntent().getExtras().get("feed"); Log.d("debug", "Intent von ItemListActivity an ItemListFragment vorhanden"); } } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { //inflate the fragment with the custom detail fragment View view = inflater.inflate(R.layout.feed_list, null); return view; } @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); //get listview from layout lv = getListView(); lv.setVerticalFadingEdgeEnabled(true); // Set custom list adapter to the ListView adapter = new CustomListAdapter(getActivity(), feed); lv.setAdapter(adapter); } //Inflate ActionBar @Override public void onCreateOptionsMenu(Menu optionsMenu, MenuInflater inflater) { inflater.inflate(R.menu.main, optionsMenu); } @Override public void onViewCreated(View view, Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); // Restore the previously serialized activated item position. if (savedInstanceState != null && savedInstanceState.containsKey(STATE_ACTIVATED_POSITION)) { setActivatedPosition(savedInstanceState.getInt(STATE_ACTIVATED_POSITION)); } } @Override public void onAttach(Activity activity) { super.onAttach(activity); // Activities containing this fragment must implement its callbacks. if (!(activity instanceof Callbacks)) { throw new IllegalStateException("Activity must implement fragment's callbacks."); } mCallbacks = (Callbacks) activity; } @Override public void onDetach() { super.onDetach(); // Reset the active callbacks interface to the dummy implementation. mCallbacks = sCallbacks; } @Override public void onListItemClick(ListView listView, View view, int position, long id) { super.onListItemClick(listView, view, position, id); // Notify the active callbacks interface (the activity, if the // fragment is attached to one) that an item has been selected. if (mCallbacks != null) { Log.d("debug","Callback in ItemListFragment mit Position: "+position+"und Feed: "+feed); mCallbacks.onItemSelected(position, feed); } } @Override public void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); if (mActivatedPosition != ListView.INVALID_POSITION) { // Serialize and persist the activated item position. outState.putInt(STATE_ACTIVATED_POSITION, mActivatedPosition); } } /** * Turns on activate-on-click mode. When this mode is on, list items will be * given the 'activated' state when touched. */ public void setActivateOnItemClick(boolean activateOnItemClick) { // When setting CHOICE_MODE_SINGLE, ListView will automatically // give items the 'activated' state when touched. getListView().setChoiceMode(activateOnItemClick ? ListView.CHOICE_MODE_SINGLE : ListView.CHOICE_MODE_NONE); } private void setActivatedPosition(int position) { if (position == ListView.INVALID_POSITION) { getListView().setItemChecked(mActivatedPosition, false); } else { getListView().setItemChecked(position, true); } mActivatedPosition = position; } //OnClick auf ActionBar @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case android.R.id.home: return true; case R.id.refresh_option: refreshList(item); return true; } return super.onOptionsItemSelected(item); } //Click on refresh in ActionBar -> Refresh the List public void refreshList(final MenuItem item) { /* Attach a rotating ImageView to the refresh item as an ActionView */ LayoutInflater inflater = (LayoutInflater) getActivity().getApplication() .getSystemService(Context.LAYOUT_INFLATER_SERVICE); ImageView iv = (ImageView) inflater.inflate(R.layout.action_refresh, null); Animation rotation = AnimationUtils.loadAnimation(getActivity(), R.anim.refresh_rotate); rotation.setRepeatCount(Animation.INFINITE); iv.startAnimation(rotation); item.setActionView(iv); // trigger feed refresh: Thread thread = new Thread(new Runnable() { @Override public void run() { DOMParser tmpDOMParser = new DOMParser(); feed = tmpDOMParser.parseXml("http://www.example.de/feed"); Log.d("debug", "Refresh Liste mit Feed: "+feed); ItemListFragment.this.getActivity().runOnUiThread(new Runnable() { @Override public void run() { if (feed != null && feed.getItemCount() > 0) { Log.d("debug", "Aktualisiere Liste"); adapter.notifyDataSetChanged(); item.getActionView().clearAnimation(); item.setActionView(null); } } }); } }); thread.start(); } @Override public void onDestroy() { super.onDestroy(); //TODO Datenverbrauch dadurch geringer? //adapter.imageLoader.clearCache(); adapter.notifyDataSetChanged(); } 

Mi CustomListAdapter.java

 public class CustomListAdapter extends BaseAdapter { private LayoutInflater layoutInflater; public ImageLoader imageLoader; public RSSFeed _feed; public CustomListAdapter(Activity activity, RSSFeed feed) { _feed = feed; layoutInflater = (LayoutInflater) activity .getSystemService(Context.LAYOUT_INFLATER_SERVICE); imageLoader = new ImageLoader(activity.getApplicationContext()); } @Override public int getCount() { // Set the total list item count return _feed.getItemCount(); } @Override public Object getItem(int position) { return position; } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { // Inflate the item layout and set the views View listItem = convertView; int pos = position; if (listItem == null) { listItem = layoutInflater.inflate(R.layout.list_item, null); } // Initialize the views in the layout ImageView iv = (ImageView) listItem.findViewById(R.id.thumb); TextView tvTitle = (TextView) listItem.findViewById(R.id.title); TextView tvDate = (TextView) listItem.findViewById(R.id.date); TextView tvDesc = (TextView) listItem.findViewById(R.id.description); // Set the views in the layout imageLoader.DisplayImage(_feed.getItem(pos).getImage(), iv); tvTitle.setText(_feed.getItem(pos).getTitle()); tvDate.setText(_feed.getItem(pos).getDate()); tvDesc.setText(_feed.getItem(pos).getShortDescription()); return listItem; } } 

Esta es la parte donde intento actualizar la lista:

  @Override public void run() { if (feed != null && feed.getItemCount() > 0) { Log.d("debug", "Aktualisiere Liste"); adapter.notifyDataSetChanged(); item.getActionView().clearAnimation(); item.setActionView(null); } } 

¿Dónde está mi error?

El código de actualización actual del adaptador no funcionará porque no está actualizando la referencia adecuada a los datos, aquél en el que se basa realmente el adaptador. Cuando llama a refreshList , crea ese hilo para analizar el xml y asigna los resultados a la variable de feed , sin embargo su adaptador tiene su propia referencia a los datos iniciales ( _feed ) que no se ve afectada por la asignación anterior así en el momento de la notifyDataSetChanged() llamará todavía verá los datos antiguos y no hará nada.

La solución es actualizar la referencia _feed del adaptador para que apunte al nuevo conjunto de resultados analizados y luego llame a notifyDataSetChanged() en el adaptador.

  Thread thread = new Thread(new Runnable() { @Override public void run() { DOMParser tmpDOMParser = new DOMParser(); feed = tmpDOMParser.parseXml("http://www.example.de/feed"); Log.d("debug", "Refresh Liste mit Feed: "+feed); ItemListFragment.this.getActivity().runOnUiThread(new Runnable() { @Override public void run() { if (feed != null && feed.getItemCount() > 0) { Log.d("debug", "Aktualisiere Liste"); // Set custom list adapter to the ListView adapter = new CustomListAdapter(getActivity(), feed); lv.setAdapter(adapter); adapter.notifyDataSetChanged(); item.getActionView().clearAnimation(); item.setActionView(null); } } }); } }); thread.start(); 

Y también en vez de refrescar el botón usted puede utilizar this.this le ayuda. Pulltorefresh

  • Hace notificydatasetchanged llamada onCreateViewHolder al usar RecyclerView
  • Cómo evitar la renovación de las celdas al llamar a notifyDataSetChanged () para PinterestLikeAdapterView?
  • ¿Por qué no "notifyDatasetChanged ()" notifica todos los elementos visibles?
  • NotifyDataSetChanged- RecyclerView -¿Es una llamada asincrónica?
  • RecyclerViewAdapter.notifyDataSetChanged () en una referencia de objeto nulo
  • Cómo añadir sugerencias dinámicamente a autocompletetextview con preservar el estado de los caracteres
  • Android ListView no se actualiza después de notifyDataSetChanged
  • ¿Quieres implementar notifyDataSetChanged o autorefresh a mi RecyclerView pero no funciona
  • Cómo actualizar algunos datos en un ListView sin utilizar notifyDataSetChanged ()?
  • El adaptador de RecyclerView notifyDataSetChanged no funciona
  • Using notifyItemRemoved o notifyDataSetChanged con RecyclerView en Android
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.