15

我在 android 中有一个 GridView,我用从 xml 资源检索到的数据填充它。
例如,我在 GridView 中有 15 个项目按顺序放置。总高度超过了屏幕高度,所以我必须滚动才能看到其余的项目。
问题是当我向上滚动时,不可见行的顺序已经改变。这是一种神秘的行为,因为有时项目会相互交换行。这是我的getView方法:

public class ImageAdapter extends BaseAdapter {
        public ImageAdapter(Context c, NodeList cuu) {
                cu = cuu;
        }
        public int getCount() {
                Log.d("Node Count",cu.getLength()+"");
                return cu.getLength();
        }
        public Object getItem(int position) {
                return position;
        }
        public long getItemId(int position) {
                return position;
        }
        public View getView(int position, View convertView, ViewGroup parent) {
                View myView = convertView;
                if (convertView == null) {
                    Node nd = cu.item(position);
                    Log.d("nodes","Pos: "+(position)+" Name: "+nd.getNodeName()+" Title: "+nd.getAttributes().getNamedItem("title").getTextContent());
                    int catID = Integer.parseInt(nd.getAttributes().getNamedItem("id").getTextContent());
                    LayoutInflater li = getLayoutInflater();
                    myView = li.inflate(R.layout.grid_item, null);
                   ImageView imageView = (ImageView) myView.findViewById(R.id.grid_item_image);
                   myView.setLayoutParams(new GridView.LayoutParams(70, 100));
                   id.download(nd.getAttributes().getNamedItem("icon").getTextContent(),imageView);
                   TextView textView = (TextView) myView.findViewById(R.id.grid_item_text);
                   textView.setText(nd.getAttributes().getNamedItem("title").getTextContent());
                   myView.setTag((Object) catID);
                }else{
                    //Log.d("nodes","Pos: "+(position));
                }
                return myView;
        }
        private NodeList cu = null;
    }

更新:嗯,这很奇怪。经过更多调试后,我注意到在 GridView 中,适配器跳过了第 13 个位置,这意味着它返回 1 而不是 13,然后移动到 14!(我猜 13 是运气不好!)

4

6 回答 6

11
public View getView(int position, View convertView, ViewGroup parent) {
    View view;
    if (convertView == null) {
        view= inflate your xml
    } else {
        view=convertView;
    }
    // all remaining code like 
    // view.findViewById(R.id.btn).setText("MyButton");                            
    // must be outside if-else
}
于 2013-07-08T09:48:25.190 回答
8

如果这是您在getView方法中拥有的所有代码,那么您没有正确实施它:

public View getView(int position, View convertView, ViewGroup parent) {
        View myView = convertView;
        if (myView == null) {           
            Node nd = cu.item(position);
            int catID = Integer.parseInt(nd.getAttributes().getNamedItem("id")
                    .getTextContent());
            LayoutInflater li = getLayoutInflater();
            myView = li.inflate(R.layout.grid_item, null);
            myView.setLayoutParams(new GridView.LayoutParams(70, 100));         
            myView.setTag((Object) catID);
        } 
        Node nd = cu.item(position);
        Log.d("nodes", "Pos: " + (position) + " Name: " + nd.getNodeName()
                + " Title: "
                + nd.getAttributes().getNamedItem("title").getTextContent());
        ImageView imageView = (ImageView) myView
                .findViewById(R.id.grid_item_image);
        id.download(nd.getAttributes().getNamedItem("icon")
                .getTextContent(), imageView);
        TextView textView = (TextView) myView
                .findViewById(R.id.grid_item_text);
        textView.setText(nd.getAttributes().getNamedItem("title")
                .getTextContent());
        return myView;
    }

我不知道上面的代码是否有效,你的有点奇怪。无论如何,我认为您看到的行为是正常的,因为您在适配器中所做的一切都是填充第一个可见元素,然后由于回收,当您上下滚动时,适配器将重用完全相同的元素。getView你应该:

  • 检查是否convertViewnull
    • 如果是null时候View为 thisGridView的元素添加一个新的了。您还可以使用持有人模式来缓存寻找组成Views(而不是findViewById每次都搜索)(您使用setTag元素作为膨胀视图,但它是来自数据元素的一条Node数据?!?你打算用它做什么?!?)
    • 如果不是null,您将什么也不做(或者如果您实现持有人模式,您将获得带有已搜索标签的标签Views

这就是你在 if/else 语句中应该做的事情

  • 在上面的部分之后,您将填充Views数据(因此它们为该位置保存适当的数据)。
于 2012-05-20T11:49:22.430 回答
4

我刚刚删除了

if(convertView==null)

有用

于 2014-02-11T17:18:14.727 回答
3

您的适配器实现存在致命缺陷。

getView(), if convertViewis 中null,您膨胀布局并填充其小部件。这可以。

getView(), 如果convertView不是null, 你绝对什么也不做。这是非常错误的。

如果不是,您应该做的仍然是填充单元格的小部件。表示要回收的单元格,因此您可以跳过通货膨胀并节省 CPU 时间,但您仍然必须更新该单元格的小部件以反映您应该在此特定调用中设置的任何位置。getView()convertViewnullconvertViewgetView()

于 2012-05-20T11:43:01.773 回答
1

如果您的 Grid 项目中有多个视图,您可以使用getTag()setTag()方法。在这种情况下,网格项目不会再在滚动时改变它们的位置,并且性能仍然很好:

public class SomeAdapter extends BaseAdapter {

    public static class ViewHolder {
        public TextView tvTitle;
        public ImageView imgPoster;
    }

    //...
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {

        ViewHolder grid;
        LayoutInflater inflator = activity.getLayoutInflater();

        if (convertView == null) {
            grid = new ViewHolder();
            convertView = inflator.inflate(R.layout.grid_item, null);
            grid.tvTitle = (TextView) convertView.findViewById(R.id.tv_title);
            grid.imgPoster = (ImageView) convertView.findViewById(R.id.img_poster);

            convertView.setTag(grid);   // <<-- H E R E
        } else {
            grid = (ViewHolder) convertView.getTag();   // <<-- H E R E
        }
        grid.tvTitle.setText(dataItem.getTitle());
        grid.imgPoster.setImage(dataItem.getImage());
        return convertView;
    }
}
于 2016-09-29T00:34:57.233 回答
0

我使用了这个解决方案,基于另一个样本,并且工作:

public View getView(int position, View convertView, ViewGroup parent) {
    View view = null;
    if (convertView == null) {
        view = inflate your xml and apply the View Holder pattern
    } else {
        view = convertView;
    }
    // retrieve the object by Holder pattern 
    // extra code here
}
于 2014-06-02T20:09:17.250 回答