列表视图中的 Edittext 值在屏幕超时时更改为默认值

Edittext values in listview changes to default on screen timeout

我有一个 listview,每行内有 edittext 个小部件。我在 custom adapter 中使用 viewholder 来跟踪所有视图。

但我的问题是,当我在我的 edittext 中输入一个值时,暂停直到我的屏幕超时,当你解锁 phone 时仍然在相同的 activity,默认 edittext 值被重新填充,覆盖我的编辑。

我在这里 (when listview scroll that time edittext set default value) 遵循了这个建议,考虑到我可能没有正确使用 viewholder 但仍然面临同样的问题。就像 getView() 一直被调用,完全重新绘制我的视图。

任何 ideas/suggestions 解决方法?

package com.shop.shopOfficer;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Filter;
import android.widget.Filterable;
import android.widget.ImageView;
import android.widget.TextView;

import com.shopOfficer.R;

import java.util.ArrayList;
import java.util.List;

/**
 * Created by steve on 2/15/16.
 */
public class ProductListAdapter extends BaseAdapter implements Filterable {
    List<ProductModel> mStringFilterList;
    ValueFilter valueFilter;

    private Activity activity;
    private LayoutInflater inflater;
    private List<ProductModel> modelItems;

    private AddRemoveProductInterface myActivityInterface;

    public ProductListAdapter(Activity activity, List<ProductModel> modelItems, AddRemoveProductInterface myActivityInterface) {
        this.activity = activity;
        this.modelItems = modelItems;
        mStringFilterList = modelItems;
        this.myActivityInterface = myActivityInterface;
    }

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

    @Override
    public Object getItem(int location) {
        return modelItems.get(location);
    }

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

    @Override
    public View getView(final int position, View convertView, ViewGroup parent) {
        final ViewHolderItem viewHolder;

        if (convertView == null) {

            // inflate the layout
            inflater = (LayoutInflater) activity
                    .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            convertView = inflater.inflate(R.layout.product_item_row, null);
            // well set up the ViewHolder
            viewHolder = new ViewHolderItem();
            viewHolder.tvTitle = (TextView) convertView.findViewById(R.id.tv2);
            viewHolder.price = (TextView) convertView.findViewById(R.id.price);
            viewHolder.p = (TextView) convertView.findViewById(R.id.p);
            viewHolder.minus = (Button) convertView.findViewById(R.id.minus);
            viewHolder.add = (Button) convertView.findViewById(R.id.add);
            viewHolder.quantity = (EditText) convertView.findViewById(R.id.num);
            viewHolder.quantity.addTextChangedListener(new MyTextWatcher(convertView, position));

            viewHolder.add.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    //get the value of edittext
                    //add one item
                    int added_item = Integer.parseInt(viewHolder.quantity.getText().toString()) + 1;
                    viewHolder.quantity.setText("" + added_item);
                }
            });
            viewHolder.minus.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {

                    int removed_item = Integer.parseInt(viewHolder.quantity.getText().toString()) - 1;
                    if (removed_item >= 0) {

                        viewHolder.quantity.setText("" + removed_item);
                    } else {

                    }
                }
            });
            // store the holder with the view.
            convertView.setTag(viewHolder);

        } else {
            // we've just avoided calling findViewById() on resource everytime
            // just use the viewHolder
            viewHolder = (ViewHolderItem) convertView.getTag();
        }

        // object item based on the position
        final ProductModel m = modelItems.get(position);
        viewHolder.tvTitle.setText(m.getname());
        viewHolder.price.setText("(" + m.getPrice() + ")");
        viewHolder.p.setText(m.getPrice());
        viewHolder.quantity.setTag(m);
        viewHolder.quantity.setText(String.valueOf(m.getTQuantity()));

        convertView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(inflater.getContext(), EditProduct.class);
                intent.putExtra("name", m.getname());
                intent.putExtra("price", m.getPrice());
                intent.putExtra("description", m.getproductDesc());
                intent.putExtra("image_url", m.getImage_url());
                inflater.getContext().startActivity(intent);
            }
        });
        return convertView;
    }

    @Override
    public Filter getFilter() {
        if (valueFilter == null) {
            valueFilter = new ValueFilter();
        }
        return valueFilter;
    }

    private class ValueFilter extends Filter {
        @Override
        protected FilterResults performFiltering(CharSequence constraint) {
            FilterResults results = new FilterResults();
            if (constraint != null && constraint.length() > 0) {
                ArrayList<ProductModel> filterList = new ArrayList<>();
                for (int i = 0; i < mStringFilterList.size(); i++)
                    if ((mStringFilterList.get(i).getname().toUpperCase())
                            .contains(constraint.toString().toUpperCase()) ||
                            (mStringFilterList.get(i).getproductDesc().toUpperCase())
                                    .contains(constraint.toString().toUpperCase())) {


                        ProductModel m = new ProductModel(mStringFilterList.get(i)
                                .getname(), mStringFilterList.get(i)
                                .getproductId(), mStringFilterList.get(i)
                                .getImage_url(), mStringFilterList.get(i)
                                .getPrice(), mStringFilterList.get(i)
                                .getproductDesc());

                        filterList.add(m);
                    }
                results.count = filterList.size();
                results.values = filterList;
            } else {
                results.count = mStringFilterList.size();
                results.values = mStringFilterList;

                //show no results were picked
                //(myActivityInterface).onSearchEmpty("No results found");
            }
            return results;

        }

        @Override
        protected void publishResults(CharSequence constraint,
                                      FilterResults results) {
            //if(results)
            modelItems = (List<ProductModel>) results.values;
            if (modelItems.size() > 0) {

                notifyDataSetChanged();
            } else {
                (myActivityInterface).onSearchEmpty("No results found");
            }
        }

    }

    static class ViewHolderItem {

        TextView tvTitle, price, p;
        Button add, minus;
        EditText quantity;
    }

    private class MyTextWatcher implements TextWatcher {
        View view;
        int position;

        public MyTextWatcher(View convertView, int position) {
            this.view = convertView;
            this.position = position;
        }

        @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) {
            EditText qtyView = (EditText) view.findViewById(R.id.num);
           // ProductModel m = modelItems.get(position);
            String qtyString = s.toString().trim();
            int quantity = qtyString.equals("") ? 0:Integer.valueOf(qtyString);
            ProductModel m = (ProductModel)qtyView.getTag();
            if(m.getTQuantity() != quantity) {
                m.setTQuantity(quantity);
                String price = ((TextView) view.findViewById(R.id.p))
                        .getText().toString();
                String name = ((TextView) view.findViewById(R.id.tv2))
                        .getText().toString();
                int database_position = 1 + position;
                Log.d("my position", "" + position);
                Log.d("my value", s.toString() + price);
                (myActivityInterface).onAdded(s.toString().trim(), price, database_position, name);
            }
        }
    }
}

Activity代码:

public class ProductList extends AppCompatActivity implements AddRemoveProductInterface {

    ListView listView, checkout_listview;
    EditText inputSearch;
    ProductListAdapter adapter;
    ProductCheckoutAdapter checkout_adapter;
    ProductHandler productDB;
    String tag_json_obj = "json_obj_req";
    TextView total;
    String unformatted_number;
    String c_phone, c_zip, c_name, total_amount, checkout_id;
    Boolean c_extras;
    fr.castorflex.android.smoothprogressbar.SmoothProgressBar progbar;
    Button button;
    byte[] b;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_product_list);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
        total = (TextView) findViewById(R.id.total);
        total.setText("0.00");
        Intent i = getIntent();
        Bundle extras = i.getExtras();
        if (extras == null) {
            //is null
            c_extras = false;
        } else {
            //has extras
            c_extras = true;
            b = extras.getByteArray("picture");
            c_phone = i.getStringExtra("phone");
            c_zip = i.getStringExtra("zip");
            c_name = i.getStringExtra("name");
            total_amount = i.getStringExtra("total_amount");
            checkout_id = i.getStringExtra("checkout_id");
            if (total_amount == null) {
                total.setText("0.00");
            } else {

                total.setText(total_amount);
            }
            // Toast.makeText(getApplicationContext(), total_amount, Toast.LENGTH_LONG).show();

        }

        productDB = new ProductHandler(this);
       /* sbv = (SlideBottomPanel) findViewById(R.id.sbv);*/

        progbar = (fr.castorflex.android.smoothprogressbar.SmoothProgressBar) findViewById(R.id.prog1);
        listView = (ListView) findViewById(R.id.list);
       // listView.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
        checkout_listview = (ListView) findViewById(R.id.checkout_list);
        // insert data into the list before setting the adapter
        // otherwise it will generate NullPointerException  - Obviously
        productListRequest();
        showProductFromTable();
        inputSearch = (EditText) findViewById(R.id.inputSearch);
        inputSearch.addTextChangedListener(new TextWatcher() {

            @Override
            public void onTextChanged(CharSequence cs, int arg1, int arg2, int arg3) {
                // When user changed the Text
               /* ProductList.this.myList.getFilter().filter(cs);*/
                if (cs.length() > 0) {
                    adapter.getFilter().filter(cs);
                } else {
                    TextView search = (TextView) findViewById(R.id.no_results);
                    search.setVisibility(View.INVISIBLE);
                    adapter.getFilter().filter(cs);
                }

            }

            @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
            }
        });

        final LinearLayout animated_layout = (LinearLayout) findViewById(R.id.list_animated);
        //animating product sold list
        button = (Button) findViewById(R.id.submit);
        if (total.getText().toString().equals("0.00")) {
            button.setEnabled(false);
        } else {
            button.setEnabled(true);
        }
        button.setOnClickListener(new View.OnClickListener() {
            @TargetApi(Build.VERSION_CODES.HONEYCOMB)
            @Override
            public void onClick(View v) {
                Log.d("JSON PROD:", productDB.composeProductSolddJSONfromSQLite());
                Intent intent = new Intent(getApplicationContext(), CustomerIdentify.class);
                intent.putExtra("total_sld", unformatted_number);
                //send extras if exist to identify activity
                if (c_extras) {
                    intent.putExtra("picture", b);
                    intent.putExtra("c_phone", c_phone);
                    intent.putExtra("c_extras", c_extras);
                    intent.putExtra("c_zip", c_zip);
                    intent.putExtra("c_name", c_name);
                }
                startActivity(intent);
              
            }
        });
    }

    private void showProductFromTable() {
        //progbar.setVisibility(View.INVISIBLE);
        ArrayList<ProductModel> modelArrayList = productDB.loadProduct();
        //adding it to the list view.
        adapter = new ProductListAdapter(this, modelArrayList, this);
        listView.setAdapter(adapter);
        adapter.notifyDataSetChanged();
    }

    public void productListRequest() {
        progbar.setVisibility(View.VISIBLE);
        String url = "http://shopofficer.com/business/products/api";
        JsonArrayRequest jsonObjReq = new JsonArrayRequest(url,
                new Response.Listener<JSONArray>() {
                    @Override
                    public void onResponse(JSONArray response) {
                        Log.d("product list response:", response.toString());
                        //listView.setVisibility(View.VISIBLE);
                        progbar.setVisibility(View.INVISIBLE);

                        // Parsing json
                        for (int i = 0; i < response.length(); i++) {
                            try {
                                JSONObject obj = response.getJSONObject(i);
                                String name = obj.getString("name");
                                String price = obj.getString("price");
                                String description = obj.getString("description");
                                String image = obj.getString("image");
                                String product_id = obj.getString("id");
                                /*Log.d("my data is", id + title + description);*/
                                productDB.addProduct(product_id, name, price, description, image, "0");
                                showProductFromTable();
                            } catch (JSONException e) {
                                e.printStackTrace();
                            }

                        }
                    }
                }, new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError error) {
                VolleyLog.d("productlist error",
                        "Error: " + error.getMessage());

              /*  Crouton.makeText(AttendantList.this, "Something went wrong, please retry",
                       Style.ALERT, R.id.anchor).show();*/
                progbar.setVisibility(View.INVISIBLE);
            }
        }) {


            @Override
            public Map<String, String> getHeaders() throws AuthFailureError {
                HashMap<String, String> headers = new HashMap<String, String>();
                headers.put("session_id", getapikey());
                return headers;
            }
        };
        ShopOfficer.getInstance().getRequestQueue().getCache()
                .invalidate(url, true);
        // Adding request to request queue
        ShopOfficer.getInstance().addToRequestQueue(jsonObjReq, tag_json_obj);
    }


    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_select_product, menu);
        return true;
    }

    @Override
    public void onResume() {
        super.onResume();
        showProductFromTable();
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_add_product) {
            Intent intent = new Intent(getApplicationContext(), AddNewProduct.class);
            startActivity(intent);
            return true;
        }
        if (id == android.R.id.home) {
            finish();
            return true;
        }


        return super.onOptionsItemSelected(item);
    }

    @Override
    public void onAdded(String s, String price, int database_position, String name) {

        if (s.equals("")) {
        } else {
            //set total
            Double currentPrice = Double.valueOf(price);
            Double quantity = Double.valueOf(s);
            Double calculated = quantity * currentPrice;
            //Double priceDiff = Double.valueOf(df.format(extPrice - currPrice));
            productDB.update(database_position, "" + calculated);
            DecimalFormat df = new DecimalFormat("0.00##");
            //add commas thousands
            unformatted_number = String.valueOf(df.format(productDB.getTotalOfAmount()));
            double amount = Double.parseDouble(unformatted_number);
            DecimalFormat formatter = new DecimalFormat("#,###.00");
            total.setText("" + formatter.format(amount));
            if (total.getText().toString().equals(".00")) {
                total.setText("0.00");
            }
            //add product sold
            if (quantity < 1) {
                productDB.deleteSingleProductSold(Integer.valueOf(s));
            } else {
                productDB.addSale(database_position, name, String.valueOf(calculated), s);
            }
            if (total.getText().toString().equals("0.00")) {
                button.setEnabled(false);
            } else {
                button.setEnabled(true);
            }

        }
    }

    @Override
    public void onRemoved(String s) {
        total.setText("");
    }

    @Override
    public void onSearchEmpty(String s) {
        // Toast.makeText(getApplicationContext(), s, Toast.LENGTH_LONG).show();
        TextView search = (TextView) findViewById(R.id.no_results);
        search.setVisibility(View.VISIBLE);
        search.setText(s);
    }
}

视图和视图持有者只是暂时与一行相关联。这意味着任何编辑过的数据都需要存储在别处。 否则,每次重建视图或为不同的行重新使用时,信息都会丢失,例如滚动或重建视图时。

一种可能的解决方案是将其添加到模型中:

  • 将数据(数量)添加到ProductModel。 (the_quantity)

  • 向 viewholder 添加位置属性 (the_position)。 这是必需的,因为听众是匿名的 类。他们看到 position 参数的值(副本)及其实例化时的值。
    这就是编译器有时会抱怨 position 参数不是最终参数的原因,这通常意味着有问题:您应该只在回调之外引用它。

  • UI -> 模型:将编辑后的值存储在模型中(在两个侦听器中)

    public void onClick(View v) {
        //get the value of edittext
        //add one item
        int added_item = Integer.parseInt(viewHolder.quantity.getText().toString()) + 1;
    
        // Store the value in the model
        // We use the position from the viewholder,
        // **not** the method's parameter (which contain 
        // the value when the listener was created)
        modelItems.get(viewHolder.the_position).the_quantity = added_item;
    
        viewHolder.quantity.setText("" + added_item);
    }
    
  • 模型 -> UI:每次更新 UI,不仅是在创建视图时

    // object item based on the position
    final ProductModel m = modelItems.get(position);
    viewHolder.tvTitle.setText(m.getname());      
    
    // update the viewholder's position 
    viewHolder.the_position = position;
    viewHolder.quantity.setText("" + m.the_quantity)
    
    return convertView;