Edit text loses content in list view on scrolling

2019-08-17 16:19发布

问题:

I have multiple edit text in list view. Number of edit texts is not fixed. When list view is scrolled edit text loses its content or some other edit text that is in focus shows value of some other edit text. I have tried solutions provided on Stack Overflow but nothing is helping out.

I have declared a hash map in which I'm storing position and value and then setting text in edit text from hash map but somewhere hash map is overwriting values in previously stored positions.

If code is required kindly let me know. I will update my question with my code.

Updating my question with my code that I have tried-

public class JunkTabAdapter extends ArrayAdapter<JunkTabBean> {

    private Activity mContext;
    /* android.graphics.Typeface face; */
    private int listItemForFile;
    private static ArrayList<JunkTabBean> itemList = new ArrayList<JunkTabBean>();

    private ListView download_row;
    ImageLoader imageloader;
    long fileLength;
    String getImage, saveinternalImagePath;
    Bitmap getBitmapImage;
    HomeLoader hl;
    NewImageLoader img;
    String fromWhere;

    String value="";
    String qty="";
    List<Integer> totAmtList = new ArrayList<Integer>();
    JunkTab junkTab;
    public int totAmt=0;

    ViewHolder holder;

    Map<Integer,String>  map = new HashMap<Integer,String>();
    int count=0;
    public JunkTabAdapter(Activity context, int listItemForFile,
            ArrayList<JunkTabBean> itemList,String fromWhere,JunkTab junkTab) {
        super(context, listItemForFile, itemList);
        this.mContext = context;
        this.listItemForFile = listItemForFile;
        this.itemList = itemList;
        this.fromWhere=fromWhere;
        this.junkTab=junkTab;

        img=new NewImageLoader(context);
    }

    public int getCount() {
        return itemList.size();
    }

    public JunkTabBean getItem(JunkTabBean position) {
        return position;
    }

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

    public class ViewHolder {

        public ImageView imgItem;
        public ImageView imgInfo;
        public ImageView imgDel;
        public EditText edQty;
        public TextView tvAmt;
        public TextView tvTotAmt;
        public View viewDivider;

        int reference;

    }
    // create a new ImageView for each item referenced by the Adapter
    public View getView(final int position, View convertView, ViewGroup parent) {



          View row = convertView; 

          if (row == null) {

                holder = new ViewHolder();

                LayoutInflater vi = (LayoutInflater)    
                        mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
                row = vi.inflate(R.layout.junktabcomponent, null);

                holder = new ViewHolder();
                  holder.imgItem = (ImageView)row.findViewById(R.id.imgItem);
                  holder.imgDel = (ImageView)row.findViewById(R.id.imgDelete);
                  holder.imgInfo = (ImageView)row.findViewById(R.id.imgInfo);
                  holder. edQty = (EditText)row.findViewById(R.id.edQty); 
                  holder.tvAmt = (TextView)row.findViewById(R.id.tvAmt); 
                  holder.tvTotAmt = (TextView)row.findViewById(R.id.tvTotalAmt); 
                  holder.viewDivider = (View)row.findViewById(R.id.view1); 


                  row.setTag(holder);
                //  holder.edQty.setTag(itemList.get(position).getId());


            } else {

                holder = (ViewHolder) row.getTag();

            }


         /* LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(Service.LAYOUT_INFLATER_SERVICE);
          row = inflater.inflate(R.layout.junktabcomponent,null, false);
          holder = new ViewHolder();
          holder.imgItem = (ImageView)row.findViewById(R.id.imgItem);
          holder.imgDel = (ImageView)row.findViewById(R.id.imgDelete);
          holder.imgInfo = (ImageView)row.findViewById(R.id.imgInfo);
          holder. edQty = (EditText)row.findViewById(R.id.edQty); 
          holder.tvAmt = (TextView)row.findViewById(R.id.tvAmt); 
          holder.tvTotAmt = (TextView)row.findViewById(R.id.tvTotalAmt); 
          holder.viewDivider = (View)row.findViewById(R.id.view1); */

         // holder.edQty.setText(qty);


          holder.edQty.setInputType(InputType.TYPE_CLASS_NUMBER);


              final JunkTabBean item = (JunkTabBean) itemList.get(position);


              img.DisplayImage(item.getImage(), holder.imgItem);
              holder.edQty.setHint(item.getUnits());

             // final int pos=(Integer) holder.edQty.getTag();

              if(map.containsKey(holder.reference))
              {
                  holder.edQty.setText(map.get(holder.reference).toString());
              }
              holder.edQty.addTextChangedListener(new TextWatcher()

              {

                @Override
                public void onTextChanged(CharSequence s, int start, int before, int count) {
                    /*value=value+s;
                    Log.e("value",value);*/


                }

                @Override
                public void beforeTextChanged(CharSequence s, int start, int count, int after) {
                    // TODO Auto-generated method stub

                }

                @Override
                public void afterTextChanged(Editable s) {
                    //map.put(pos,s.toString());

                    map.put(holder.reference,s.toString());

                    Log.e("map",""+map);
                    //holder.tvAmt.setText(""+(Integer.parseInt(item.getPrize()) * Integer.parseInt(map.get(holder.reference))));
                    //holder.tvAmt.setText(""+(Integer.parseInt(item.getPrize()) * Integer.parseInt(s.toString())));
                    /*totAmt=totAmt+(Integer.parseInt(item.getPrize()) * Integer.parseInt(s.toString()));
                    junkTab.setTotAmt(""+totAmt);*/
                    //qty=s.toString();

                }
            });

              holder.reference=position;
             // holder.edQty.setText(map.get(position));

              //  if(!map.get(position).contains(""))

              /*  if(!holder.edQty.getText().toString().equalsIgnoreCase(""))
              holder.tvAmt.setText(""+(Integer.parseInt(item.getPrize())* Integer.parseInt(holder.edQty.getText().toString())));*/

          return row;

    }



 }

回答1:

A generic solution for these kind of ListView problems is the View Holder pattern. It also has a small positive impact on performance.

Basically the idea is to create a class which represents the UI of one Listview item. It stores the View instances (EditTexts and whatnot) with their content intact.

private class MyViewHolder {
  public EditText myEditText;
  public ViewGroup myListItemLayout;
}

The View Holder object is created when a View is accessed for the first time in the list adapter's getView() and is then stored as the View objects' tags.

public View getView(int position, View convertView, ViewGroup parent) {

  MyViewHolder holder = new ViewHolder(); 

  // Get the data object for this row.
  MyDataItem item = items.get(position);

  // If we receive a null View we need to construct a one.
  if (convertView == null) {
    convertView = inflater.inflate(R.layout.my_list_item, parent, false);

    // Store the UI elements in the View Holder.
    holder.myEditText = (EditText)view.findViewById(R.id.editTextMyEditText);
    holder.myListItemLayout = (ViewGroup)view.findViewById(R.id.layoutMyListItemLayout);

    // Strore the View Holder as the View's tag.
    convertView.setTag(holder);
  }

  // Get the holder from the View's tag. 
  holder = (ViewHolder) convertView.getTag();

  ...
}

Now when the same View is later accessed again in getView() and convertView != null we will skip all the findViewById() code and go straight into:

holder = (ViewHolder) convertView.getTag();

Now the View has the correct content instead of some other list item's data.

As for rest of the getView() code you'll just replace all references to the View convertView with references to the View Holder i.e. instead of convertView.myTextView.setText("Hello world!") you'll use holder.myTextView.setText("Hello world!")

Some references:
https://developer.android.com/training/improving-layouts/smooth-scrolling.html#ViewHolder
http://www.javacodegeeks.com/2013/09/android-viewholder-pattern-example.html
https://dzone.com/articles/optimizing-your-listview
http://www.vogella.com/tutorials/AndroidListView/article.html#adapterperformance_holder



回答2:

Your adapter has to save text for each EditText :

  1. create a map to save values
  2. Define and set a generic TextWatcher for every EditText
  3. set a Tag on the editText (using its position or give any id you want) you'll use this tag as the key in the hashMap
  4. create a method to retrieve the value for a given EditText and save the HashMap values in cache or sharedPreferences.
  5. Check position of editText and populate values accordingly by retrieving it from stored cache/sharedPreferences.

follow Get all EditText values for hint only.