无法从 Listview 的 EditText 中获取值?

Posted

技术标签:

【中文标题】无法从 Listview 的 EditText 中获取值?【英文标题】:Can't get values from Listview's EditText? 【发布时间】:2017-01-03 03:33:40 【问题描述】:

我正在尝试从我的 Listview 中的 EditText 获取数据。我看到了很多类似的问题并得到了solution。但它在我的实现中引发了 NPE。

所以请指导我解决这个问题。

适配器

public class Coscho_adapter extends BaseAdapter 

    Context con;
    ArrayList<HashMap<String, String>> list;
    LayoutInflater mInflater;
    EditText marks;
    TextView studname, acname;

    public Coscho_adapter(Context co, ArrayList<HashMap<String, String>> list1) 
        list = list1;
        con = co;
        mInflater = (LayoutInflater) con.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    

    @Override
    public int getCount() 
        return list.size();
    

    @Override
    public Object getItem(int arg0) 
        return null;
    

    @Override
    public long getItemId(int arg0) 
        return 0;
    

    @Override
    public View getView(final int position, View convertView, ViewGroup parent) 
        ViewHolder holder;
        if(convertView==null)
            holder = new ViewHolder();
            convertView = mInflater.inflate(R.layout.sc_item,null,false);
            holder.marks = (EditText) convertView.findViewById(R.id.marks);
            holder.studname = (TextView) convertView.findViewById(R.id.stu_name);
            holder.acname = (TextView) convertView.findViewById(R.id.act_name);
            convertView.setTag(holder);
        else
            holder = (ViewHolder) convertView.getTag();
        

        int sno = position + 1;
        holder.studname.setText(sno + ". " + list.get(position).get("DESCRIPTOR"));
        holder.acname.setVisibility(View.GONE);
        holder.marks.setText(list.get(position).get("STUDENT_MARK"), TextView.BufferType.EDITABLE);
        int maxLength = 1;
        holder.marks.setFilters(new InputFilter[] new InputFilter.LengthFilter(maxLength), new InputFilterMinMax("0", "5"));
        desc_ids.add(list.get(position).get("DESCRIPTOR_ID"));

        return convertView;
    

    class ViewHolder 
        EditText marks;
        TextView studname, acname;
    

点击

@Override
public boolean onOptionsItemSelected(MenuItem item) 
    if(item.getItemId()==R.id.add)
    
       View v;
        ArrayList<String> scho = new ArrayList<String>();
        EditText et;
        if (co_adapter.getCount() != 0) 
        for (int i = 0; i < co_adapter.getCount(); i++) 
            v = mListView.getChildAt(i);
            et = (EditText) v.findViewById(R.id.marks);
            if (et != null) 
                scho.add(et.getText().toString());
                Log.e("SCH", et.getText().toString());
            
        
    
   
    return super.onOptionsItemSelected(item);

使用 TextWatcher 更新

现在我可以将编辑文本的值存储在一个数组中。但是当列表视图滚动时。这些值将更改为初始值。

 public class Coscho_adapter extends BaseAdapter 

            Context con;
            LayoutInflater mInflater;

            public Scholastic_adapter(Context context, ArrayList<HashMap<String, String>> list1) 
                sadap_list = list1;
                con = context;
                mInflater = LayoutInflater.from(context);
            

            @Override
            public int getCount() 
                return sadap_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) 
                ViewHolder holder;
                if(convertView==null)
                    holder = new ViewHolder();
                    convertView = mInflater.inflate(R.layout.sc_item,null,false);
                    holder.marks = (EditText) convertView.findViewById(R.id.marks);
                    holder.studname = (TextView) convertView.findViewById(R.id.stu_name);
                    holder.acname = (TextView) convertView.findViewById(R.id.act_name);
                    convertView.setTag(holder);
                else
                    holder = (ViewHolder) convertView.getTag();
                

                for (int i = 0; i < arrScMarks.length; i++) 
                    Log.e("Array > ", i +"> "+ arrScMarks[i]);
                

                int sno = position + 1;
                holder.ref = position;
                holder.studname.setText(sno + ". " + sadap_list.get(holder.ref).get("FIRST_NAME"));
                holder.acname.setText(sadap_list.get(holder.ref).get("ACTIVITY_NAME"));
                holder.marks.setText(arrScMarks[holder.ref]);
                holder.marks.addTextChangedListener(new GenericTextWatcher(holder.ref));


                return convertView;
            

            class ViewHolder 
                EditText marks;
                TextView studname, acname;
                int ref;
            
        

TextWatcher

private class GenericTextWatcher implements TextWatcher

        int position;

        private GenericTextWatcher(int pos) 
              this.position = pos;
        

        public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) 
        public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) 

        public void afterTextChanged(Editable editable) 
            String text = editable.toString();
            arrScMarks[position] = text;
            Log.e("Watcher > ", position +"> "+ arrScMarks[position] );
            
        

LOGCAT

输入数据

09-01 05:37:59.658 2466-2466/app E/Watcher >: 1> 
09-01 05:38:00.638 2466-2466/app E/Watcher >: 1> 1
09-01 05:38:02.518 2466-2466/app E/Watcher >: 2> 
09-01 05:38:02.798 2466-2466/app E/Watcher >: 2> 2
09-01 05:38:04.478 2466-2466/app E/Watcher >: 3> 
09-01 05:38:05.318 2466-2466/app E/Watcher >: 3> 3
09-01 05:38:06.878 2466-2466/app E/Watcher >: 4> 
09-01 05:38:07.758 2466-2466/app E/Watcher >: 4> 4
09-01 05:38:09.928 2466-2466/app E/Watcher >: 5> 
09-01 05:38:10.278 2466-2466/app E/Watcher >: 5> 5

滚动时

09-01 05:48:49.188 16362-16362/app E/Watcher >: 0> 0
09-01 05:48:49.538 16362-16362/app E/Watcher >: 1> 0
09-01 05:48:49.708 16362-16362/app E/Watcher >: 2> 0
09-01 05:48:49.888 16362-16362/app E/Watcher >: 3> 0
09-01 05:48:50.268 16362-16362/app E/Watcher >: 4> 0
09-01 05:48:50.538 16362-16362/app E/Watcher >: 5> 0
09-01 05:48:50.558 16362-16362/app E/Watcher >: 6> 0
09-01 05:48:50.868 16362-16362/app E/Watcher >: 8> 0
09-01 05:48:52.708 16362-16362/app E/Watcher >: 9> 0
09-01 05:48:52.768 16362-16362/app E/Watcher >: 0> 0
09-01 05:48:52.768 16362-16362/app E/Watcher >: 10> 0
09-01 05:49:20.648 16362-16362/app E/Watcher >: 9> 0
09-01 05:49:20.648 16362-16362/app E/Watcher >: 18> 0
09-01 05:49:20.738 16362-16362/app E/Watcher >: 8> 0
09-01 05:49:20.738 16362-16362/app E/Watcher >: 17> 0
09-01 05:49:20.818 16362-16362/app E/Watcher >: 7> 0
09-01 05:49:20.888 16362-16362/app E/Watcher >: 5> 0
09-01 05:49:20.888 16362-16362/app E/Watcher >: 15> 0
09-01 05:49:20.898 16362-16362/app E/Watcher >: 4> 0
09-01 05:49:20.898 16362-16362/app E/Watcher >: 14> 0
09-01 05:49:20.968 16362-16362/app E/Watcher >: 3> 0
09-01 05:49:20.968 16362-16362/app E/Watcher >: 13> 0
09-01 05:49:21.068 16362-16362/app E/Watcher >: 6> 0
09-01 05:49:21.068 16362-16362/app E/Watcher >: 16> 0
09-01 05:49:22.008 16362-16362/app E/Watcher >: 1> 0
09-01 05:49:22.008 16362-16362/app E/Watcher >: 11> 0
09-01 05:49:22.058 16362-16362/app E/Watcher >: 0> 0
09-01 05:49:22.058 16362-16362/app E/Watcher >: 10> 0
09-01 05:49:22.058 16362-16362/app E/Watcher >: 10> 0
09-01 05:49:22.098 16362-16362/app E/Watcher >: 9> 0
09-01 05:49:22.098 16362-16362/app E/Watcher >: 18> 0
09-01 05:49:22.108 16362-16362/app E/Watcher >: 9> 0

滚动后重新输入值时

09-01 05:56:32.288 16362-16362/app E/Watcher >: 1> 
09-01 05:56:32.288 16362-16362/app E/Watcher >: 10> 
09-01 05:56:32.288 16362-16362/app E/Watcher >: 10> 
09-01 05:56:32.288 16362-16362/app E/Watcher >: 1> 
09-01 05:56:33.438 16362-16362/app E/Watcher >: 1> 1
09-01 05:56:33.438 16362-16362/app E/Watcher >: 10> 1
09-01 05:56:33.438 16362-16362/app E/Watcher >: 10> 1
09-01 05:56:33.438 16362-16362/app E/Watcher >: 1> 1
09-01 05:56:34.918 16362-16362/app E/Watcher >: 11> 
09-01 05:56:34.918 16362-16362/app E/Watcher >: 2> 
09-01 05:56:36.248 16362-16362/app E/Watcher >: 11> 2
09-01 05:56:36.248 16362-16362/app E/Watcher >: 2> 2
09-01 05:56:37.918 16362-16362/app E/Watcher >: 3> 
09-01 05:56:37.918 16362-16362/app E/Watcher >: 12> 
09-01 05:56:37.918 16362-16362/app E/Watcher >: 3> 
09-01 05:56:39.008 16362-16362/app E/Watcher >: 3> 3
09-01 05:56:39.008 16362-16362/app E/Watcher >: 12> 3
09-01 05:56:39.008 16362-16362/app E/Watcher >: 3> 3

【问题讨论】:

从堆栈跟踪中可以清楚地看出,从mListView.getChildAt(i) 返回的视图为空 参考android - listview get item view by position 请在下面查看我的答案 我认为getItemId的方法是错误的。你也可以发布errorlog @Soham 请检查 Logcat。 【参考方案1】:

我首先尝试的方法是将 TextChangedListener 添加到 holder.marks,或者您可以添加一个按钮来保存输入到 EditText 中的新值。

当文本更改时,我会更改列表中的值。如果没有这个,当列表滚动为这一行时,您将失去数据用户:

        holder.marks.setText(list.get(position).get("STUDENT_MARK"), TextView.BufferType.EDITABLE);

将重写原来在列表中的学生标记。

编辑:我将我找到的适配器代码放在链接中,以防将来不可用。

private class MyListAdapter extends BaseAdapter

    @Override
    public int getCount() 
        // TODO Auto-generated method stub
        if(arrText != null && arrText.length != 0)
            return arrText.length;    
        
        return 0;
    

    @Override
    public Object getItem(int position) 
        // TODO Auto-generated method stub
        return arrText[position];
    

    @Override
    public long getItemId(int position) 
        // TODO Auto-generated method stub
        return position;
    

    @Override
    public View getView(int position, View convertView, ViewGroup parent) 

        //ViewHolder holder = null;
        final ViewHolder holder;
        if (convertView == null) 

            holder = new ViewHolder();
            LayoutInflater inflater = ListviewActivity.this.getLayoutInflater();
            convertView = inflater.inflate(R.layout.lyt_listview_list, null);
            holder.textView1 = (TextView) convertView.findViewById(R.id.textView1);
            holder.editText1 = (EditText) convertView.findViewById(R.id.editText1);    

            convertView.setTag(holder);

         else 

            holder = (ViewHolder) convertView.getTag();
        

        holder.ref = position;

        holder.textView1.setText(arrText[position]);
        holder.editText1.setText(arrTemp[position]);
        holder.editText1.addTextChangedListener(new TextWatcher() 

            @Override
            public void onTextChanged(CharSequence arg0, int arg1, int arg2, int arg3) 
                // TODO Auto-generated method stub

            

            @Override
            public void beforeTextChanged(CharSequence arg0, int arg1, int arg2,
                    int arg3) 
                // TODO Auto-generated method stub

            

            @Override
            public void afterTextChanged(Editable arg0) 
                // TODO Auto-generated method stub
                arrTemp[holder.ref] = arg0.toString();
            
        );

        return convertView;
    

    private class ViewHolder 
        TextView textView1;
        EditText editText1;
        int ref;
    



新编辑:

删除您的 GenericTextWatcher 并改用它。当我使用您的 TextWatcher 实现时它不起作用,我像这样更改了它,这对我有用。

holder.getEditText().addTextChangedListener(new TextWatcher() 
        @Override
        public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) 

        

        @Override
        public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) 

        

        @Override
        public void afterTextChanged(Editable editable) 
            String text = editable.toString();
            ARR[holder.getPosition()] = text;
            Log.e("Watcher > ", holder.getPosition()+"> "+ ARR[holder.getPosition()] );
        
    );

【讨论】:

嗨。抱歉我不能早点回答。您的 EditText 标记是一个全局变量。它应该是一个私有的最终变量。另外,我可以给出的一条建议是我建议你应该使用 ViewHolder 模式。甚至 Android 开发人员都说我们应该使用该模式 :) 我无法将 EditText 变量更改为 final。给我看一些代码。我已经更新了代码。 好的,我有空闲时间尝试解决问题。 好的,我找到了一些东西。我测试了这个方法,它工作正常。 webplusandroid.com/… 我的方法看起来也差不多。我不知道我哪里出错了?【参考方案2】:

您需要先从 edittext 中删除 TextWatcher,然后才能在其中设置文本

if (holder.marks.getTag() != null) 
   GenericTextWatcher oldWatcher = (GenericTextWatcher) holder.marks.getTag();
   holder.marks.removeTextChangedListener(oldWatcher);
   holder.marks.setText(arrScMarks[holder.ref]);

//then set new textwatcher to edittext with current position 
GenericTextWatcher watcher;
watcher = new GenericTextWatcher(position);
holder.marks.addTextChangedListener(watcher);
holder.marks.setTag(watcher);

【讨论】:

【参考方案3】:

您获得 NPE 的原因可能是因为您的 getItem 返回 null。

@Override
  public Object getItem(int arg0) 
    return null;

您需要返回 Collection(Arraylist) 中的特定位置

 @Override
public Object getItem(int arg0) 
    return list.get(arg0);

【讨论】:

【参考方案4】:

替换这个:

    if (et != null)  // here you check if et,which is a textview if its null
        scho.add(et.getText().toString());
        Log.e("SCH", et.getText().toString());
    

有了这个:

    if (et.getText().toString())  // check if the text is null
        scho.add(et.getText().toString());
        Log.e("SCH", et.getText().toString());
    

【讨论】:

他从 getChildAt(int) 得到 null,你的回答没有解决问题【参考方案5】:

您正在使用的方法:

v = mListView.getChildAt(i);

属于 ViewGroup 超类,将仅返回 ListView 中当前可见的项目(因为它们被回收,没有理由将它们全部保存在内存中)。尝试在适配器的 getView() 方法中设置 OnClickListener:

public View getView(final int position, View convertView, ViewGroup parent) 
    ...

    convertView.setOnClickListener(new OnClickListener() 
        public void onClick(View v) 
            ...
            et = (EditText) v.findViewById(R.id.marks);
        
    ;

请注意,通常不需要为每个项目创建新的 OnClickListener 实例,并且会产生一些开销。您可以使用单个 OnClickListener 和标签来区分项目。

或者,您可以使用 ListView 的内置监听器:

https://developer.android.com/reference/android/widget/AdapterView.OnItemClickListener.html

【讨论】:

但我的 onclick 是 onOptionsItemSelected【参考方案6】:

Listview 的getChildAt(i) 仅返回设备上可见项目的值,而不是适配器中膨胀的所有项目的值,因此您将获得设备屏幕上可见项目的所有视图,否则 null。所以尝试只获取可见项目视图并处理NullPointerException,您可以进行检查:

     View v = mListView.getChildAt(i);
     if(v!=null)
       // your code
     

【讨论】:

请看截图。该列表在 onclick 期间可见【参考方案7】:

试试这个

@Override
public boolean onOptionsItemSelected(MenuItem item) 
if(item.getItemId()==R.id.add)

ArrayList<String> scho = new ArrayList<String>();
    EditText et;
    if (mListView.getChildCount() > 0) 
    for (int i = 0; i < mListView.getChildCount(); i++) 
       // if your view statrts with relative layout then 
         RelativeLayout rl=(RelativeLayout)mListView.getChildAt(i);
   // else 
         yourlayout lay =(yourlayout)mListView.getChildAt(i);

         EditText et=(EditText)lay.getChildAt(your edit text positin in lay)

        //  main thing is we have to follow chain logic to find out the EditText position

        System.out.println(et.getText().toString());
    
    
 
return super.onOptionsItemSelected(item);

【讨论】:

如果列表向下滚动很远,ListView 的视图将已经被回收并且值丢失。不过,这个解决方案适用于嵌套视图,我以前用过。

以上是关于无法从 Listview 的 EditText 中获取值?的主要内容,如果未能解决你的问题,请参考以下文章

如何从具有多个视图的 ListView 中的 EditText 获取文本?

ListView中EditText无法获取焦点

android - 在更改 EditText 值时无法更新列表视图

将数据从edittext发送到listview

如何从 ListView 中的所有 EditText 中检索值

在 ListView 适配器中初始化空的 EditText