溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

解決ListView中包含EditText數(shù)據(jù)混亂原理

發(fā)布時(shí)間:2020-08-10 11:25:28 來源:網(wǎng)絡(luò) 閱讀:5235 作者:IT學(xué)無止境 欄目:移動(dòng)開發(fā)

要求:屏幕中顯示一個(gè)listview,其中每一個(gè)item都有一個(gè)editText,在任一editText上輸入內(nèi)容,快速上下滑動(dòng),保證數(shù)據(jù)不混亂。

這是一道面試題,初看沒什么,應(yīng)該會(huì)很簡單,但實(shí)際解決起來沒那么簡單,先上解決代碼。

package com.zhiren.mytestok;

import android.content.Context;
import android.text.Editable;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.EditText;

import java.util.List;

/**
 * Created by Administrator on 2017/2/20.
 */

public class MyAdapters extends BaseAdapter {
    private Context context;
    //    private String[] str;
    private List list;

    public MyAdapters(Context context, List list) {
        this.context = context;
        this.list = list;
    }

    @Override
    public int getCount() {
        return list.size();
    }

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

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public View getView(final int position, View convertView, ViewGroup parent) {
        final ViewHolder viewHolder;
        if (convertView == null) {
            convertView = View.inflate(context, R.layout.item_mian, null);
            viewHolder = new ViewHolder(convertView);


            convertView.setTag(viewHolder);
        } else {
            viewHolder = (ViewHolder) convertView.getTag();
        }

        Bean bean = (Bean) list.get(position);
        Log.e("TAG", viewHolder.text + ":" + position);
        viewHolder.text.setTag(position);
        viewHolder.text.clearFocus();


        viewHolder.text.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {

            }

            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {
                int pos = (int) viewHolder.text.getTag();
                Bean b  = (Bean) list.get(pos);
                b.setName(s + "");
            }

            @Override
            public void afterTextChanged(Editable s) {

            }
        });

        if (!TextUtils.isEmpty(bean.getName())) {
            viewHolder.text.setText(bean.getName());
        } else {
            viewHolder.text.setText("");
        }

        return convertView;
    }

    public class ViewHolder {
        private EditText text;

        public ViewHolder(View v) {
            text = (EditText) v.findViewById(R.id.et_item);
        }
    }
}

解釋:解決ListView中包含EditText數(shù)據(jù)混亂原理

通過打印log可以看到,屏幕中最多可以顯示7行item,下標(biāo)依次為:0、1、2、3、4、5、6.

其中下標(biāo)為0的item的地址值是3098e6e5

通過向上滑動(dòng),當(dāng)出現(xiàn)第8行item(下標(biāo)為7)的時(shí)候,下標(biāo)為0的item已經(jīng)完全看不到了,根據(jù)谷歌設(shè)計(jì)原理,下標(biāo)為0的item復(fù)用到了剛剛出現(xiàn)的下標(biāo)為7的item上,其中可以看到下標(biāo)為7的item的地址值也是3098e6e5,以上可以證明。這些都是大家知道的,重點(diǎn)看下面:

為什么要寫

viewHolder.text.setTag(position);

這一行意義重大,在滑動(dòng)的過程中,動(dòng)態(tài)的將item與position進(jìn)行綁定,如圖:

解決ListView中包含EditText數(shù)據(jù)混亂原理

那么這么做的意義是什么呢,可以看到item中的editText有一個(gè)監(jiān)聽事件:每當(dāng)editText內(nèi)容變化的時(shí)候都會(huì)將editText上的內(nèi)容保存至集合中,那么保存到集合的哪一個(gè)下標(biāo)中呢?看這行

int pos = (int) viewHolder.text.getTag();

被點(diǎn)擊的那行item根據(jù)getTag()獲取了最近與它綁定的那個(gè)position,還以地址為3098e6e5的item為例,那么pos的值此時(shí)應(yīng)該是0還是7呢?這與當(dāng)前l(fā)istview滑動(dòng)的位置有關(guān),如果當(dāng)前屏幕能看到下標(biāo)為7的item,那么此時(shí)pos就必定為7,不可能為0,第一:item只能動(dòng)態(tài)與一個(gè)position相綁定,第二,綁定是動(dòng)態(tài)變化的,當(dāng)前屏幕能看到的是下標(biāo)為7的item,自然item與下標(biāo)7綁定就不能再與下標(biāo)0綁定了。那么就得到pos為7,集合就會(huì)將當(dāng)前editText的內(nèi)容保存到下標(biāo)為7的對(duì)象中。那么無論再怎么上下滑動(dòng),只有當(dāng)positon為7的時(shí)候才能從集合中獲取那條保存的數(shù)據(jù),其他position都不可以,其他item也同理。



如果正常寫會(huì)出現(xiàn)什么呢?

例如:監(jiān)聽器里不getTag()

viewHolder.text.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {

            }

            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {
//                int pos = (int) viewHolder.text.getTag();
//                Bean b  = (Bean) list.get(pos);
//                b.setName(s + "");
                Bean b = (Bean) list.get(position);
                b.setName(s + "");
                Log.e("TAG", "" + position);
            }

            @Override
            public void afterTextChanged(Editable s) {

            }
        });


運(yùn)行app后,首先上下滑動(dòng)listView到最后再滑動(dòng)到開頭(我設(shè)置了長度為51),讓每一個(gè)item充分復(fù)用,此時(shí)再次在下標(biāo)為0的item中輸入內(nèi)容,打印數(shù)據(jù)如下:

解決ListView中包含EditText數(shù)據(jù)混亂原理

可以看到,我只在一個(gè)item的editText中輸入了1個(gè)字,按道理來說應(yīng)該只觸發(fā)下標(biāo)為0的那個(gè)item,并將下標(biāo)為0的item上的數(shù)據(jù)保存到集合,但事實(shí)上卻觸發(fā)了這么多item中的editText的監(jiān)聽,這是為什么呢?

原因是在上下快速滑動(dòng)的過程中,下標(biāo)為0的item出現(xiàn)了大量的復(fù)用情況,例如第0、7、14、21行的item都復(fù)用了這一個(gè)item,而適配器中的getView()方法經(jīng)過了多次的執(zhí)行,每次執(zhí)行完畢后一些無用的資源就被回收了,但是item的editText是保存在viewHolder中的,并沒有被回收,但是多次的執(zhí)行g(shù)etView()方法,每一次都讓Item中的這個(gè)editText在對(duì)應(yīng)的positon下設(shè)置了一次監(jiān)聽,那么多次設(shè)置監(jiān)聽,對(duì)應(yīng)的是不同的位置(position),當(dāng)觸發(fā)監(jiān)聽的時(shí)候,自然會(huì)多處響應(yīng),導(dǎo)致了數(shù)據(jù)顯示的混亂。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請(qǐng)聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI