java - Android ListView 中包含的 EditText 内容未保存

标签 java android android-listview

在我的项目中,我必须向用户显示一个基本上包含 EditText 的 ListView。

这就像一份问卷,当他回答完问题后,他可以继续下去回答下一个问题。 (然后返回)

public class onAdapter extends BaseAdapter {
    List<PointVerification> mObjects;
    Context mContext;
    LayoutInflater mInflater;

    HashMap<Integer, List<ChoixPointVerification>> mChoix;
    HashMap<Integer, ReponsePointVerification> mReponses;
    HashMap<Integer, String> mReponsesActuel;
    Integer mPositionSelectionne;
    Integer mIdIntervention;


    /**
     * Constructeur
     * @param context

     * @param listePointsVerification Liste des points de vérification à afficher.
     * @param listeChoixPointsVerification liste des choix de points de vérification pour chaque point de vérification.
     * @param listeReponsesPointsVerification réponses déjà fournies pour chaque point de vérification
     * @param idIntervention Identifiant de l'intervention
     */
    public onAdapter(
            Context context,

            Integer idIntervention, 
            List<PointVerification> listePointsVerification,
            List<ChoixPointVerification>> listeChoixPointsVerification,
            ReponsePointVerification> listeReponsesPointsVerification) {

        this.mInflater = LayoutInflater.from(context);
        this.mContext = context;
        this.mObjects = listePointsVerification;

        this.mChoix = listeChoixPointsVerification;
        this.mReponses = listeReponsesPointsVerification;
        this.mIdIntervention = idIntervention;


        // préparation des réponses par position
        this.mReponsesActuel = new HashMap<Integer, String>();
    }


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

        final Integer idPointVerification = getItem(position).id;

        if (convertView == null)
        {
            row = mInflater.inflate(R.layout.intervention_reponses_controle_nombre, null);

            EditText edValeur = (EditText) row.findViewById(R.id.edValeur);
            // Ajout de l'évènement lorsque l'on change la valeur
            // evènement d'enregistrement
            edValeur.addTextChangedListener(new TextWatcher() 

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

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

                @Override
                public void afterTextChanged(Editable s) {
                    // This hashmap is a try workaround to the bug
                    // i register all modifications into this hashmap
                    mReponsesActuel.put(
                            idPointVerification,
                            s.toString());

                    // SAVE PROCEDURE
                    // REMOVED FOR THE EXAMPLE
                    // BUT I UPDATE MY DATABASE
                }
            });
        }
        else
        {
            row = convertView;
        }

        EditText edValeur = (EditText) row.findViewById(R.id.edValeur);

        // update of the text
        // it is the contained in the hashmap
        if (mReponsesActuel.containsKey(idPointVerification)) {
            String valeur = mReponsesActuel.get(idPointVerification);
            edValeur.setText(valeur);
        // otherwhise i will look into the database
        } else if (mReponses != null && mReponses.containsKey(idPointVerification)
                && mReponses.get(idPointVerification).valeur != null) {
            edValeur.setText(mReponses.get(idPointVerification).valeur);
        }
        else
        {
            edValeur.setText("");
        }

        return row;
    }
}

我不知道为什么,但是用户在ListView中向下移动,内容未保存并显示一些特殊值,例如其他EditText。我没有找到如何纠正这种行为,而且真的很匆忙。

基本上,我制作了一个 TextWatcher,它将数据注册到数据库中,并将数据注册到包含所有值的临时 HashMap 中。调用 GetView 时会回调该数据。如果我删除该初始化,EditText 将被删除。

注意:我在代码中做了一些测试,因此可能会出现不同的问题。

编辑

我上传了一个有问题的项目:http://dl.free.fr/rbqOhUfJF

以下是重现问题的步骤:

  1. 以 Debug模式启动项目

  2. 写在第一行A,第二行B,第三行C

  3. 向下滚动直到 C 隐藏

  4. 向上滚动到顶部。结果:没有更多文本。

如果仔细查看调试日志,您可以看到带有 afterText 的行。每次我们在第 2 部分中编写一些文本时,都会有一个带有事件注册的调试行。

但是在第 3 阶段,当你隐藏一个项目时。该 Activity 将以“”启动

结果:在第四阶段,加载“”字符串

最佳答案

为了加快大多数移动应用程序(Android iOS ...)中的速度,列表单元格通常会被回收。这可以节省内存,特别是对于长列表。因此,您必须获取新显示单元格的数据。当单元格移出屏幕时,其布局/ View 将被破坏。在您的情况下,您必须将编辑文本的文本保存在某处。这就是您尝试对 HashMap 执行的操作。

我在您的代码中没有发现任何特定错误。

如果问题是关于使用 HashMap 的“解决方法”,我确认对我来说,由您来保存编辑文本的状态。使用 HashMap 是实现此目的的一种方法。

顺便说一句,getItem(position).id 可以替换为 getItemId(position),这里就是为了这个目的。

不确定这是否能回答您的问题。

编辑

既然我正确理解了你的问题,我可以提供一些代码。我必须说,我对找到的解决方案并不完全满意,但至少它是有效的。

TextWatcher 的问题是您无法访问上下文和相应的 View 。

使用setOnFocusChangeListener解决了这个问题。这是我终于开始工作的代码。

public final class PointVerificationAdapter extends BaseAdapter {
    List<BasicNameValuePair> mObjects;
    Context mContext;
    LayoutInflater mInflater;
    HashMap<Integer, String> mReponsesActuel;
    ArrayList<String> myItems = new ArrayList<String>();

    public PointVerificationAdapter(
            Context context,
            List<BasicNameValuePair> listObjets
            ) {

        this.mInflater = LayoutInflater.from(context);
        this.mContext = context;
        this.mObjects = listObjets;

        for (int i = 0; i < 30; i++) {
            myItems.add(Integer.toString(i));
        }
    }

    @Override
    public int getCount() {
        return mObjects.size();
    }

    @Override
    public BasicNameValuePair getItem(int position) {
        return mObjects.get(position);
    }

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

    static class ViewHolder {
        EditText yourEditText;
    }

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

        ViewHolder holder = null;

        if (convertView == null)
        {
            holder = new ViewHolder();
            convertView = mInflater.inflate(R.layout.intervention_reponses_controle_nombre, parent, false);
            convertView.setId(position);
            holder.yourEditText = (EditText) convertView.findViewById(R.id.edValeur);

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

        ((TextView) convertView.findViewById(R.id.tvNom)).setText(Integer.toString(position));

        holder.yourEditText.setText(myItems.get(position));
        holder.yourEditText.setId(position);
        holder.yourEditText.setOnFocusChangeListener(new OnFocusChangeListener() {
            public void onFocusChange(View view, boolean hasFocus) {
                if (!hasFocus){
                    final int position = view.getId();
                    final EditText editText = (EditText) view;
                    myItems.set(position, editText.getText().toString());
                }
            }
        });

        return convertView;
    }

}

最终编辑

之前的代码可以工作,但我对此不满意,因为您要求的是 addTextChangedListener 而不是 onFocusChange

所以这是解决方案:

public final class PointVerificationAdapter extends BaseAdapter {
    List<BasicNameValuePair> mObjects;
    Context mContext;
    LayoutInflater mInflater;
    HashMap<Integer, String> mReponsesActuel;
    ArrayList<String> myItems = new ArrayList<String>();

    public PointVerificationAdapter(
            Context context,
            List<BasicNameValuePair> listObjets
            ) {

        this.mInflater = LayoutInflater.from(context);
        this.mContext = context;
        this.mObjects = listObjets;

        for (int i = 0; i < 30; i++) {
            myItems.add(Integer.toString(i));
        }
    }

    @Override
    public int getCount() {
        return mObjects.size();
    }

    @Override
    public BasicNameValuePair getItem(int position) {
        return mObjects.get(position);
    }

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

    static class ViewHolder {
        EditText yourEditText;
    }

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

        ViewHolder holder = null;

        if (convertView == null)
        {
            holder = new ViewHolder();
            convertView = mInflater.inflate(R.layout.intervention_reponses_controle_nombre, parent, false);
            convertView.setId(position);
            holder.yourEditText = (EditText) convertView.findViewById(R.id.edValeur);
            holder.yourEditText.setId(position);
            holder.yourEditText.addTextChangedListener(new GenericTextWatcher(holder.yourEditText));
            convertView.setTag(holder);
        }
        else
        {
            holder = (ViewHolder) convertView.getTag();
            holder.yourEditText.setId(position);
        }

        ((TextView) convertView.findViewById(R.id.tvNom)).setText(Integer.toString(position));

        holder.yourEditText.setText(myItems.get(position));

        return convertView;
    }

    private class GenericTextWatcher implements TextWatcher{

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

        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) {
            final int position = view.getId();
            final EditText editText = (EditText) view;
            myItems.set(position, editText.getText().toString());
        }
    }
}

关于java - Android ListView 中包含的 EditText 内容未保存,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19127524/

相关文章:

java - Delaunay 对带孔的二维多边形进行三角剖分

java - "Failed to attach to the remote VM"连接jdb到windows上的android模拟器

java - 使用android studio在android中通过单击java中的媒体播放器按钮来播放声音

android - Unresolved reference : getPreferences

android - 单击项目重新创建相同的 ListView

用于生成和使用生成的决策树的 Java 库

java - AWS Java Lambda Cognito - 无效的 lambda 触发器源

Android studio canary 5更新报错

具有自定义 View 层次结构的 Android + ListFragment

android - 在主类 findviewbyid 中声明 listview 不工作