关于notifyDatasetChanged刷新的奇怪行为

时间:2015-11-10 10:25:35

标签: android

背景

嗨,我是Android新手,并试图熟悉ListView。所以我决定为用户编写一个简单的程序来输入引号并按顺序显示它们。我实施StringAdapter并在每次用户确认时调用notifyDataSetChanged

问题

奇怪的是,ListView有时会更新最旧的引号,有时会更新较新的引号。我不知道这个问题。

Picture

请忽略view data按钮。在这种状态下,我输入了四个引号:

  1. 行情:hi - 签名:William Shakespeare
  2. 行情:你好 - 签名:William Shakespeare
  3. 行情:美德大胆,善良永不恐惧。 - 签名:William Shakespeare
  4. 行情:爱所有人,相信少数人,不做任何事。 - 签名:William Shakespeare
  5. (以相反的顺序,按时间顺序表示,它为4,3,2,1)

    代码

    主要活动

    public class storage extends AppCompatActivity {
    
        // the adapter
        private StringAdapter sa;
        // the edit text view 
        public EditText etString,etSignature;
        // the list view
        public ListView lv;
        // the array list to capture the quotes and signature
        private ArrayList<String[]> dataString = new ArrayList<String[]>();
    
        // add the string and notify
        public void addString(String[] s){
            this.dataString.add(0,s);
            ((BaseAdapter)this.lv.getAdapter()).notifyDataSetChanged();
        }
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_storage);
    
            // Link the view elements
            this.etString = (EditText) findViewById(R.id.etInput);
            this.etSignature = (EditText) findViewById(R.id.etSignature);
            this.lv = (ListView) findViewById(R.id.stringList);
            Button btn_confirm = (Button) findViewById(R.id.btnConfirm),
                    btn_viewData = (Button) findViewById(R.id.btnViewData);
    
            // load the adapter
            this.sa = new StringAdapter(this,this.dataString);
            lv.setAdapter(sa);
    
            btn_confirm.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    storage s = (storage) v.getContext();
    
                    // get the String
                    String sString = s.etString.getText().toString(),
                            sSignature = s.etSignature.getText().toString();
                    System.out.println("Quotes: " + sString + "\nSignature:" + sSignature);
    
                    // verify it is not empty
                    if (!sString.isEmpty()&&!sSignature.isEmpty()) {
                        // add new string and notify
                        s.addString(new String[]{s.etString.getText().toString(),
                                               s.etSignature.getText().toString()});
                        ((StringAdapter) s.lv.getAdapter()).print_stringData();
    
                        // prompt the result
                        Toast.makeText(s.getBaseContext(),
        "Enter Quotes from"+etSignature.getText().toString(),Toast.LENGTH_SHORT).show();
                    } else {
                        // prompt the result
                        Toast.makeText(s.getBaseContext(),
        "Please Enter Quotes and Signatures!",Toast.LENGTH_SHORT).show();
                    }
                }
            });
    
        }
    }
    

    StringAdapter

    public class StringAdapter extends BaseAdapter {
        private Context mContext;
    
        private ArrayList<String[]> dataStrings = new ArrayList<String[]>();
    
        public StringAdapter(Context c,ArrayList<String[]> dataStrings){this.mContext=c;this.dataStrings=dataStrings;}
    
        public int getCount(){return this.dataStrings.size();}
    
        public Object getItem(int position){ return this.dataStrings.get(position);}
    
        public long getItemId(int postion){ return (long) postion;}
    
        public void print_stringData(){
            System.out.println("String Adapter Output:");
            for(String [] s: this.dataStrings){
                System.out.println("Quotes: "+s[0]+"\nSignature:"+s[1]);
            }
        }
    
        public View getView(int position, View convertView, ViewGroup parent){
            LinearLayout ll;
            if(convertView == null){
                // set the linear layout
                ll = new LinearLayout(this.mContext);
                ll.setOrientation(LinearLayout.VERTICAL);
                ll.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
                        ViewGroup.LayoutParams.WRAP_CONTENT));
    
                // get the data and set the text inside
                String[] data = this.dataStrings.get(position);
                TextView //tvNo = new TextView(this.mContext),
                        tvString = new TextView(this.mContext),
                        tvSignature = new TextView(this.mContext);
                ll.addView(tvString);
                ll.addView(tvSignature);
    
    
                tvString.setText(data[0]);
                tvString.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,
                        LinearLayout.LayoutParams.WRAP_CONTENT));
    
                tvSignature.setText(data[1]);
                tvSignature.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,
                        LinearLayout.LayoutParams.WRAP_CONTENT));
                tvSignature.setGravity(Gravity.RIGHT);
            }
            else{
                ll = (LinearLayout) convertView;
            }
            return ll;
        }
    }
    

    评论

    有些人可能会注意到我总是将String[]添加到第一个元素。实际上我试图添加到最后一个。奇怪的行为仍然存在。

    环境

    Android SDK版本:API 23棒棒糖

    仿真器版本:Nexus S API 23

1 个答案:

答案 0 :(得分:1)

是的,当然,你得到了这个错误。为什么?由于ListView始终会在convertView getView函数中重复使用Adapter
看看你的if,else

else{
    ll = (LinearLayout) convertView;
}
return ll;

在此块中,您告诉adapter重用convertView,但您不会重新设置数据。结果,它将显示前一行的数据。
如何解决?只需在else块中设置数据,就像在if块中一样。
P / s:你应该学习如何在ViewHolder中使用ListView来避免在滚动时出现滞后现象。