Почему элементы изменяют порядок при прокрутке в Android GridView?

У меня есть GridView в Android, который я заполняю его данными, полученными из ресурса XML.
Например, у меня есть 15 элементов в GridView, которые расположены по порядку. Общая высота превышает высоту экрана, поэтому мне нужно прокрутить, чтобы увидеть остальные элементы.
Проблема в том, что при прокрутке назад порядок невидимых строк изменился. Это таинственное поведение, поскольку иногда элементы обмениваются рядами друг с другом. Вот мой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;
    }

Update: Ну, это довольно странно. После некоторой дополнительной отладки я заметил, что в GridView адаптер пропускает 13-ю позицию, то есть возвращает 1 вместо 13, а затем переходит к 14 !!! (Полагаю, 13 - неудача!)

 Luksprog20 мая 2012 г., 12:01
Adapter не будет пропускать позиции самостоятельно. Разместите полный код вашего адаптера.
 Hamed Momeni20 мая 2012 г., 12:20
Хорошо, я положил весь адаптер там.

Ответы на вопрос(6)

Я только что удалил

if(convertView==null)

оно работает

Решение Вопроса

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

Я не знаю, работает ли приведенный выше код, ваш немного странный. В любом случае, я думаю, что поведение, которое вы видите, нормальное, потому что все, что вы делаете в адаптере, это заполнение первых видимых элементов, а затем адаптер будет повторно использоватьexact те же элементы при прокрутке вверх и вниз из-за переработки. вgetView вам следует:

Check if the convertView is null: If it is null it's time to inflate a new View for this GridView's element. You could also use the holder pattern to cache looking for the composing Views(instead of searching with findViewById everytime)(You use the setTag element for the inflated View but it's a piece of data from the Node data element ?!? What do you plan to do with it?!?) If it isn't null you'll do nothing(or if you implement the holder pattern you would get the tag with the already searched Views)

И это то, что вы должны сделать в этом выражении if / else

After the part above you'll populate the Views with data(so they hold the apropriate data for that position).
 12 сент. 2015 г., 15:28
ти! ты спас мне день
 Hamed Momeni20 мая 2012 г., 14:32
Спасибо, это потому, что я совершенно новичок в программировании на Android. С вашей помощью я смогу заставить его работать.

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
}

ВgetView(), еслиconvertView являетсяnullВы раздуваете макет и заполняете его виджеты. Это отлично.

ВgetView(), еслиconvertView не являетсяnullВы абсолютно ничего не делаете. Это крайне неправильно.

Что тыshould делать вgetView(), еслиconvertView не являетсяnull, являетсяstill populating the cell's widgets. convertView представляет ячейку, подлежащую рециркуляции, так что вы можете пропустить инфляцию и сэкономить процессорное время, но вам все равно придется обновить виджеты этой ячейки, чтобы отразить, какую позицию вы должны установить в этом конкретном случае.getView() вызов.

 02 нояб. 2012 г., 10:42
У меня та же проблема, но я применил ViewHolder, и все же мой порядок изображений менялся.
 18 авг. 2013 г., 14:59
@sandalone: вклevery call to getView() you need to configure the row, Какиеif/else конструкции, которые вы используете, если таковые имеются, зависит от вас, до тех пор, пока это на самом призывеgetView() Вы полностью настраиваете ряд. В случае ФП ФП былnot настройка строки, еслиconvertView не былоnull.
 18 авг. 2013 г., 14:44
@CommonsWare Правда ли, что все действия, включаяfindViewById() должно быть сделано снаружи, если / еще? Кто-то заявил, что здесь и эта информация для меня новая.

has several views in it ты можешь использоватьgetTag() а такжеset,Tag() методы. В этом случае элементы сетки больше не меняются местами при прокрутке, и производительность по-прежнему будет хорошей:

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

Ваш ответ на вопрос