Mein ListFragment-Code
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);
}
}
}
Meine 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>
Dies aktualisiert aber nicht die ListView
. Auch nach dem Neustart der App werden die aktualisierten Elemente nicht angezeigt. Mein ItemAdapter
erstreckt sichBaseAdapter
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;
}
}
Kann mir bitte jemand helfen?
adapter
Referenz erstellen, warum testen Sie es dann eine Zeile weiter unten auf Null?Antworten:
Schauen Sie sich Ihre
onResume
Methode an inItemFragment
:Was Sie gerade vor dem Aufruf aktualisiert haben,
notifyDataSetChanged()
ist nicht das Feld des Adapters,private List<Item> items;
sondern das identisch deklarierte Feld des Fragments. Der Adapter speichert weiterhin einen Verweis auf die Liste der Elemente, die Sie beim Erstellen des Adapters übergeben haben (z. B. in onCreate des Fragments). Die kürzeste (im Sinne der Anzahl der Änderungen), aber nicht elegante Möglichkeit, Ihren Code so zu verhalten, wie Sie es erwarten, besteht darin, einfach die Zeile zu ersetzen:mit
Eine elegantere Lösung:
1) Elemente entfernen
private List<Item> items;
vonItemFragment
- wir müssen nur im Adapter auf sie verweisen2) Ändern Sie onCreate in:
3) Methode in ItemAdapter hinzufügen:
4) Ändern Sie Ihren onResume in:
quelle
adapter.swapItems();
und der Adapter würde dasdbHelper.getItems()
Zeug erledigen . Aber trotzdem danke für die Antwort :)notifyDataSetChanged()
?Sie weisen globalen Variablenelementen in neu geladene Elemente zu
onResume()
, dies wird jedoch in derItemAdapter
Klasse nicht berücksichtigt , da es eine eigene Instanzvariable mit dem Namen "Elemente" gibt.Fügen
ListView
Sie zum Aktualisieren in derItemAdapter
Klasse ein refresh () hinzu , das Listendaten, dh Elemente, akzeptiertUpdate
onResume()
mit folgendem Codequelle
Ändern Sie in onResume () diese Zeile
zu
Das Problem ist, dass Sie Ihrem Adapter niemals von der Liste der neuen Elemente erzählen. Wenn Sie Ihrem Adapter keine neue Liste übergeben möchten (wie es scheint, tun Sie dies nicht), verwenden Sie sie einfach
items.addAll
nach Ihremclear()
. Dadurch wird sichergestellt, dass Sie dieselbe Liste ändern, auf die der Adapter verweist.quelle
adapter.clear()
der Adapter nicht zwingt zu erkennen, dass die Ansicht aktualisiert werden soll, aberadapter.add()
oderadapter.addAll()
. Danke für die Antwort!items.addAll()
adapter.addAll () verwendet habe und nicht. Das einzige, was den Adapter auf Änderungen reagieren lässt, ist dasnotifyDataSetChanged
. Der Grund, warum der Adapter überhaupt Änderungen sieht, ist, dass dieitems
Liste dieselbe Liste ist, die der Adapter verwendet.Wenn der Adapter bereits eingestellt ist, wird durch erneutes Einstellen die Listenansicht nicht aktualisiert. Überprüfen Sie stattdessen zuerst, ob die Listenansicht einen Adapter hat, und rufen Sie dann die entsprechende Methode auf.
Ich denke, es ist keine sehr gute Idee, beim Festlegen der Listenansicht eine neue Instanz des Adapters zu erstellen. Erstellen Sie stattdessen ein Objekt.
Sie können auch versuchen, die Aktualisierungsliste im UI-Thread auszuführen:
quelle
ItemAdapter
ist, dass ich die Zeilen einfärben möchte und in der Listenansicht mehrere Datenelemente angezeigt werden. Ich habe den Code für den Adapter gepostet.Wenn Sie Ihre Listenansicht aktualisieren möchten spielt keine Rolle , wenn Sie wollen , dass auf
onResume()
,onCreate()
oder in einer anderen Funktion, erste , was Sie zu erkennen ist , dass Sie nicht brauchen eine neue Instanz des Adapters, nur bevölkern erstellen die Arrays mit Ihren Daten wieder. Die Idee ist ähnlich:Abhängig von dieser Antwort sollten Sie dasselbe
List<Item>
in Ihrem verwendenFragment
. Bei Ihrer ersten Adapterinitialisierung füllen Sie Ihre Liste mit den Elementen und setzen den Adapter auf Ihre Listenansicht. Danach müssen Sie bei jeder Änderung Ihrer Artikel die Werte aus der Hauptposition löschenList<Item> items
und sie dann erneut mit Ihren neuen Artikeln füllen und aufrufennotifySetDataChanged();
.So funktioniert das : ).
quelle
Eine Antwort von AlexGo hat den Trick für mich getan:
Das Listen-Update hat bei mir zuvor funktioniert, als das Update von einem GUI-Ereignis ausgelöst wurde und sich somit im UI-Thread befand.
Wenn ich jedoch die Liste von einem anderen Ereignis / Thread aktualisiere, dh von einem Aufruf von außerhalb der App, befindet sich das Update nicht im UI-Thread und ignoriert den Aufruf von getListView. Das Aufrufen des Updates mit runOnUiThread wie oben hat den Trick für mich getan. Vielen Dank!!
quelle
Versuche dies
quelle
Versuchen Sie dies in der
onPause()
Methode der Aktivitätsklasse.quelle
sollte den Trick machen.
quelle
Wenn Ihre Liste im Adapter selbst enthalten ist, sollte auch der Aufruf der Funktion zum Aktualisieren der Liste aufgerufen werden
notifyDataSetChanged()
.Das Ausführen dieser Funktion über den UI-Thread hat den Trick für mich getan:
Die
refresh()
Funktion im AdapterFühren Sie diese Funktion dann wiederum über den UI-Thread aus
quelle
Versuchen Sie es so:
anstatt:
Sie müssen
notifyDataSetChanged()
auf dieListView
nicht mit dem Adapter - Klasse.quelle