【问题标题】:Items inside GridView getting repeated when screen scrolls屏幕滚动时,GridView 中的项目会重复
【发布时间】:2012-06-30 00:44:30
【问题描述】:

我正在使用 GridView 来显示一组用户可以选择的类别。网格的每个项目都由一个 ImageView 和一个 TextView 组成,两者都从服务器检索。当一个项目被触摸时,另一个活动被启动。

我以为一切正常,直到我注意到滚动屏幕时有些项目重复出现。每当我在网格中向下滚动然后返回时,它都会改变它的位置并被复制。但即使我触摸了混乱的项目,正确的值也会发送到下一个活动。

在 LogCat 中,任何对服务器的重复请求都会发生。事实上,我在滚动时得到了这个:

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

看起来每次我滚动时,都会重绘...

更新:它仅在我第一次向下滚动 GridView 时重绘。在此之后,所有的元素,包括重复的元素,都会保持原位。

我的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;
}

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>

网格视图 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"
/>

我看到了关于同一问题的其他问题,但没有一个回答。对正在发生的事情有任何想法吗?

【问题讨论】:

  • 使用 ViewHolder 是代码的好习惯

标签: android android-layout gridview drawable


【解决方案1】:

向下滚动GridView 时看到相同的项目是正常的,因为在getView 方法中,仅当convertViewnull 时才为ImageView 设置可绘制对象(例如GridView 出现在屏幕上时看到的第一个元素)。如果convertView 不是null,这意味着您有一个回收的行视图,则您没有设置正确的图像,您将保留之前在此回收视图上设置的图像。尝试像这样修改getView 方法:

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;
}

单击一个元素会显示正确的项目,因为您使用position 参数来检索数据。

【讨论】:

  • 成功了!虽然当我第一次向下滚动网格时 LogCat 一直显示那些 GC_EXTERNAL_ALLOC 行......
  • @LucasJota 那是垃圾收集器,我认为这很正常(如果它没有使GridView 滞后)。请记住,您正在查询这些图像并将它们保存在内存中(我不知道您有多少)。
  • 使用 Button + Textview 非常适合我
  • 非常感谢你是英雄
【解决方案2】:

这是我的 Button + Textview 的 GirdView 代码

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;
    }

【讨论】:

    【解决方案3】:

    这里改一下再试试,

       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;
    }
    

    【讨论】:

    • 为什么要添加额外的检查,虽然我们已经检查了 convertview==null,但我会将最后一个块放在 else 块中。
    • 是的,你是对的,但它在“其他声明”中对我来说不起作用,我不确定。
    【解决方案4】:

    发送和gridview或listview并在构造函数中实现这个方法 实现滚动监听

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

    【讨论】:

      【解决方案5】:

      使用ViewHolder 静态类为我修复重复项。

      还将layout_widthlayout_height 更改为fill_parent 也没有帮助。

      我完成了这个教程 http://android-vogue.blogspot.com/2011/06/custom-gridview-in-android-with.html

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-02-19
        • 2021-03-18
        • 2020-10-28
        • 1970-01-01
        • 2016-04-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多