Java 在列表适配器中,如何保存值?

Java 在列表适配器中,如何保存值?,java,android,listview,android-arrayadapter,Java,Android,Listview,Android Arrayadapter,因此,我有一个自定义适配器,每行有两个EditText字段 除了将值保存在ArrayList中之外,我已经使大部分内容正常工作 这是我到目前为止所做的代码: private void holderTitleSavedOnScroll(final int position, IZUICartViewHolder holder) { if (!(position == (variantArrayList.size() - 1)) && holder.title != null

因此,我有一个自定义适配器,每行有两个EditText字段

除了将值保存在ArrayList中之外,我已经使大部分内容正常工作

这是我到目前为止所做的代码:

private void holderTitleSavedOnScroll(final int position, IZUICartViewHolder holder) {
    if (!(position == (variantArrayList.size() - 1)) && holder.title != null) {
        holder.title.setText(variantArrayList.get(position).getVariantTitle());
        final int finalPosition = position;
        holder.title.setOnFocusChangeListener(new OnFocusChangeListener() {
            @Override
            public void onFocusChange(View v, boolean hasFocus) {
                    final EditText newVariant = (EditText) v;
                    variantArrayList.get(finalPosition).setVariantTitle(newVariant.getText().toString());
            }
        });
    }
}
所以这实际上是我想要的,它在焦点改变时保存了值。除了一个问题,它只在焦点改变时保存值

这在大多数情况下都很好,除非用户实际按下一个按钮,整个视图都消失了。焦点从未改变,值也未设置

所以我猜你们都在想,是的,让我们调用AddContextChangedListener并附加一个TextWatcher,添加如下内容:

        holder.title.setText(variantArrayList.get(position).getVariantTitle());
        final int finalPosition = position;
        final EditText holderTitle = (EditText) holder.title;

        if (holderTitle.getTag() != null) {
            final TextWatcher textWatcher = 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) {
                        variantArrayList.get(finalPosition).setVariantTitle(s.toString());
                }

                @Override
                public void afterTextChanged(Editable s) {

                }
            };


            holder.title.addTextChangedListener(textWatcher);
            holder.title.setTag(true);
        }
不,那也不行。 当然,它确实保存了值,但是当您滚动时,它也会弄乱内容,因为listview重用了单元格,它认为一个单元格的值在另一个单元格中,然后从ArrayList设置值

我尝试过不同的方法,比如在改变值和内容时检查焦点,但它不起作用(原因或多或少很明显)

有没有创造性的解决方案

更新(包含更多代码):

建议的TextWatcher方法:

我的getView方法(这里有很多与此问题无关的代码):

holderTitleSavedOnScroll方法

private void holderTitleSavedOnScroll(final int position, IZUICartViewHolder holder) {
    if (!(position == (variantArrayList.size() - 1)) && holder.title != null) {

        holder.title.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                v.requestFocus();
            }
        });


        final int finalPosition = position;
        final EditText holderTitle = (EditText) holder.title;

        if (holderTitle != null) {
            holder.title.setText(variantArrayList.get(position).getVariantTitle());
        }

        holderTitle.addTextChangedListener(new EditVariantTextWatcher(variantArrayList.get(finalPosition)));

    }
}
TextWatcher类:

public class EditVariantTextWatcher implements TextWatcher {

private IZUIProductVariantContainer variantContainer;

protected EditVariantTextWatcher(IZUIProductVariantContainer variantContainer) {
    this.variantContainer = variantContainer;
}

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

}

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

}

@Override
public void afterTextChanged(Editable s) {
    variantContainer.setVariantTitle(s.toString());
}
}

我们可以借助
TextWatcher

最好使用模型来存储和检索EditText的值。

public class RowData {

    private String value;

    public String getValue() {
        return value;
    }

    public void setValue(String value) {
        this.value = value;
    }
} 
接下来是TextWatcher Listener

public class EditTextWatcher implements TextWatcher {

    private RowData data;

    public EditTextWatcher(RowData data) {
        this.data = data;
    }

    @Override
    public void afterTextChanged(Editable s) {
        data.setValue(s.toString());
    }

    @Override
    public void beforeTextChanged(CharSequence arg0, int arg1, int arg2,
            int arg3) {

    }

    @Override
    public void onTextChanged(CharSequence arg0, int arg1, int arg2, int arg3) {

    }

}
您的适配器类

         public class YourAdapter extends ArrayAdapter<RowData> {
                private ArrayList<RowData> data;
                private Context context;
            public YourAdapter(Context context, ArrayList<RowData> data) {
                    super(context, 0, data);
                    this.data = data;
                }
            @Override
            public View getView(final int position, View convertView, ViewGroup parent) {
                View v = convertView;
                final RowData row = data.get(position);
                final EditText edittext = (EditText) v.findViewById(R.id.edittext);
                if (edittext != null)
                   edittext.setText(row.getValue());
                edittext.addTextChangedListener(new EditTextWatcher(row));


                ///////Your Code
                /////
        }
}
公共类YourAdapter扩展了ArrayAdapter{
私有数组列表数据;
私人语境;
公共YourAdapter(上下文、ArrayList数据){
super(上下文,0,数据);
这个数据=数据;
}
@凌驾
公共视图getView(最终整数位置、视图转换视图、视图组父视图){
视图v=转换视图;
最终行数据行=data.get(位置);
最终编辑文本编辑文本=(编辑文本)v.findViewById(R.id.EditText);
如果(edittext!=null)
edittext.setText(row.getValue());
addTextChangedListener(新的EditTextWatcher(行));
///////你的代码
/////
}
}
//
edittext.addTextChangedListener(新的EditTextWatcher(行))此行将存储
每个EditText的数据,即使在创建单元格时滚动ListView
它将根据模型(RowData)设置值


像这样试试,希望这会对你有所帮助。

这可以通过仔细使用文本观察者来实现

在ViewHolder中包含对当前TextWatcher的引用。回收视图时,删除现有的TextWatcher并添加一个新的TextWatcher,并将其键入当前位置

下面是一个完整的工作示例,包括允许测试导航的状态保存:

public class EditTextListActivity extends ListActivity {

    private static final String SAVED_STATE_KEY = "saved_state_key";

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        EditTextAdapter editTextAdapter = new EditTextAdapter(this, R.layout.main);
        setListAdapter(editTextAdapter);

        // Restore our state, if there is any
        if (savedInstanceState != null) {
            List<String> savedStrings = savedInstanceState.getStringArrayList(SAVED_STATE_KEY);
            for (String savedString : savedStrings)
                editTextAdapter.add(new ListItem(savedString));
        } else {
            // Add some empty items so that we can see it in action
            for (int i = 0; i < 30; i++)
                editTextAdapter.add(new ListItem(""));
        }
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        ArrayList<String> arrayList = new ArrayList<String>();
        EditTextAdapter editTextAdapter = (EditTextAdapter) getListAdapter();
        for (int i = 0; i < editTextAdapter.getCount(); i++)
            arrayList.add(editTextAdapter.getItem(i).string1);
        outState.putStringArrayList(SAVED_STATE_KEY, arrayList);
    }

    /**
     * The object we have a list of, probably more complex in your app
     */
    static class ListItem {
        public String string1;

        ListItem(String string1) {
            this.string1 = string1;
        }
    }

    /**
     * ViewHolder which also tracks the TextWatcher for an EditText
     */
    static class ViewHolder {
        public TextView textView;
        public EditText editText;
        public TextWatcher textWatcher;
    }

    class EditTextAdapter extends ArrayAdapter<ListItem> {
        EditTextAdapter(Context context, int resource) {
            super(context, android.R.layout.simple_list_item_single_choice);
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            View rowView = convertView;
            if (rowView == null) {
                // Not recycled, inflate a new view
                rowView = getLayoutInflater().inflate(R.layout.main, null);
                ViewHolder viewHolder = new ViewHolder();
                viewHolder.textView = (TextView) rowView.findViewById(R.id.textview);
                viewHolder.editText = (EditText) rowView.findViewById(R.id.edittext1);
                rowView.setTag(viewHolder);
            }

            ViewHolder holder = (ViewHolder) rowView.getTag();
            // Remove any existing TextWatcher that will be keyed to the wrong ListItem
            if (holder.textWatcher != null)
                holder.editText.removeTextChangedListener(holder.textWatcher);

            final ListItem listItem = getItem(position);

            // Keep a reference to the TextWatcher so that we can remove it later
            holder.textWatcher = 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) {
                    listItem.string1 = s.toString();
                }

                @Override
                public void afterTextChanged(Editable s) {
                }
            };
            holder.editText.addTextChangedListener(holder.textWatcher);

            holder.editText.setText(listItem.string1);
            holder.textView.setText(Integer.toString(position));

            return rowView;
        }
    }
}

已知错误:当键盘打开时,EditText将失去初始焦点,有关该问题的讨论,请参阅。

是否删除任何现有的TextWatcher?尝试过该操作后,无效。我无法使其正常工作,滚动期间值会出错。每次重新使用新行时,都会触发文本监视程序PostTextChanged。有什么想法吗?@JoakimEngstrom你试过我的方法吗?或者共享完整的适配器类,或者更新问题本身?使用您的方法更新问题。还尝试了一些修改,但仍然会使用重用的值设置这些值,因为每次操作系统重用一行时都会触发afterTextChanged。
public class EditTextListActivity extends ListActivity {

    private static final String SAVED_STATE_KEY = "saved_state_key";

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        EditTextAdapter editTextAdapter = new EditTextAdapter(this, R.layout.main);
        setListAdapter(editTextAdapter);

        // Restore our state, if there is any
        if (savedInstanceState != null) {
            List<String> savedStrings = savedInstanceState.getStringArrayList(SAVED_STATE_KEY);
            for (String savedString : savedStrings)
                editTextAdapter.add(new ListItem(savedString));
        } else {
            // Add some empty items so that we can see it in action
            for (int i = 0; i < 30; i++)
                editTextAdapter.add(new ListItem(""));
        }
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        ArrayList<String> arrayList = new ArrayList<String>();
        EditTextAdapter editTextAdapter = (EditTextAdapter) getListAdapter();
        for (int i = 0; i < editTextAdapter.getCount(); i++)
            arrayList.add(editTextAdapter.getItem(i).string1);
        outState.putStringArrayList(SAVED_STATE_KEY, arrayList);
    }

    /**
     * The object we have a list of, probably more complex in your app
     */
    static class ListItem {
        public String string1;

        ListItem(String string1) {
            this.string1 = string1;
        }
    }

    /**
     * ViewHolder which also tracks the TextWatcher for an EditText
     */
    static class ViewHolder {
        public TextView textView;
        public EditText editText;
        public TextWatcher textWatcher;
    }

    class EditTextAdapter extends ArrayAdapter<ListItem> {
        EditTextAdapter(Context context, int resource) {
            super(context, android.R.layout.simple_list_item_single_choice);
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            View rowView = convertView;
            if (rowView == null) {
                // Not recycled, inflate a new view
                rowView = getLayoutInflater().inflate(R.layout.main, null);
                ViewHolder viewHolder = new ViewHolder();
                viewHolder.textView = (TextView) rowView.findViewById(R.id.textview);
                viewHolder.editText = (EditText) rowView.findViewById(R.id.edittext1);
                rowView.setTag(viewHolder);
            }

            ViewHolder holder = (ViewHolder) rowView.getTag();
            // Remove any existing TextWatcher that will be keyed to the wrong ListItem
            if (holder.textWatcher != null)
                holder.editText.removeTextChangedListener(holder.textWatcher);

            final ListItem listItem = getItem(position);

            // Keep a reference to the TextWatcher so that we can remove it later
            holder.textWatcher = 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) {
                    listItem.string1 = s.toString();
                }

                @Override
                public void afterTextChanged(Editable s) {
                }
            };
            holder.editText.addTextChangedListener(holder.textWatcher);

            holder.editText.setText(listItem.string1);
            holder.textView.setText(Integer.toString(position));

            return rowView;
        }
    }
}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal">

    <TextView
        android:id="@+id/textview"
        android:layout_width="0dp"
        android:layout_weight="1"
        android:layout_height="wrap_content" />

    <EditText
        android:id="@+id/edittext1"
        android:layout_width="0dp"
        android:layout_height="?android:attr/listPreferredItemHeightSmall"
        android:layout_weight="2"
        android:inputType="text" />

    <!-- This EditText is included to demonstrate problems with a naive approach. -->
    <EditText
        android:inputType="text"
        android:layout_width="0dp"
        android:layout_height="?android:attr/listPreferredItemHeightSmall"
        android:layout_weight="2" />
</LinearLayout>