自定义类变量被某个未知进程覆盖

时间:2017-06-14 16:42:06

标签: java android arrays arraylist

我有一个自定义类,它由一个静态ArrayList对象组成。由于某种原因,我似乎无法弄清楚,当我在另一个 ArrayList对象上调用clear()方法时,对象中的元素会被覆盖。这就是我所说的:

  

关于itemsArray.clear()行的注意事项,我将在下面进一步解释

public class AddItemsActivity extends AppCompatActivity{

// Global variables
// For the Description
private EditText descEditText;

// For the Price
private EditText priceEditText;

// Temporary array to store the list of items which will be passed into the Diner
public static ArrayList<Item> itemsArray = new ArrayList<>();

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

    // THIS HAS PROBLEM!!!!
    itemsArray.clear();
    // Set the content to use the activity_add_items xml file
    setContentView(R.layout.activity_add_items);

    final ItemsListAdapter adapter = new ItemsListAdapter(this, itemsArray);
    // Find the ListView to display the adapter on
    ListView listView = (ListView) findViewById(R.id.items_list);

    // Set the ListView with the adapter
    listView.setAdapter(adapter);

    Button addDetailsFragment = (Button) findViewById(R.id.add_item_button);
    addDetailsFragment.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            // Setting up a new dialog
            final Dialog dialog = new Dialog(AddItemsActivity.this);
            dialog.setContentView(R.layout.item_add_dialog);
            dialog.setCancelable(true);
            dialog.setTitle(R.string.add_item_title);
            dialog.getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
            dialog.setCanceledOnTouchOutside(false);

            Button num1 = (Button) dialog.findViewById(R.id.key_1);
            Button num2 = (Button) dialog.findViewById(R.id.key_2);
            Button num3 = (Button) dialog.findViewById(R.id.key_3);
            Button num4 = (Button) dialog.findViewById(R.id.key_4);
            Button num5 = (Button) dialog.findViewById(R.id.key_5);
            Button num6 = (Button) dialog.findViewById(R.id.key_6);
            Button num7 = (Button) dialog.findViewById(R.id.key_7);
            Button num8 = (Button) dialog.findViewById(R.id.key_8);
            Button num9 = (Button) dialog.findViewById(R.id.key_9);
            Button num0 = (Button) dialog.findViewById(R.id.key_0);
            Button numPeriod = (Button) dialog.findViewById(R.id.key_period);
            Button numDel = (Button) dialog.findViewById(R.id.key_del);
            Button numAdd = (Button) dialog.findViewById(R.id.key_add_item);

            // Properties for description field
            descEditText = (EditText) dialog.findViewById(R.id.details_desc_input);

            // Properties for price field
            priceEditText = (EditText) dialog.findViewById(R.id.details_price_input);

            // Keypad OnClickListener to append or delete digits in the price input field
            View.OnClickListener keyOnClickListener = new View.OnClickListener() {
                @Override
                // Program logic when one of the buttons is pressed
                public void onClick(View v) {
                    priceEditText.requestFocus();
                    CharSequence originalText = priceEditText.getText();
                    Button button = (Button)v;
                    // Prevents app from crashing when trying to delete an empty field
                    if (button.getText() == getString(R.string.details_button_delete_text)
                            && originalText != null && originalText.length()>0) {
                        // Deletes one character/digit, deletes '$' if required
                        if (originalText.length() == 2 && originalText.charAt(0) == '$') {
                            priceEditText.setText("");
                        } else {
                            priceEditText.setText("");
                            priceEditText.append(originalText.subSequence(0, originalText.length() - 1));
                        }
                        // Delete key does nothing instead of displaying 'Del'
                    } else if (button.getText() == getString(R.string.details_button_delete_text)) {
                        priceEditText.append("");
                        // Prevents a second period from appearing in the field
                    } else if (button.getText().toString()
                            .equals(getString(R.string.details_button_period_text))
                            && originalText.toString().contains(".")) {
                        priceEditText.append("");
                        // Adds a $ sign
                    } else if (originalText == null || originalText.length() == 0) {
                        priceEditText.append("$");
                        priceEditText.append(button.getText());
                        // Else, input the digit pressed
                    } else {
                        priceEditText.append(button.getText());
                    }
                }
            };

            // Add key OnClickListener to  add items into Diner's editItemsArray
            View.OnClickListener addOnClickListener = new View.OnClickListener() {
                @Override
                // Program logic when one of the buttons is pressed
                public void onClick(View v) {
                    priceEditText.requestFocus();
                    CharSequence originalText = priceEditText.getText();
                    Button button = (Button)v;
                    // If the input field is empty, do nothing. Else, add the items
                    if (originalText == null && button.getText() == getString(R.string.details_button_add_text)) {
                        priceEditText.append("");
                    // Adds the items into the editItemsArray ArrayList
                    } else {
                        Item itemToAdd = new Item(descEditText.getText().toString(),
                                Double.parseDouble(priceEditText.getText().toString().replace("$",
                                        "")));
                        itemsArray.add(itemToAdd);
                        adapter.notifyDataSetChanged();
                        dialog.dismiss();
                        Log.e("add item", "works");
                    }
                    Log.e("line1", "works");
                }
            };

            num1.setOnClickListener(keyOnClickListener);
            num2.setOnClickListener(keyOnClickListener);
            num3.setOnClickListener(keyOnClickListener);
            num4.setOnClickListener(keyOnClickListener);
            num5.setOnClickListener(keyOnClickListener);
            num6.setOnClickListener(keyOnClickListener);
            num7.setOnClickListener(keyOnClickListener);
            num8.setOnClickListener(keyOnClickListener);
            num9.setOnClickListener(keyOnClickListener);
            num0.setOnClickListener(keyOnClickListener);
            numPeriod.setOnClickListener(keyOnClickListener);
            numDel.setOnClickListener(keyOnClickListener);
            numAdd.setOnClickListener(addOnClickListener);

        /*
        Request focus for the price input field such that focus is on that field when
        the dialog opens
        */
            priceEditText.requestFocus();
        /*
        Hide the appearance of any keyboard when the user presses on the price input field
        so the user only uses the provided in app customised keypad
         */

            // Hide default keyboard when focus is on this field
            priceEditText.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
                    imm.toggleSoftInput(0, InputMethodManager.HIDE_NOT_ALWAYS);
                    getWindow().setSoftInputMode(WindowManager
                            .LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
                    Log.e("testonclickclose", "works");
                }
            });

            priceEditText.setOnFocusChangeListener(new View.OnFocusChangeListener() {
                @Override
                public void onFocusChange(View v, boolean hasFocus) {
                    if (hasFocus) {
                        InputMethodManager im = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
                        im.hideSoftInputFromWindow(v.getWindowToken(), 0);
                    }
                }
            });

            priceEditText.setOnTouchListener(new View.OnTouchListener() {
                @Override
                public boolean onTouch(View v, MotionEvent event) {
                    return false;
                }
            });


            dialog.show();

            // Setting the size of the dialog
            Window window = dialog.getWindow();
            window.setLayout(WindowManager.LayoutParams.MATCH_PARENT,
                    WindowManager.LayoutParams.WRAP_CONTENT);
        }
    });

    Button addNextDinerActivity = (Button) findViewById(R.id.item_done_button);
    addNextDinerActivity.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            // Assign the list of items to specified Diner (selected previously or
            // currently adding)
            // Get name of current diner
            String nameOfCurrentDiner = Diner.getCurrentName();

            // Iteration process to find the index of current Diner
            int indexOfCurrentDiner = -1;
            for (Diner list : AddDinerActivity.dinerArray) {
                if (list.getmDinerName().equals(nameOfCurrentDiner)) {
                    // Stores in index in a variable
                    indexOfCurrentDiner = AddDinerActivity.dinerArray.indexOf(list);
                }
            }
            // Instantiate a Diner object to be added later
            ArrayList<Item> array = getItemsArray();
            Diner dinerToAdd = new Diner(nameOfCurrentDiner, getCurrentBill(getItemsArray()), array);
            // Sets a new Diner object to the index position found
            AddDinerActivity.dinerArray.remove(indexOfCurrentDiner);
            AddDinerActivity.dinerArray.add(indexOfCurrentDiner, dinerToAdd);
            // Clears the editItemsArray when leaving activity

            // Brings the user back to Diner list page
            Intent addDiner = new Intent(AddItemsActivity.this, AddDinerActivity.class);
            startActivity(addDiner);
        }
    });
// Method to calculate the current individual's bill
public double getCurrentBill(ArrayList<Item> list) {
    double currentBill = 0;
    for (Item item : list) {
        currentBill += item.getmItemPrice();
    }
    return currentBill;
}

// Method to get current item array
public ArrayList<Item> getItemsArray() {
    return itemsArray;
}
}
  

My Diner类定义如下,其中包含一个名为mDinerItemsList的ArrayList对象

public class Diner {

public static String currentName;

// To store the currentName
private String mDinerName;

// To store individual's total bill
private double mDinerBill;

// To store the individual's list of items (its description and price)
private ArrayList<Item> mDinerItemsList = new ArrayList<>();

// Class constructor
public Diner(String mDinerName, double mDinerBill, ArrayList<Item> DinerItemsList) {
    this.mDinerName = mDinerName;
    this.mDinerBill = mDinerBill;
    mDinerItemsList = DinerItemsList;
}

// Class constructor with Name ONLY
public Diner(String mDinerName) {
    this.mDinerName = mDinerName;
}

// Class constructor with Bill ONLY
public Diner(double mDinerBill) {
    this.mDinerBill = mDinerBill;
}

// Class constructor with ItemsList ONLY
public Diner(ArrayList<Item> mDinerItemsList) {
    this.mDinerItemsList = mDinerItemsList;
}

// Method to set the current name to identify current diner
public static void setCurrentName(String name) {
    currentName = name;
}

// Method to return the current name to identify current diner
public static String getCurrentName() {
    return currentName;
}

// Method to return Diner's Name
public String getmDinerName() {
    return mDinerName;
}

// Method to return Diner's bill
public double getmDinerBill() {
    return mDinerBill;
}

public void setmDinerName(String mDinerName) {
    this.mDinerName = mDinerName;
}

// Method to put an item (description and price) into Diner's list of items
public void putmDinerItem(ArrayList<Item> array) {
    mDinerItemsList = array;
}

// Method to return Diner's list of items in the form of ArrayList
public ArrayList<Item> getmDinerItemsList() {
    return mDinerItemsList;
}
}

按下活动中的按钮,包含descEditText和priceEditText字符串的单个对象将添加到itemsArray中。然后在我实例化新的Diner对象期间将此数组传递给mDinerItemsList。这些发生在AddItemsActivity结束之前。通过调试过程,我发现第二次调用AddItemsActivity时,itemsArray.clear()以某种方式擦除我之前实例化的Diner对象的mDinerItemsList。每次调用活动时都会发生这种情况。因此,我无法在mDinerItemsList中为我想要创建的每个Diner对象存储任何ArrayLists。我哪里做错了??我一直在试图解决这个问题几个小时!请帮忙!!!

3 个答案:

答案 0 :(得分:1)

在你的Diner构造函数中尝试这个:

list = new ArrayList<>(passedList);

这样您就不会将Diner对象中的变量设置为其他类中的静态引用。相反,您只是在Diner对象中创建一个新列表,并将其填充为静态列表的内容。

答案 1 :(得分:1)

function EligibleAbout(state = { selections: [] } , action = {}){
  switch (action.type){
    case ADD_SELECT:
      return {
        ...state,
        selections: [].concat(state.selections, action.data),
      }
    case REMOVE_SELECT:
      return {
        ...state,
        selections: state.selections.filter((selection, index) => (index !== action.data)),
      }
    case SAVE_SELECT_OPTION:
      return {
        ...state,
        selections: state.selections.map((selection) => selection.id === action.data.id ? action.data : selection)
      }
    default:
      return state
  }
}

答案 2 :(得分:1)

问题是你只是在你的列表周围传递而不是创建它的副本。所以实际上只有一个List对象,但有很多变量指向该列表。

例如:在您的Diner构造函数中,您只需将mDinerItemsList分配给已传递的DinerItemsList。

// Class constructor
public Diner(String mDinerName, double mDinerBill, ArrayList<Item> DinerItemsList) {
    this.mDinerName = mDinerName;
    this.mDinerBill = mDinerBill;
    mDinerItemsList = DinerItemsList;
}

所以当你这样做时

ArrayList<Item> array = getItemsArray();
Diner dinerToAdd = new Diner(nameOfCurrentDiner, getCurrentBill(getItemsArray()), array);

您只是传递getItemArray()返回Diner的静态List,新的Diner Object将指向完全相同的List。

要解决该问题,您可以使用ArrayList Copy Constructor,它将创建一个浅拷贝(一个单独的List指向与原始List相同的对象):

mDinerItemsList = new ArrayList<>(DinerItemsList);

编辑:澄清一些非常简单的示例代码:

List<String> list1 = new ArrayList<String>();
List<String> list2 = list1;

在上面的示例中,您将只有1个List,但有2个变量指向它。调用list2.clear();还将清除list1(因为这两个变量只指向1个List)。你的代码做同样的事情。它只是传递一个Object引用,但不会创建一个新的。