recyclerview - listview android personalizado
Android ListView no se actualiza después de notifyDataSetChanged (11)
En onResume () cambie esta línea
items = dbHelper.getItems(); //reload the items from database
a
items.addAll(dbHelper.getItems()); //reload the items from database
El problema es que nunca le dices a tu adaptador sobre la nueva lista de elementos. Si no desea pasar una nueva lista a su adaptador (como parece que no), simplemente use items.addAll
después de su clear()
. Esto asegurará que esté modificando la misma lista a la que hace referencia el adaptador.
Mi código ListFragment
public class ItemFragment extends ListFragment {
private DatabaseHandler dbHelper;
private static final String TITLE = "Items";
private static final String LOG_TAG = "debugger";
private ItemAdapter adapter;
private List<Item> items;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.item_fragment_list, container, false);
return view;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.setHasOptionsMenu(true);
super.onCreate(savedInstanceState);
getActivity().setTitle(TITLE);
dbHelper = new DatabaseHandler(getActivity());
items = dbHelper.getItems();
adapter = new ItemAdapter(getActivity().getApplicationContext(), items);
this.setListAdapter(adapter);
}
@Override
public void onResume() {
super.onResume();
items.clear();
items = dbHelper.getItems(); //reload the items from database
adapter.notifyDataSetChanged();
}
@Override
public void onListItemClick(ListView l, View v, int position, long id) {
super.onListItemClick(l, v, position, id);
if(dbHelper != null) { //item is edited
Item item = (Item) this.getListAdapter().getItem(position);
Intent intent = new Intent(getActivity(), AddItemActivity.class);
intent.putExtra(IntentConstants.ITEM, item);
startActivity(intent);
}
}
}
Mi ListView
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<ListView
android:id="@android:id/list"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
</LinearLayout>
Pero esto no actualiza el ListView
. Incluso después de reiniciar la aplicación, los elementos actualizados no se muestran. My ItemAdapter
amplía BaseAdapter
public class ItemAdapter extends BaseAdapter{
private LayoutInflater inflater;
private List<Item> items;
private Context context;
public ProjectListItemAdapter(Context context, List<Item> items) {
super();
inflater = LayoutInflater.from(context);
this.context = context;
this.items = items;
}
@Override
public int getCount() {
return items.size();
}
@Override
public Object getItem(int position) {
return items.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ItemViewHolder holder = null;
if(convertView == null) {
holder = new ItemViewHolder();
convertView = inflater.inflate(R.layout.list_item, parent,false);
holder.itemName = (TextView) convertView.findViewById(R.id.topText);
holder.itemLocation = (TextView) convertView.findViewById(R.id.bottomText);
convertView.setTag(holder);
} else {
holder = (ItemViewHolder) convertView.getTag();
}
holder.itemName.setText("Name: " + items.get(position).getName());
holder.itemLocation.setText("Location: " + items.get(position).getLocation());
if(position % 2 == 0) {
convertView.setBackgroundColor(context.getResources().getColor(R.color.evenRowColor));
} else {
convertView.setBackgroundColor(context.getResources().getColor(R.color.oddRowColor));
}
return convertView;
}
private static class ItemViewHolder {
TextView itemName;
TextView itemLocation;
}
}
¿Puede alguien ayudar, por favor?
Está asignando elementos recargados a elementos de variables globales en onResume()
, pero esto no se reflejará en la clase ItemAdapter
, ya que tiene su propia variable de instancia llamada ''items''.
Para actualizar ListView
, agregue una actualización () en la clase ItemAdapter
que acepta datos de la lista, es decir, elementos
class ItemAdapter
{
.....
public void refresh(List<Item> items)
{
this.items = items;
notifyDataSetChanged();
}
}
actualizar onResume()
con el siguiente código
@Override
public void onResume()
{
super.onResume();
items.clear();
items = dbHelper.getItems(); //reload the items from database
**adapter.refresh(items);**
}
Mire su método ItemFragment
en ItemFragment
:
@Override
public void onResume() {
super.onResume();
items.clear();
items = dbHelper.getItems(); // reload the items from database
adapter.notifyDataSetChanged();
}
lo que acaba de actualizar antes de llamar a notifyDataSetChanged()
no es el campo private List<Item> items;
del adaptador elementos de private List<Item> items;
pero el campo idénticamente declarado del fragmento. El adaptador aún almacena una referencia a la lista de elementos que pasó cuando creó el adaptador (por ejemplo, en el fragmento onCreate). La forma más corta (en el sentido de número de cambios) pero no elegante para hacer que su código se comporte como espera es simplemente reemplazar la línea:
items = dbHelper.getItems(); // reload the items from database
con
items.addAll(dbHelper.getItems()); // reload the items from database
Una solución más elegante:
1) eliminar elementos ítems de private List<Item> items;
from ItemFragment
- necesitamos mantener referencia a ellos solo en el adaptador
2) cambiar onCreate a:
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
super.setHasOptionsMenu(true);
getActivity().setTitle(TITLE);
dbHelper = new DatabaseHandler(getActivity());
adapter = new ItemAdapter(getActivity(), dbHelper.getItems());
setListAdapter(adapter);
}
3) agregar método en ItemAdapter:
public void swapItems(List<Item> items) {
this.items = items;
notifyDataSetChanged();
}
4) cambie su onResume a:
@Override
public void onResume() {
super.onResume();
adapter.swapItems(dbHelper.getItems());
}
Prueba esto
@Override
public void onResume() {
super.onResume();
items.clear();
items = dbHelper.getItems(); //reload the items from database
adapter = new ItemAdapter(getActivity(), items);//reload the items from database
adapter.notifyDataSetChanged();
}
Pruebe de esta manera:
this.notifyDataSetChanged();
en lugar de:
adapter.notifyDataSetChanged();
notifyDataSetChanged()
a ListView
no a la clase de adaptador.
Si desea actualizar su lista de listas no importa si desea hacer eso en onResume()
, onCreate()
o en alguna otra función, lo primero que debe tener en cuenta es que no necesitará crear una nueva instancia del adaptador, vuelva a llenar las matrices con sus datos. La idea es algo similar a esto:
private ArrayList<String> titles;
private MyListAdapter adapter;
private ListView myListView;
@Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.main_activity);
myListView = (ListView) findViewById(R.id.my_list);
titles = new ArrayList<String>()
for(int i =0; i<20;i++){
titles.add("Title "+i);
}
adapter = new MyListAdapter(this, titles);
myListView.setAdapter(adapter);
}
@Override
public void onResume(){
super.onResume();
// first clear the items and populate the new items
titles.clear();
for(int i =0; i<20;i++){
titles.add("New Title "+i);
}
adapter.notifySetDataChanged();
}
Entonces, dependiendo de esa respuesta, debería usar la misma List<Item>
en su Fragment
. En su primera inicialización de adaptador, completa su lista con los elementos y configura el adaptador a su vista de lista. Después de eso, en cada cambio en sus artículos, debe borrar los valores de los elementos principales de la List<Item> items
y luego rellenarlos nuevamente con sus nuevos elementos y llamar a notifySetDataChanged();
.
Asi es como funciona : ).
Si el adaptador ya está configurado, al configurarlo nuevamente no actualizará la vista de lista. En su lugar, primero compruebe si la vista de lista tiene un adaptador y luego llame al método apropiado.
Creo que no es una buena idea crear una nueva instancia del adaptador al configurar la vista de lista. En cambio, crea un objeto.
BuildingAdapter adapter = new BuildingAdapter(context);
if(getListView().getAdapter() == null){ //Adapter not set yet.
setListAdapter(adapter);
}
else{ //Already has an adapter
adapter.notifyDataSetChanged();
}
También puede intentar ejecutar la lista de actualización en el subproceso UI:
activity.runOnUiThread(new Runnable() {
public void run() {
//do your modifications here
// for example
adapter.add(new Object());
adapter.notifyDataSetChanged()
}
});
Si su lista está contenida en el Adaptador mismo, llamar a la función que actualiza la lista también debe llamar a notifyDataSetChanged()
.
Ejecutar esta función desde el subproceso UI me funcionó:
La función refresh()
dentro del Adaptador
public void refresh(){
//manipulate list
notifyDataSetChanged();
}
Luego, a su vez ejecuta esta función desde el subproceso UI
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
adapter.refresh()
}
});
Una respuesta de AlexGo hizo el truco para mí:
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
messages.add(m);
adapter.notifyDataSetChanged();
getListView().setSelection(messages.size()-1);
}
});
La Actualización de lista me funcionó antes cuando la actualización se desencadenó a partir de un evento GUI, por lo que se encontraba en el hilo de la interfaz de usuario.
Sin embargo, cuando actualizo la lista desde otro evento / subproceso, es decir, una llamada desde fuera de la aplicación, la actualización no estaría en el hilo de la interfaz de usuario e ignoró la llamada a getListView. Llamar a la actualización con runOnUiThread como arriba hizo el truco para mí. ¡¡Gracias!!
adapter.setNotifyDataChanged()
debería hacer el truco.
adpter.notifyDataSetInvalidated();
Pruebe esto en el método onPause()
de la clase Activity.