Mój kod 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);
}
}
}
Mój 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>
Ale to nie odświeża ListView
. Nawet po ponownym uruchomieniu aplikacji zaktualizowane elementy nie są wyświetlane. Moje ItemAdapter
przedłużeniaBaseAdapter
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;
}
}
Czy ktoś może pomóc?
adapter
odniesienia, dlaczego testujesz go pod kątem zerowej jednej linii poniżej?Odpowiedzi:
Spójrz na swoją
onResume
metodę wItemFragment
:to, co właśnie zaktualizowałeś przed wywołaniem,
notifyDataSetChanged()
nie jest polem adaptera,private List<Item> items;
ale identycznie zadeklarowanym polem fragmentu. Adapter nadal przechowuje odniesienie do listy elementów przekazanych podczas tworzenia adaptera (np. W onCreate fragmentu). Najkrótszym (w sensie liczby zmian), ale niezbyt eleganckim sposobem, aby kod zachowywał się zgodnie z oczekiwaniami, jest po prostu zastąpienie linii:z
Bardziej eleganckie rozwiązanie:
1) usuń elementy
private List<Item> items;
zItemFragment
- odwołanie do nich musimy zachować tylko w adapterze2) Zmień na Utwórz do:
3) dodaj metodę w ItemAdapter:
4) zmień swój onResume na:
źródło
adapter.swapItems();
a adapter zrobidbHelper.getItems()
wszystko. W każdym razie dzięki za odpowiedź :)notifyDataSetChanged()
?Przypisujesz ponownie załadowane elementy do elementów zmiennych globalnych w programie
onResume()
, ale nie będzie to odzwierciedlane wItemAdapter
klasie, ponieważ ma własną zmienną instancji o nazwie „items”.Aby odświeżyć
ListView
, dodaj refresh () wItemAdapter
klasie, która akceptuje dane listy, czyli elementyaktualizacja za
onResume()
pomocą następującego koduźródło
W onResume () zmień tę linię
do
Problem polega na tym, że nigdy nie mówisz adapterowi o liście nowych elementów. Jeśli nie chcesz przekazywać nowej listy do adaptera (wydaje się, że nie), po prostu użyj
items.addAll
poclear()
. Zapewni to modyfikację tej samej listy, do której odwołuje się adapter.źródło
adapter.clear()
nie zmusza adaptera do uświadomienia sobie, że widok powinien się odświeżyć, aleadapter.add()
lub tak sięadapter.addAll()
dzieje. Ale dzięki za odpowiedź!items.addAll()
a nie adapter.addAll (). Jedyną rzeczą, która pozwala adapterowi reagować na zmiany, jest pliknotifyDataSetChanged
. Adapter widzi w ogóle zmiany, ponieważitems
jest to ta sama lista, której używa adapter.Jeśli adapter jest już ustawiony, ponowne ustawienie nie spowoduje odświeżenia widoku listy. Zamiast tego najpierw sprawdź, czy listview ma adapter, a następnie wywołaj odpowiednią metodę.
Myślę, że tworzenie nowej instancji adaptera podczas ustawiania widoku listy nie jest dobrym pomysłem. Zamiast tego utwórz obiekt.
Możesz także spróbować uruchomić listę odświeżania w wątku interfejsu użytkownika:
źródło
ItemAdapter
jest to, że chcę pokolorować wiersze, a widok listy wyświetla wiele elementów danych. Wysłałem kod adaptera.Jeśli chcesz zaktualizować swój widok listy, nie ma znaczenia, czy chcesz to zrobić w innej funkcji
onResume()
,onCreate()
czy w innej, pierwszą rzeczą, którą musisz zdać sobie sprawę, jest to, że nie musisz tworzyć nowej instancji adaptera, po prostu wypełnij tablice z twoimi danymi ponownie. Pomysł jest podobny do tego:Więc w zależności od tej odpowiedzi powinieneś użyć tego samego
List<Item>
w swoimFragment
. Podczas pierwszej inicjalizacji karty należy wypełnić listę elementami i ustawić adapter w widoku listy. Następnie przy każdej zmianie w elementach musisz usunąć wartości z głównego,List<Item> items
a następnie wypełnić go ponownie nowymi elementami i zadzwonićnotifySetDataChanged();
.Tak to działa : ).
źródło
Odpowiedź od AlexGo załatwiła mi sprawę:
Aktualizacja listy działała wcześniej, gdy aktualizacja została wyzwolona ze zdarzenia GUI, a zatem znajdowała się w wątku interfejsu użytkownika.
Jednak gdy zaktualizuję listę z innego zdarzenia / wątku - tj. Wywołanie spoza aplikacji, aktualizacja nie pojawi się w wątku interfejsu użytkownika i zignoruje wywołanie getListView. Wywołanie aktualizacji za pomocą runOnUiThread jak powyżej załatwiło sprawę. Dzięki!!
źródło
Spróbuj tego
źródło
Spróbuj tego w
onPause()
metodzie klasy Activity.źródło
powinien załatwić sprawę.
źródło
Jeśli lista znajduje się w samym adapterze, należy również wywołać funkcję aktualizującą listę
notifyDataSetChanged()
.Uruchomienie tej funkcji z poziomu wątku interfejsu użytkownika załatwiło sprawę:
refresh()
Funkcja wewnątrz zasilaczaNastępnie z kolei uruchom tę funkcję z poziomu wątku interfejsu użytkownika
źródło
Spróbuj tak:
zamiast:
Trzeba
notifyDataSetChanged()
się doListView
nie do klasy adaptera.źródło