1. 程式人生 > >解決ListView中包含EditText資料混亂原理

解決ListView中包含EditText資料混亂原理

要求:螢幕中顯示一個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);
        }
    }
}


解釋:wKiom1ir0-HRh-Q9AACx4z3Czt8488.jpg-wh_50

通過列印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進行繫結,如圖:

wKioL1ir1taizi86AABKX-swbb4328.png-wh_50

那麼這麼做的意義是什麼呢,可以看到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中輸入內容,列印資料如下:

wKiom1ir2-TzjSiTAADBY-sl4YQ323.jpg-wh_50

可以看到,我只在一個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),當觸發監聽的時候,自然會多處響應,導致了資料顯示的混亂。

相關推薦

解決ListView包含EditText資料混亂原理

要求:螢幕中顯示一個listview,其中每一個item都有一個editText,在任一editText上輸入內容,快速上下滑動,保證資料不混亂。 這是一道面試題,初看沒什麼,應該會很簡單,但實際解決起來沒那麼簡單,先上解決程式碼。 package com.zhiren.m

商城購物車加減控制元件的簡單封裝(續),解決ListView資料錯亂的問題

在上一篇文章中,我們學習了商城購物車加減控制元件的簡單封裝,知道了封裝的思路過程和使用方法。還沒有看過上一篇文章的朋友,建議先去閱讀 商城購物車加減控制元件的簡單封裝 。這段時間收到一些小夥伴的反饋,在ListView或者是RecyclerView中存在ite

AndroidListView包含Button時滑動丟失選中狀態的解決方法(二)

1.介面卡中的主要邏輯: import android.content.Context; import android.support.v4.content.ContextCompat; import android.text.TextUtils; import a

ScrollView包含EditText,設定android:windowSoftInputMode="adjustPan"後無效

最近在做專案的時候遇到了如下問題: ScrollView中包含EditText,點選EditText輸入內容的時候被鍵盤遮擋,而且ScrollView無法繼續向上滑動到輸入框位置。 解決辦法: 在ScrollView的根節點處新增屬性 android:fitsSystemWind

資料庫索引包含資料結構有哪些

1 索引介紹   MySQL官方對索引的定義為:索引(Index)是幫助MySQL高效獲取資料的資料結構。提取句子主幹,就可以得到索引的本質:索引是資料結構。   我們知道,資料庫查詢是資料庫的最主要功能之一,例如下面的SQL語句: SELECT *

(15)關於ListViewnotifyDataSetChanged()重新整理資料不更新原因

使用Listview的時候: 當要動態顯示更改後的資料(例如資料庫改動), 很多人應該都用過notifyDataSetChanged();這個方法來重新整理Listview,顯示改後的資料. 這時候就要注意了:                  ......       

Android ListViewnotifyDataSetChanged()重新整理資料不更新原因

使用Listview的時候: 當要動態顯示更改後的資料(例如資料庫改動), 很多人應該都用過notifyDataSetChanged();這個方法來重新整理Listview,顯示改後的資料.這時候就要注意了:                 ......                 private Ar

解決URL包含以及不包含https、www時引起的JS跨域問題

場景:站點的全域名是:https://www.example.com,使用者使用此連結訪問站點時完全正常,但是有時候使用者手動輸入網址時並不會輸入全域名,可能是:www.example.com,也可能

解決echarts多次資料非同步載入後觸發事件疊加問題

解決echarts中多次資料非同步載入後觸發事件疊加問題 問題描述 echarts中資料通過ajax等方式多次非同步載入資料後,當點選圖表中的同一位置時,其觸發事件也會隨之觸發多次。在官方的教程中有這樣一局原話“所有資料的更新都通過 setOption實現,你只需要定時獲

VS2012如何在解決方案包含預設的標頭檔案目錄

大家安裝完vs2012後,最讓人困惑的是原先的解決方案中包含預設標頭檔案不知道跑哪去了。只能在每個專案屬性中新增,這樣是很麻煩的。 那vs2012應該如何新增啦,步驟如下:        1.新建一個解決方案。        2.檢視---->屬性管理        

解決spark遇到的資料傾斜問題

一. 資料傾斜的現象 多數task執行速度較快,少數task執行時間非常長,或者等待很長時間後提示你記憶體不足,執行失敗。 二. 資料傾斜的原因 常見於各種shuffle操作,例如reduceByKey,groupByKey,join等操作。 資

解決listview ,點選item時,item裡的所有設定了selector的元件全部一起變色

listview中如果不設定,item裡面的每個元件的背景顏色的話,預設情況下,點選item時,會有listview的預設,點選變色。預設的效果很醜,所以我們一般都會使用自定義的顏色。 現在我要實現這種效果,如上圖紅框中的兩個元件。這是一個listview,我想要實現

解決ListViewItem的子控制元件(比如Button)與Item點選事件衝突

經常會碰到在ListView中點選其中一個Item,會一併觸發其子控制元件的點選事件,例如Item中的Button、ImageButton等,導致了點選Item中Button以外區域也會觸發Button點選事件。在網上找了相關方法,這裡記錄下,親測可行.. 1、在Item

ListView子項包含Button按鈕監聽混亂解決辦法

ListView子項中包含Button按鈕,遇到監聽混亂這種問題對於初學者來說,可謂是焦頭爛額,加之網上的程式碼多是複製貼上,質量不高,也可能未能從根本上解決自己的問題,這裡我就簡要記錄下自己的一些嘗試和體會,僅以此文獻給廣大初學者。 Goods(實體類

Android RecyclerView 多Item的EditText焦點混亂資料錯亂的解決方法(更新)

最近在做畢業設計,使用了RecyclerView來做了以下個人資料的編輯介面。RecyclerView中包含了多種不同的Item,例如圖片裡面的 姓名,公司,部門,職位,郵箱的Item 裡面都包含一個EditText。 RecyclerView中Edi

ListView動態新增EditText並對其中的資料進行儲存和由於複用引起的Editext的內容顯示異常的解決方案

public class AddAdapter extends BaseAdapter { private Context context; //需要增加的條目用一個Map儲存 private Map edItem; //記錄增加的條目數,作為下標給deItem賦值,可以不要

react native ListView資料變了,但是ListView不重新整理的解決方法

適用條件 ListView的資料型別是陣列物件,物件的某些個屬性需要用到介面的響應中,例如,{text: 'row', selected: true} 點選時selected = !select

Listview、RecyclerView的item包含可以點選的控制元件,點選衝突解決辦法

在item的根佈局中新增: android:descendantFocusability="blocksDescendants" 可點選的子item新增 android:focusable="f

AndroidListView滑動時資料混亂

主要分析Android ListView滾動過程中圖片顯示重複、錯亂、閃爍的原因及解決方法,順帶提及ListView的快取機制。 1、原因分析 ListView item快取機制:為了使得效能更優,ListView會快取行item(某行對應的View)。ListView通過adapter的getV

解決Listview控制元件資料實時更新產生閃爍!

將多個項新增到 ListView 的首選方法是使用 ListView.ListViewItemCollection(通過 ListView 的 Items 屬性訪問)的 AddRange 方法。這使您得以在一個操作中就可