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?
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.
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;
}
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;
}
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");
}
});
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