每次滚动时都会调用 ListView 中的 addTextChangedListener

addTextChangedListener inside a ListView is called every time while scrolling

我有一个 ListView,每行都有一个 EditText(数量框)。当用户设置所需的数量时,新值会更新 SQLite 数据库中的相应列,然后我用修改后的值重新填充 ListView。 为了触发这个过程,我在 EditText 上使用了 addTextChangedListener,效果很好。

我的问题是每次滚动时都会调用监听器,这会触发上述过程,甚至没有触及数量框。

如何避免在滚动时触发 addTextChangedListener?我的 spinner.setOnItemSelectedListener 也出现了同样的问题。我试图让 getView 方法之外的侦听器但没有任何运气......:(

自定义 ListView:

public class PhotosListViewAdapter extends ArrayAdapter<ImageItemsSetter> {

        DeleteImageListener dListener;
        private Context context;
        private int layoutResourceId;
        private ArrayList<ImageItemsSetter> data = new ArrayList<ImageItemsSetter>();   

        //standard constructor
        public PhotosListViewAdapter(Context context, int layoutResourceId, ArrayList<ImageItemsSetter> data) {
            super(context, layoutResourceId, data);
            this.layoutResourceId = layoutResourceId;
            this.context = context;
            this.data = data;            
        }           

        static class ViewHolder {

            public ImageView Img; 
            public EditText quantity;
            public Spinner spinner;
            public Button delete;

        }

        @Override
        public View getView(final int position, View convertView, ViewGroup parent) {
            View row = convertView;
            ViewHolder holder = null;            

            ImageItemsSetter image = data.get(position);

        if (row == null) {
            LayoutInflater inflater = ((Activity) context).getLayoutInflater();
            row = inflater.inflate(layoutResourceId, parent, false);
            holder = new ViewHolder(); 

            holder.Img = (ImageView) row.findViewById(R.id.Img);

            holder.quantity = (EditText) row.findViewById(R.id.quantity);
            // holder.quantity.addTextChangedListener(new GenericTextWatcher(holder.quantity));           

            holder.spinner = (Spinner) row.findViewById(R.id.photo_format);
            holder.delete = (Button) row.findViewById(R.id.deleteImage);

            row.setTag(holder);
        } else {
            holder = (ViewHolder) row.getTag(); 
        }           

         holder.Img.setImageBitmap(image.getTheImage());            
         holder.quantity.setText(image.getQuantity());


        ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(context,
                R.array.formats_array, android.R.layout.simple_spinner_item);       
        adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);     
        holder.spinner.setAdapter(adapter);

        //The delete button
        holder.delete.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {           

                if (dListener != null) {  
                    dListener.onDeletePressed(position); 
                }       
            }           
            });      


        holder.spinner.setOnItemSelectedListener(new OnItemSelectedListener() {     

            @Override
            public void onItemSelected(AdapterView<?> parent, View view,
                    int pos, long id) {                         
                dListener.onFormatChanged(parent.getItemAtPosition(pos).toString(), data.get(position).getName());              
            }

            @Override
            public void onNothingSelected(AdapterView<?> parent) {
                // TODO Auto-generated method stub              
            }

        });

        holder.quantity.addTextChangedListener(new TextWatcher() {

               @Override
               public void afterTextChanged(Editable s) { }

               @Override    
               public void beforeTextChanged(CharSequence s, int start,
                 int count, int after) {  }

               @Override    
               public void onTextChanged(CharSequence s, int start,
                 int before, int count) {
                   dListener.onQuantityChanged(s.toString(), data.get(position).getName());
                }
              });


        return row;
        }


        /*
         private class GenericTextWatcher implements TextWatcher {

                private View view;              
                private GenericTextWatcher(View view) {
                    this.view = view;
                }                           


                // 3. saving the quantity box before it gets outside the visible area
                @Override
                public void afterTextChanged(Editable s) { 
                     final EditText editText = (EditText) view; 
                     dListener.onQuantityChanged(editText.getText().toString(), "tom");

                }

                @Override
                public void beforeTextChanged(CharSequence s, int start,
                        int count, int after) {

                }

                @Override
                public void onTextChanged(CharSequence s, int start,
                        int before, int count) {


                }
            }
            */



        //Interface to send selected image's position for deletion
        public void setDeleteImageListener(DeleteImageListener listener) {  
            this.dListener = listener;  
        } 

        public static interface DeleteImageListener { 
            public void onDeletePressed(int position);
            public void onQuantityChanged(String quantity, String name);
            public void onFormatChanged(String format, String name);
        }               

主机 activity 部分(这里我使用 2 个自定义接口接收响应):

@Override
public void onQuantityChanged(String quantity, String name) {
    System.out.println("quantity set to: " + quantity + " " + name );
    datasource.updateImageQuantiry(name, quantity);
    rePopulateList(); 

}

@Override
public void onFormatChanged(String format, String name) {
    System.out.println("format set to: " + format + " name: " + name);

}

这是因为您的适配器在您滚动时在视图上设置文本,这应该会启动您的侦听器。

此外,您应该只设置一次监听器,而不是每次调用 getView() 时都设置。

向您的 ListView 添加一个滚动侦听器,并在某处设置一个标志以了解 ListView 是否正在滚动。
然后在 onTextChanged 中,在调用您的侦听器之前检查该标志。
这将起作用,因为方法 AbsListView.OnScrollListener.onScrollStateChanged 在滚动发生之前被调用。

public abstract void onScrollStateChanged (AbsListView view, int scrollState)

Callback method to be invoked while the list view or grid view is being scrolled. If the view is being scrolled, this method will be called before the next frame of the scroll is rendered. In particular, it will be called before any calls to getView(int, View, ViewGroup).

您甚至可以让您的 class PhotosListViewAdapter 实现 OnScrollListener 接口,然后将您的适配器设置为 ListView 的滚动侦听器。这样您就可以管理适配器内的滚动标志状态。

public class PhotosListViewAdapter extends ArrayAdapter<String> implements AbsListView.OnScrollListener {

    public boolean scrolling;

    @Override
    public void onScrollStateChanged(AbsListView view, int scrollState) {
        scrolling = scrollState != SCROLL_STATE_IDLE ;
    }

    @Override
    public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {

    }

    //...
    //TextWatcher.onTextChanged()
    //if(!scrolling) dListener.onQuantityChanged(s.toString(), data.get(position));
    //...
}

//In your activity or fragment:
//myListView.setOnScrollListener(myPhotoListViewAdapter);