要求:屏幕中顯示一個(gè)listview,其中每一個(gè)item都有一個(gè)editText,在任一editText上輸入內(nèi)容,快速上下滑動(dòng),保證數(shù)據(jù)不混亂。
堅(jiān)守“ 做人真誠(chéng) · 做事靠譜 · 口碑至上 · 高效敬業(yè) ”的價(jià)值觀,專業(yè)網(wǎng)站建設(shè)服務(wù)10余年為成都成都木包裝箱小微創(chuàng)業(yè)公司專業(yè)提供企業(yè)網(wǎng)站建設(shè)營(yíng)銷(xiāo)網(wǎng)站建設(shè)商城網(wǎng)站建設(shè)手機(jī)網(wǎng)站建設(shè)小程序網(wǎng)站建設(shè)網(wǎng)站改版,從內(nèi)容策劃、視覺(jué)設(shè)計(jì)、底層架構(gòu)、網(wǎng)頁(yè)布局、功能開(kāi)發(fā)迭代于一體的高端網(wǎng)站建設(shè)服務(wù)。
這是一道面試題,初看沒(méi)什么,應(yīng)該會(huì)很簡(jiǎn)單,但實(shí)際解決起來(lái)沒(méi)那么簡(jiǎn)單,先上解決代碼。
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); } } }
解釋:
通過(guò)打印log可以看到,屏幕中最多可以顯示7行item,下標(biāo)依次為:0、1、2、3、4、5、6.
其中下標(biāo)為0的item的地址值是3098e6e5
通過(guò)向上滑動(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)看下面:
為什么要寫(xiě)
viewHolder.text.setTag(position);
這一行意義重大,在滑動(dòng)的過(guò)程中,動(dòng)態(tài)的將item與position進(jìn)行綁定,如圖:
那么這么做的意義是什么呢,可以看到item中的editText有一個(gè)監(jiān)聽(tīng)事件:每當(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ì)象中。那么無(wú)論再怎么上下滑動(dòng),只有當(dāng)positon為7的時(shí)候才能從集合中獲取那條保存的數(shù)據(jù),其他position都不可以,其他item也同理。
如果正常寫(xiě)會(huì)出現(xiàn)什么呢?
例如:監(jiān)聽(tīng)器里不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)到開(kāi)頭(我設(shè)置了長(zhǎng)度為51),讓每一個(gè)item充分復(fù)用,此時(shí)再次在下標(biāo)為0的item中輸入內(nèi)容,打印數(shù)據(jù)如下:
可以看到,我只在一個(gè)item的editText中輸入了1個(gè)字,按道理來(lái)說(shuō)應(yīng)該只觸發(fā)下標(biāo)為0的那個(gè)item,并將下標(biāo)為0的item上的數(shù)據(jù)保存到集合,但事實(shí)上卻觸發(fā)了這么多item中的editText的監(jiān)聽(tīng),這是為什么呢?
原因是在上下快速滑動(dòng)的過(guò)程中,下標(biāo)為0的item出現(xiàn)了大量的復(fù)用情況,例如第0、7、14、21行的item都復(fù)用了這一個(gè)item,而適配器中的getView()方法經(jīng)過(guò)了多次的執(zhí)行,每次執(zhí)行完畢后一些無(wú)用的資源就被回收了,但是item的editText是保存在viewHolder中的,并沒(méi)有被回收,但是多次的執(zhí)行g(shù)etView()方法,每一次都讓Item中的這個(gè)editText在對(duì)應(yīng)的positon下設(shè)置了一次監(jiān)聽(tīng),那么多次設(shè)置監(jiān)聽(tīng),對(duì)應(yīng)的是不同的位置(position),當(dāng)觸發(fā)監(jiān)聽(tīng)的時(shí)候,自然會(huì)多處響應(yīng),導(dǎo)致了數(shù)據(jù)顯示的混亂。