二、Android 解决在ListView历史复用中Edittext数据显示混乱

时间:2021-11-22 09:28:04

二、ListView的子项中包含EditText,由于复用引起的Editext中的内容显示异常的解决方案

  转至 http://blog.csdn.net/dream_remote/article/details/44262361

这是小生的第一篇博文。萌发写博客的念头并不是一时的脑热,早在上大学的时候就有写写博客的想法,由于那时没有一点经历,这想法也就胎死腹中。算下来,真正开始工作也已经有半年了,在网上看到各种达人的文章,受益匪浅,于是,决定自己也开始写博客。不求太多回报,只希望能将自己学到的东西与大家一起分享下,如果,自己的某个想法能帮助到别人,那真是我莫大的幸福了。好了,废话到此,开正文。

        最近做的一个项目需要在ListView的子项中添加一个EditText组件,不必说,为了解决ListView的复用问题又要请Map同学帮忙了,平时遇到的TextView,ImageView,CheckBox等等这些组件只用在Map中记录下它们的状态或者内容就可以轻松解决复用问题,但EditText却另当别论,首先,EditText需要实时保存其中输入的内容,并且在它再次出现的时候其上应有的内容需要被正确复现;再者,Editext与别的组件另外不同的一点是,它还存在焦点的问题,由于复用的存在,焦点可能会同时落在多个EditText上!是一个很有意思的问题。为了保存EditText上输入的数据,需要在其上注册OnTextChangedListener监听事件,并在afterTextChanged()中写入存储操作,当EditText再次被显示出来时,在getView()中为EditText加上之前存储好的值,第一个问题感觉已经完美的解决了。但事情远没有那么简单,由于复用产生的焦点问题,你在操作这个EditText时,下面看不见的地方的EditText的监听也在偷偷运行的,等你输入完了再一滚动,就乱七八糟了。所以,必须解决焦点问题。我的方案是这样的:在Adapter中写两个内部类,它们分别继承于TextWatcher和OnFocusChangeListener,在EditText上分别注册上OnFocusChangeListener和OnTextChangedListener监听,通过OnFocusChangeListener监听事件,动态的改变TextWatcher,使它始终只作用在真正获得焦点的EditText上,这是大概思路。上代码了,只有Adapter部分。


[java]  view plain  copy
  1. public class ImproveDetailInputAdapter extends BaseAdapter {  
  2.   
  3.     private Holder holder;  
  4.     private Context context;  
  5.     private LayoutInflater inflater;  
  6.     // 用来存放输入的数据  
  7.     public HashMap<Integer, Object> inputContainer;  
  8.     // 这是我继承写的两个监听,没用匿名内部类,首先是为了方便对position这个变量进行操作,再者  
  9.     // Adapter中我只分别实例化了一个监听对象,这样对内存开支应该会小些,好吧,我是对Java的垃圾回收机制信不过。  
  10.     private MyFoucus myFoucus;  
  11.     private MyWatch myWatch;  
  12.   
  13.     public HashMap<Integer, Object> getInputContainer() {  
  14.         return inputContainer;  
  15.     }  
  16.   
  17.     // 构造函数  
  18.     public ImproveDetailInputAdapter(Activity context) {  
  19.         this.context = context;  
  20.         inflater = LayoutInflater.from(context);  
  21.         inputContainer = new HashMap<Integer, Object>();  
  22.         myFoucus = new MyFoucus();  
  23.         myWatch = new MyWatch();  
  24.     }  
  25.   
  26.     @Override  
  27.     public int getCount() {  
  28.   
  29.         return 20;  
  30.     }  
  31.   
  32.     @Override  
  33.     public Object getItem(int position) {  
  34.         // TODO Auto-generated method stub  
  35.         return null;  
  36.     }  
  37.   
  38.     @Override  
  39.     public long getItemId(int position) {  
  40.         // TODO Auto-generated method stub  
  41.         return 0;  
  42.     }  
  43.   
  44.     @Override  
  45.     public View getView(int position, View convertView, ViewGroup parent) {  
  46.         if (null == convertView) {  
  47.   
  48.             holder = new Holder();  
  49.             convertView = inflater.inflate(  
  50.                     R.layout.yhl_adapter_detail_input_adapter, null);  
  51.             holder.brand = (TextView) convertView  
  52.                     .findViewById(R.id.detail_brand);  
  53.             holder.station = (TextView) convertView  
  54.                     .findViewById(R.id.detail_station);  
  55.             holder.stockNum = (TextView) convertView  
  56.                     .findViewById(R.id.detail_stock_num);  
  57.             holder.type = (TextView) convertView.findViewById(R.id.detail_type);  
  58.             holder.unit = (TextView) convertView.findViewById(R.id.detail_unit);  
  59.             // 上面的部分完全可以忽略,直接看这里  
  60.             holder.input = (EditText) convertView  
  61.                     .findViewById(R.id.detail_input_num);  
  62.             // 注册上自己写的焦点监听  
  63.             holder.input.setOnFocusChangeListener(myFoucus);  
  64.   
  65.             convertView.setTag(holder);  
  66.         } else {  
  67.             holder = (Holder) convertView.getTag();  
  68.         }  
  69.         // setTag是个好东西呀,把position放上去,一会用  
  70.         holder.input.setTag(position);  
  71.   
  72.         View currentFocus = ((Activity) context).getCurrentFocus();  
  73.         if (currentFocus != null) {  
  74.             currentFocus.clearFocus();  
  75.         }  
  76.   
  77.         // 为了实现最小的内存开销,复用两个不同的监听对象,通过每次点击的事件来修正mywatch中的position;s  
  78.   
  79.         // 使用remove和add来区别开复用修正和手动添加;之所以费劲的加个remove又加个add也是为了能尽量减少些  
  80.         // 思考量,剔除修正EditText时的TextChange监听事件,整个世界都清净了。。。  
  81.         holder.input.removeTextChangedListener(myWatch);  
  82.         if (inputContainer.containsKey(position)) {  
  83.             holder.input.setText(inputContainer.get(position).toString());  
  84.         } else {  
  85.             holder.input.setText("");  
  86.         }  
  87.         holder.input.addTextChangedListener(myWatch);  
  88.         return convertView;  
  89.     }  
  90.   
  91.     class MyFoucus implements OnFocusChangeListener {  
  92.         // 当获取焦点时修正myWatch中的position值,这是最重要的一步!  
  93.         @Override  
  94.         public void onFocusChange(View v, boolean hasFocus) {  
  95.             if (hasFocus) {  
  96.                 int position = (int) v.getTag();  
  97.                 myWatch.position = position;  
  98.             }  
  99.         }  
  100.     }  
  101.   
  102.     class MyWatch implements TextWatcher {  
  103.         // 不得不吐槽一下这里,java的内部类机制怎么就和我想的不一样呢,外部依然能很轻松的访问这个“私有  
  104.         // 化的”position,我是不是该去看看《think in java》了。  
  105.         private int position;  
  106.   
  107.         @Override  
  108.         public void afterTextChanged(Editable s) {  
  109.             inputContainer.put(position, s.toString());  
  110.         }  
  111.   
  112.         @Override  
  113.         public void beforeTextChanged(CharSequence s, int start, int count,  
  114.                 int after) {  
  115.             // TODO Auto-generated method stub  
  116.   
  117.         }  
  118.   
  119.         @Override  
  120.         public void onTextChanged(CharSequence s, int start, int before,  
  121.                 int count) {  
  122.             // TODO Auto-generated method stub  
  123.   
  124.         }  
  125.   
  126.     }  
  127.   
  128.     class Holder {  
  129.         TextView brand;  
  130.         TextView station;  
  131.         TextView stockNum;  
  132.         TextView type;  
  133.         TextView unit;  
  134.         EditText input;  
  135.     }  
  136.   
  137. }