Update d'une ListView

Parce que je patauge dans la semoule

a marqué ce sujet comme résolu.

Salut

J'ai créé une ListView avec un custom adapter pour pouvoir afficher des éléments avec un layout personnalisé, j'ai suivi plusieurs tuto notamment celui d'Andr0 ainsi que plusieurs réponses sur stackoverflow. Là dessus pas de problème j'arrive à afficher tous mes éléments de ma base. Mon problème survient lorsque je veux ajouter un élément à ma listview déjà remplie, si je modifie l'ArrayList (laquelle contient toutes mes items de ma ListView) puis que j'appelle java adapter.notifyDataChanged() ma liste est bien mise à jour mais tous les items sont dupliqués.

Voici mon code :

MyListFragment.java

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
public class MyListFragment extends ListFragment {
    
    private static final String TAG = "ListFragment";

    private List<List<String>> content = new ArrayList<List<String>>();
    private Context mContext;
    private View mView;
    private ListViewAdapter adapter;
    // RECEIVER
    private BroadcastReceiver mMessageReceiver;
    private static String REMOVE_ITEM = "remove_item";
    private static String ADD_ITEM = "add_item";
    
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {

        mView = inflater.inflate(R.layout.list_routes_fragment, container, false);
        
        mContext = getActivity();
        
        // Broadcast receiver filter
        
        mContext.registerReceiver(mMessageReceiver,
                new IntentFilter(REMOVE_ITEM));
        mContext.registerReceiver(mMessageReceiver,
                new IntentFilter(ADD_ITEM));

        mMessageReceiver = new BroadcastReceiver() {
            
            @Override            
            public void onReceive(Context context, Intent intent) {
                
                String action = intent.getAction();
                                
                if (action != null) {
                    
                    if (action.equals(REMOVE_ITEM)) {
                        
                        int position = Integer.valueOf(intent.getStringExtra("position"));

                        content.remove(position);
                        
                        adapter.notifyDataSetChanged();
                        
                    } else if(action.equals(ADD_ITEM)) {
                        
                        List<String> item = intent.getStringArrayListExtra("item");
 
                        content.add(item);
 
                        adapter.notifyDataChanged();
                                             
                    } 
                }
            }
        };
        
        return mView;

    }
    
    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        
        super.onActivityCreated(savedInstanceState);
     
        new databaseTask().execute("");
        
    }
    
    @Override
    public void onResume() {        
        // Broadcast receiver filter
        
        mContext.registerReceiver(mMessageReceiver,
                new IntentFilter(REMOVE_ITEM));
        mContext.registerReceiver(mMessageReceiver,
                new IntentFilter(ADD_ITEM));
        
        super.onResume();
    }

    @Override
    public void onPause() {
        mContext.unregisterReceiver(mMessageReceiver);
        super.onPause();
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
    }

    public class databaseTask extends AsyncTask<String, Integer, String> {

        @Override
        protected String doInBackground(String... params) {

            SQLiteHelper db = new SQLiteHelper(mContext);
            
            // Get all routes

            List<Route> routes = db.getRoutes();
            
            if (routes != null && routes.size() > 0) {

                for (Route route : routes) {
                    
                    List<String> listRoute = new ArrayList<String>();

                    // Add Date

                    listRoute.add(route.getDateTime());
                    
                    // Add Time

                    String time = db.getRouteStatName(routeId,
                            getResources().getString(R.string.statTime));

                    listRoute.add(time);
                    
                    // Add Route Id
                    
                    listRoute.add(route.getRouteId() + "");
                    
                    // Add list to content
                    
                    content.add(listRoute);

                }

            }

            return null;
        }

        @Override
        protected void onPostExecute(String result) {

            // Set adapter

            adapter = new ListViewAdapter(getActivity(), content);
            
            setListAdapter(adapter);
            
            
        }

    }

}

ListViewAdapter.java

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
public class ListViewAdapter extends ArrayAdapter<List<List<String>>> {

    private static final String TAG = "ListViewAdapter";
    private Context mContext;
    private List<List<String>> adapter;
    // RECEIVER
    private BroadcastReceiver mMessageReceiver;
    private static String REMOVE_ITEM = "remove_item";

    public ListViewAdapter(Context context, List<List<String>> content) {
        super(context, R.layout.custom_layout_route);
        mContext = context;
        adapter = content;
    }
    
    @Override
    public int getCount() {

        return adapter.size();
    }

    @Override
    public long getItemId(int position) {

        return adapter.indexOf(getItem(position));
    }
    

    @Override
    public View getView(final int position, View convertView, ViewGroup parent) {
                
        View rowView = convertView;
        ViewHolder view;
        
        if(rowView == null)
        {
            
            // Get a new instance of the row layout view
            LayoutInflater inflater = (LayoutInflater) mContext
                    .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            rowView = inflater.inflate(R.layout.custom_layout_route,parent, false);

            // Hold the view objects in an object, that way the don't need to be "re-  finded"
            view = new ViewHolder();
            view.textviewDate = (TextView) rowView.findViewById(R.id.textviewDate);
            view.textviewTime = (TextView) rowView.findViewById(R.id.textviewTime);
            view.btDelete = (ImageButton) rowView.findViewById(R.id.btDelete);

            rowView.setTag(view);
            
        } else {
            
            view = (ViewHolder) rowView.getTag();
            
        }
        
        List<String> route = new ArrayList<String>();
        
        route = adapter.get(position);
                        
        String date = route.get(0).toString();
        String time = route.get(1).toString();
        final String routeId = route.get(2).toString();
                
        view.textviewDate.setText(date); 
        view.textviewTime.setText(time);   
        
        // Set click listener on remove button 
        
        view.btDelete.setOnClickListener(new OnClickListener() {
            
            @Override
            public void onClick(View v) {
                
                new AlertDialog.Builder(mContext)
                .setTitle(mContext.getString(R.string.delete_route_title))
                .setMessage(mContext.getString(R.string.delete_route_message))
                .setPositiveButton(android.R.string.yes,
                        new DialogInterface.OnClickListener() {
                            public void onClick(DialogInterface dialog, int which) {

                                SQLiteHelper db = new SQLiteHelper(mContext);

                                db.removeRoute(Integer.parseInt(routeId));
                                
                                // Send Broadcast to remove item from listview
                                
                                Intent i = new Intent(REMOVE_ITEM);
                                
                                i.putExtra("position", position  + "");

                                mContext.sendBroadcast(i.setAction(REMOVE_ITEM));
                                
                                // Tell user the route is deleted
                                
                                Toast.makeText(mContext, getRessource().getString().RouteDelete,
                                        Toast.LENGTH_SHORT).show();

                            }
                        })
                .setNegativeButton(android.R.string.no,
                        new DialogInterface.OnClickListener() {
                            public void onClick(DialogInterface dialog, int which) {
                                // do nothing
                            }
                        })
                .show();
                
            }
            
        });

        return rowView;
    }
    
    protected static class ViewHolder{
        protected TextView textviewDate;
        protected TextView textviewTime;
        protected ImageButton btDelete;
    }
        
}

Le plus frustrant c'est que je comprends pourquoi il me duplique ma liste, c'est lorsque je fais

1
2
3
4
5
List<String> item = intent.getStringArrayListExtra("item");

content.add(item);

adapter.notifyDataChanged();

Je lui dis "Hé ! Le contenu de la ListView a changé tu pourrais me la rafraîchir steuplé ? " Seulement j'aurais crû que qu'il aurait été assez intelligent pour rajouter uniquement le nouvel élément et pas toute la liste. J'ai testé beaucoup (toutes ?) de réponses sur Stack et autre blog mais je pense qu'il y a un truc que j'ai pas dû bien comprendre sur les adapter.

Merci d'avance à ceux qui pourront m'aider :)

+0 -0

S'il te duplique tes données c'est parce que tu as certainement oublié de faire un clear() de ta liste.

Réessaye avec ce morceau.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
public class MyListFragment extends ListFragment {
    
    private static final String TAG = "ListFragment";

    private List<List<String>> content = new ArrayList<List<String>>();
    private Context mContext;
    private View mView;
    private ListViewAdapter adapter;
    // RECEIVER
    private BroadcastReceiver mMessageReceiver;
    private static String REMOVE_ITEM = "remove_item";
    private static String ADD_ITEM = "add_item";
    
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {

        mView = inflater.inflate(R.layout.list_routes_fragment, container, false);
        
        mContext = getActivity();
        
        // Broadcast receiver filter
        
        mContext.registerReceiver(mMessageReceiver,
                new IntentFilter(REMOVE_ITEM));
        mContext.registerReceiver(mMessageReceiver,
                new IntentFilter(ADD_ITEM));

        mMessageReceiver = new BroadcastReceiver() {
            
            @Override            
            public void onReceive(Context context, Intent intent) {
                
                String action = intent.getAction();
                                
                if (action != null) {
                    
                    if (action.equals(REMOVE_ITEM)) {
                        
                        int position = Integer.valueOf(intent.getStringExtra("position"));

                        content.remove(position);
                        
                        adapter.notifyDataSetChanged();
                        
                    } else if(action.equals(ADD_ITEM)) {
                        
                        List<String> item = intent.getStringArrayListExtra("item");
 
                        content.add(item);
 
                        adapter.notifyDataChanged();
                                             
                    } 
                }
            }
        };
        
        return mView;

    }
    
    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        
        super.onActivityCreated(savedInstanceState);
     
        new databaseTask().execute("");
        
    }
    
    @Override
    public void onResume() {        
        // Broadcast receiver filter
        
        mContext.registerReceiver(mMessageReceiver,
                new IntentFilter(REMOVE_ITEM));
        mContext.registerReceiver(mMessageReceiver,
                new IntentFilter(ADD_ITEM));
        
        super.onResume();
    }

    @Override
    public void onPause() {
        mContext.unregisterReceiver(mMessageReceiver);
        super.onPause();
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
    }

    public class databaseTask extends AsyncTask<String, Integer, String> {

        @Override
        protected String doInBackground(String... params) {

            SQLiteHelper db = new SQLiteHelper(mContext);
            
            // Get all routes

            List<Route> routes = db.getRoutes();
            
            if (routes != null && routes.size() > 0) {

                content.clear();

                for (Route route : routes) {
                    
                    List<String> listRoute = new ArrayList<String>();

                    // Add Date

                    listRoute.add(route.getDateTime());
                    
                    // Add Time

                    String time = db.getRouteStatName(routeId,
                            getResources().getString(R.string.statTime));

                    listRoute.add(time);
                    
                    // Add Route Id
                    
                    listRoute.add(route.getRouteId() + "");
                    
                    // Add list to content
                    
                    content.add(listRoute);

                }

            }

            return null;
        }

        @Override
        protected void onPostExecute(String result) {

            // Set adapter

            adapter = new ListViewAdapter(getActivity(), content);
            
            setListAdapter(adapter);
            
            
        }

    }

}

Salut firm1

Merci pour ta réponse tout fonctionne cependant je comprends pas pourquoi.

Mon AsyncTask est appelée lors de la création de l'activity, donc normalement là ou il y a le content.clear() l'ArrayList *content * est vide donc je vide une liste vide ? Pourrais tu m'expliquer si possible le résonnement derrière ?

Merci

+0 -0

En fait ton Objet de type ListFragment est conservé en mémoire, et dans cet objet tu stockes l'attribut content qui est une List. Cette attribut ne sera pas effacé tant que ton objet ListFragment sera toujours en mémoire.

Donc à chaque fois tu ne faisais qu'appeler ta méthode qui rajoutait des élément dans la liste, mais tu ne le nettoyais pas avant. Là j'ai juste rajouté la méthode qui vide le contenu de ta liste pour la recharger et ça fonctionne.

Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte