您好,登錄后才能下訂單哦!
要求:屏幕中顯示一個listview,其中每一個item都有一個editText,在任一editText上輸入內容,快速上下滑動,保證數據不混亂。
這是一道面試題,初看沒什么,應該會很簡單,但實際解決起來沒那么簡單,先上解決代碼。
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); } } }
解釋:
通過打印log可以看到,屏幕中最多可以顯示7行item,下標依次為:0、1、2、3、4、5、6.
其中下標為0的item的地址值是3098e6e5
通過向上滑動,當出現第8行item(下標為7)的時候,下標為0的item已經完全看不到了,根據谷歌設計原理,下標為0的item復用到了剛剛出現的下標為7的item上,其中可以看到下標為7的item的地址值也是3098e6e5,以上可以證明。這些都是大家知道的,重點看下面:
為什么要寫
viewHolder.text.setTag(position);
這一行意義重大,在滑動的過程中,動態的將item與position進行綁定,如圖:
那么這么做的意義是什么呢,可以看到item中的editText有一個監聽事件:每當editText內容變化的時候都會將editText上的內容保存至集合中,那么保存到集合的哪一個下標中呢?看這行
int pos = (int) viewHolder.text.getTag();
被點擊的那行item根據getTag()獲取了最近與它綁定的那個position,還以地址為3098e6e5的item為例,那么pos的值此時應該是0還是7呢?這與當前listview滑動的位置有關,如果當前屏幕能看到下標為7的item,那么此時pos就必定為7,不可能為0,第一:item只能動態與一個position相綁定,第二,綁定是動態變化的,當前屏幕能看到的是下標為7的item,自然item與下標7綁定就不能再與下標0綁定了。那么就得到pos為7,集合就會將當前editText的內容保存到下標為7的對象中。那么無論再怎么上下滑動,只有當positon為7的時候才能從集合中獲取那條保存的數據,其他position都不可以,其他item也同理。
如果正常寫會出現什么呢?
例如:監聽器里不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) { } });
運行app后,首先上下滑動listView到最后再滑動到開頭(我設置了長度為51),讓每一個item充分復用,此時再次在下標為0的item中輸入內容,打印數據如下:
可以看到,我只在一個item的editText中輸入了1個字,按道理來說應該只觸發下標為0的那個item,并將下標為0的item上的數據保存到集合,但事實上卻觸發了這么多item中的editText的監聽,這是為什么呢?
原因是在上下快速滑動的過程中,下標為0的item出現了大量的復用情況,例如第0、7、14、21行的item都復用了這一個item,而適配器中的getView()方法經過了多次的執行,每次執行完畢后一些無用的資源就被回收了,但是item的editText是保存在viewHolder中的,并沒有被回收,但是多次的執行getView()方法,每一次都讓Item中的這個editText在對應的positon下設置了一次監聽,那么多次設置監聽,對應的是不同的位置(position),當觸發監聽的時候,自然會多處響應,導致了數據顯示的混亂。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。