web-dev-qa-db-fra.com

Les éléments de GridView sont répétés lorsque l'écran défile

J'utilise un GridView pour afficher un ensemble de catégories que l'utilisateur peut choisir. Chaque élément de la grille est constitué d'un ImageView et d'un TextView, tous deux extraits du serveur. Lorsqu'un élément est touché, une autre activité est lancée.

Je pensais que tout allait bien, jusqu'à ce que je remarque que certains éléments se répètent lorsque je fais défiler l'écran. Chaque fois que je fais défiler la grille, puis reculer, cela change de position et est dupliqué. Mais même lorsque je touche les détails, les bonnes valeurs sont envoyées à l'activité suivante. 

En regardant dans LogCat, toute demande répétée au serveur se produit. En fait, j'ai ceci en faisant défiler:

06-28 12:36:38.554: D/dalvikvm(358): GC_EXTERNAL_ALLOC freed 2061 objects / 156024 bytes in 51ms
06-28 12:36:42.915: D/dalvikvm(358): GC_FOR_MALLOC freed 6590 objects / 737528 bytes in 57ms
06-28 12:38:26.725: D/dalvikvm(358): GC_EXTERNAL_ALLOC freed 5426 objects / 468176 bytes in 71ms
06-28 12:38:26.875: D/dalvikvm(358): GC_EXTERNAL_ALLOC freed 409 objects / 17480 bytes in 68ms

On dirait qu'à chaque fois que je défile, ça se redessine ...

UPDATE: Cela ne fait que redessiner la première fois que je fais défiler le GridView. Après cela, tous les objets, y compris les objets répétés, restent en place.

Ma classe Java:

public void proccess(){
    int qtdCategorias = json.length();
    imagens = new Drawable[qtdCategorias];
    categorias = new String[qtdCategorias];
    for (int i=0; i<qtdCategorias; i++){
        JSONArray c = json.optJSONArray(i);
        String urlAmigavel = null;
        String imagemSite = null;
        String nomeCategoria = null;
        try {
            urlAmigavel = c.getString(6);
            imagemSite = c.getString(3);
            nomeCategoria = c.getString(2);
        } catch (JSONException e) {
            Log.e("CategoriasJogarActivity", e.toString());
            e.printStackTrace();
        }
        categorias[i] = nomeCategoria;
        imagens[i] = getImagem(urlAmigavel, imagemSite);
    }


    gridview = (GridView) findViewById(R.id.include3);

    ImageAdapter imageAdapter = new ImageAdapter(ctx, imagens, categorias);

    gridview.setAdapter(imageAdapter);

    gridview.setOnItemClickListener(new OnItemClickListener() {
        public void onItemClick(AdapterView<?> parent, View v,
                int position, long id) {

            String name = null;
            String idt = null;
            try {
                JSONArray c = json.optJSONArray(position);
                name = c.getString(2);
                idt = c.getString(0);
            } catch (JSONException e) {
                Log.e("CategoriasJogarActivity",
                        "JSONException" + e.toString());
            }

            Intent in = new Intent(getApplicationContext(),
                    JogarActivity.class);
            in.putExtra(TAG_NAME, name);
            in.putExtra(TAG_ID, idt);
            in.putExtra(TAG_PRIMEIRAPERGUNTA, true);
            startActivity(in);

        }
    });
}


public Drawable getImagem(String urlAmigavel, String img) {
    String url = "http://www.qranio.com/pergunta/" + urlAmigavel + "/"+ img;
    InputStream is = null;
    try {
        URL urlImagem = new URL(url);
        is = (InputStream) getObjeto(urlImagem);
    } catch (MalformedURLException e1) {
        Log.e("CategoriasJogarActivity", e1.toString());
        e1.printStackTrace();
    }
    Drawable d = Drawable.createFromStream(is, "src");

    return d;
}

private Object getObjeto(URL url) {
    Object content = null;
    try {
        content = url.getContent();
    } catch (IOException e) {
        Log.e("CategoriasJogarActivity", e.toString());
        e.printStackTrace();
    }
    return content;
}

classe imageAdapter

public class ImageAdapter extends BaseAdapter{
private Context mContext;
private final Drawable[] mThumbIds;
private final String[] mTextIds;


public ImageAdapter(Context c, Drawable[] d, String[] s) {
    mContext = c;
    mThumbIds = d;
    mTextIds = s;
}

public int getCount() {
    return mThumbIds.length;
}

public Object getItem(int position) {
    return null;
}

public long getItemId(int position) {
    return 0;
}

//create a new ImageView for each item referenced by the Adapter
public View getView(int position, View convertView, ViewGroup parent) {
    //ImageView imageView;
    View v;
    if (convertView == null) {  // if it's not recycled, initialize some attributes
        LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(     Context.LAYOUT_INFLATER_SERVICE );
        v = inflater.inflate(R.layout.gridview_item_layout, null);
        TextView text = (TextView)v.findViewById(R.id.grid_item_text);
        text.setText(mTextIds[position]);
        ImageView image = (ImageView)v.findViewById(R.id.grid_item_image);
        image.setImageDrawable(mThumbIds[position]);


    } else {

        v = (View) convertView;
    }


    return v;
}


}

gridview_item_layout xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
Android:id="@+id/gridview_item_layout"
Android:layout_width="wrap_content"
Android:layout_height="wrap_content"
Android:orientation="vertical"
Android:gravity="center_horizontal" >

<ImageView Android:id="@+id/grid_item_image"
Android:layout_width="wrap_content"
Android:layout_height="wrap_content"
Android:scaleType="fitCenter"
Android:minHeight="100dip"
Android:minWidth="100dip"
>
</ImageView>

<TextView Android:id="@+id/grid_item_text"
Android:layout_width="match_parent"
Android:layout_height="match_parent"
Android:text="TextView"
Android:gravity="center"
Android:textColor="#F9A512"
Android:textStyle="bold"
Android:textSize="18dp"
>
</TextView>
</LinearLayout>

gridview xml

<?xml version="1.0" encoding="utf-8"?>
<GridView xmlns:Android="http://schemas.Android.com/apk/res/Android" 
Android:id="@+id/gridview"
Android:layout_width="fill_parent" 
Android:layout_height="fill_parent"
Android:numColumns="auto_fit"
Android:verticalSpacing="10dip"
Android:horizontalSpacing="10dip"
Android:stretchMode="columnWidth"
Android:gravity="center"
Android:background="#FFFFFF"
Android:padding="5dip"
/>

J'ai vu d'autres questions sur ce même problème, mais aucune d'entre elles n'a répondu. Des idées sur ce qui se passe?

18
Lucas Jota

Il est normal que vous voyiez les mêmes éléments que lorsque vous faites défiler la GridView car, dans la méthode getView, vous définissez les éléments dessinables pour la ImageView uniquement lorsque la convertView est null (par exemple pour les premiers éléments vus lorsque la GridView est affichée à l'écran) . Si convertView n'est pas null, ce qui signifie que vous avez une vue de rangée recyclée, vous ne définissez pas la bonne image et vous restez avec l'image précédemment définie sur cette vue recyclée. Essayez de modifier la méthode getView comme ceci:

public View getView(int position, View convertView, ViewGroup parent) {
    View v;
    if (convertView == null) {  // if it's not recycled, initialize some attributes
        LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(     Context.LAYOUT_INFLATER_SERVICE );
        v = inflater.inflate(R.layout.gridview_item_layout, parent, false);
    } else {
        v = (View) convertView;
    }
    TextView text = (TextView)v.findViewById(R.id.grid_item_text);
    text.setText(mTextIds[position]);
    ImageView image = (ImageView)v.findViewById(R.id.grid_item_image);
    image.setImageDrawable(mThumbIds[position]);
    return v;
}

En cliquant sur un élément, vous affichez les éléments corrects car vous utilisez le paramètre position pour extraire les données.

84
Luksprog

Voici mon code pour GridView avec Button + Textview

public View getView(final int position, View convertView, ViewGroup parent) {
        LayoutInflater mInflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        if (convertView == null) {
            convertView = mInflater.inflate(R.layout.grid_item, null);  
        } else {
            holder = (ViewHolder) convertView.getTag();
        }
        TextView text = (TextView)convertView.findViewById(R.id.texto_grid);
        text.setText(app_listaActiva_NOMBRES[position]);
        Button image = (Button)convertView.findViewById(R.id.miniatura_grid);
        image.setBackgroundResource(R.drawable.custom_button);
        image.setOnClickListener(new MyOnClickListener2(position,app_listaActiva_SONIDOS));
        return convertView;
    }
2
KNU

Changez ici et essayez à nouveau,

   View v;
if (convertView == null) {  // if it's not recycled, initialize some attributes
    LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(     Context.LAYOUT_INFLATER_SERVICE );
    v = inflater.inflate(R.layout.gridview_item_layout, null);
    TextView text = (TextView)v.findViewById(R.id.grid_item_text);
    text.setText(mTextIds[position]);


} else {

    v = (View) convertView;
}
if(view!=null)
        {
               ImageView image = (ImageView)v.findViewById(R.id.grid_item_image);
               image.setImageDrawable(mThumbIds[position]);
               notifyDataSetChanged();  //Calling this helped to solve the problem. 
        }


return v;
}
0
osayilgan

Send et gridview ou listview et dans le constructeur implémentent cette méthode Implémentent onscroll listener

    this.mGridView = mGridView;
    this.mGridView.setOnScrollListener(new OnScrollListener() {

        @Override
        public void onScrollStateChanged(AbsListView view, int scrollState) {
            Log.v("onScrollStateChanged", "onScrollStateChanged");
            if (scrollState == OnScrollListener.SCROLL_STATE_IDLE) {
                isScrollStop = true;

                notifyDataSetChanged();
            } else {
                isScrollStop = false;
            }
        }

        @Override
        public void onScroll(AbsListView view, int firstVisibleItem,
                int visibleItemCount, int totalItemCount) {
            Log.v("onScroll", "onScroll");
        }
    });
0
Krste Moskov

En utilisant ViewHolder, la classe statique fixe les éléments répétés pour moi. 

Changer aussi layout_width et layout_height en fill_parent n'a pas aidé. 

J'ai suivi ce tutoriel http://Android-vogue.blogspot.com/2011/06/custom-gridview-in-Android-with.html

0
Nikolay Podolnyy