Mon code de liste
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);
}
}
}
Mon 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>
Mais cela ne rafraîchit pas la ListView
. Même après le redémarrage de l'application, les éléments mis à jour ne sont pas affichés. Ma ItemAdapter
s'étend 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;
}
}
Quelqu'un peut aider s'il vous plaît?
Regardez votre méthode onResume
dans ItemFragment
:
@Override
public void onResume() {
super.onResume();
items.clear();
items = dbHelper.getItems(); // reload the items from database
adapter.notifyDataSetChanged();
}
ce que vous venez de mettre à jour avant d'appeler notifyDataSetChanged()
n'est pas le champ private List<Item> items;
de l'adaptateur, mais le champ du même fragment déclaré. L’adaptateur conserve toujours une référence à la liste des éléments que vous avez transmis lors de la création de l’adaptateur (par exemple, dans fragment onCreate) . simplement pour remplacer la ligne:
items = dbHelper.getItems(); // reload the items from database
avec
items.addAll(dbHelper.getItems()); // reload the items from database
Une solution plus élégante:
1) supprimer les éléments private List<Item> items;
de ItemFragment
- nous devons garder la référence à eux uniquement dans l'adaptateur
2) changer onCreate pour:
@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) ajouter une méthode dans ItemAdapter:
public void swapItems(List<Item> items) {
this.items = items;
notifyDataSetChanged();
}
4) changez votre onResume pour:
@Override
public void onResume() {
super.onResume();
adapter.swapItems(dbHelper.getItems());
}
Vous affectez des éléments rechargés à des éléments de variable globale dans onResume()
, mais cela ne sera pas reflété dans la classe ItemAdapter
, car elle possède sa propre variable d'instance appelée 'éléments'.
Pour actualiser ListView
, ajoutez un refresh () dans la classe ItemAdapter
qui accepte les données de liste, c'est-à-dire les éléments.
class ItemAdapter
{
.....
public void refresh(List<Item> items)
{
this.items = items;
notifyDataSetChanged();
}
}
mettre à jour onResume()
avec le code suivant
@Override
public void onResume()
{
super.onResume();
items.clear();
items = dbHelper.getItems(); //reload the items from database
**adapter.refresh(items);**
}
Dans onResume () changez cette ligne
items = dbHelper.getItems(); //reload the items from database
à
items.addAll(dbHelper.getItems()); //reload the items from database
Le problème est que vous ne dites jamais à votre adaptateur la nouvelle liste d'éléments. Si vous ne souhaitez pas transmettre une nouvelle liste à votre adaptateur (comme il semble que vous n'en ayez pas), utilisez simplement items.addAll
après votre clear()
. Cela garantira que vous modifiez la même liste que celle de l'adaptateur.
Si vous voulez mettre à jour votre liste, peu importe si vous voulez le faire sur onResume()
, onCreate()
ou dans une autre fonction, vous devez d'abord vous rendre compte que vous n'avez pas besoin de créer une nouvelle instance de l'adaptateur remplissez simplement les tableaux avec vos données à nouveau . L'idée ressemble à ceci:
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();
}
Donc, en fonction de cette réponse, vous devriez utiliser le même List<Item>
dans votre Fragment
. Lors de votre première initialisation d'adaptateur, vous remplissez votre liste avec les éléments et définissez l'adaptateur sur votre liste. Ensuite, à chaque modification de vos éléments, vous devez effacer les valeurs du List<Item> items
principal, puis les ré-peupler avec vos nouveaux éléments et appeler notifySetDataChanged();
.
C'est comme ça que ça fonctionne:).
Si l'adaptateur est déjà défini, il ne sera pas actualisé si la liste est affichée. Au lieu de cela, commencez par vérifier si la liste a un adaptateur, puis appelez la méthode appropriée.
Je pense que ce n'est pas une très bonne idée de créer une nouvelle instance de l'adaptateur lors du paramétrage de la vue liste. Au lieu de cela, créez un objet.
BuildingAdapter adapter = new BuildingAdapter(context);
if(getListView().getAdapter() == null){ //Adapter not set yet.
setListAdapter(adapter);
}
else{ //Already has an adapter
adapter.notifyDataSetChanged();
}
Vous pouvez également essayer d'exécuter la liste d'actualisation sur le thread d'interface utilisateur:
activity.runOnUiThread(new Runnable() {
public void run() {
//do your modifications here
// for example
adapter.add(new Object());
adapter.notifyDataSetChanged()
}
});
Essaye ça
@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();
}
Une réponse de AlexGo a fait le tour pour moi:
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
messages.add(m);
adapter.notifyDataSetChanged();
getListView().setSelection(messages.size()-1);
}
});
La mise à jour de liste a fonctionné pour moi auparavant lorsque la mise à jour a été déclenchée à partir d'un événement d'interface graphique, faisant ainsi partie du thread d'interface utilisateur.
Cependant, lorsque je mets à jour la liste à partir d'un autre événement/fil - c'est-à-dire d'un appel externe à l'application, la mise à jour ne serait pas dans le fil de l'interface utilisateur et l'ignorant de l'appel à getListView. Appeler la mise à jour avec runOnUiThread comme ci-dessus a été le bon choix pour moi. Merci!!
adpter.notifyDataSetInvalidated();
Essayez ceci avec la méthode onPause()
de la classe d’activité.
adapter.setNotifyDataChanged()
devrait faire l'affaire.
Essayez comme ça:
this.notifyDataSetChanged();
au lieu de:
adapter.notifyDataSetChanged();
Vous devez notifyDataSetChanged()
dans ListView
et non dans la classe d'adaptateur.
Si votre liste est contenue dans l'adaptateur même, l'appel de la fonction qui met à jour la liste doit également appeler notifyDataSetChanged()
.
L'exécution de cette fonction à partir du thread d'interface utilisateur a fait l'affaire pour moi:
La fonction refresh()
à l'intérieur de l'adaptateur
public void refresh(){
//manipulate list
notifyDataSetChanged();
}
Ensuite, exécutez cette fonction à partir du fil de l'interface utilisateur.
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
adapter.refresh()
}
});