当成员方法访问时,为什么对我的自定义对象的引用变为null?

时间:2017-04-23 23:41:04

标签: java android

我正在使用Android Studio中的纯Java(无NDK)编写的应用程序。该应用程序几天前开始崩溃并告诉我,我正在尝试在空对象引用上调用抽象类方法。但是,输出控制台引用的对象引用只被修改一次(当它们第一次被实例化时)。

我有一个名为RecipeEditor的自定义类,其中包含其他两个自定义类的私有成员对象数组:IngredientSelectorGraphBar。当我实例化RecipeEditor时,它会逐个实例化IngredientSelector个对象和GraphBar个对象。

RecipeEditorIngredientSelector都包含方法updateValues()。实例化IngredientSelector对象时,会传递对其所属的RecipeEditor对象的引用。此外,当IngredientSelector对象在其自身内部调用updateValues()时,它会更新一些变量,然后调用先前传递给它的updateValues()对象的RecipeEditor函数。

这是事情变得棘手的问题:updateValues()对象中的RecipeEditor函数在尝试调用GraphBar类中包含的setBarValue()方法时会崩溃应用程序。更糟糕的是,调试器表示IngredientSelector对象数组和GraphBar对象数组都为空。为了使事情变得更奇怪,曾经包含在数组中的对象仍然存在于内存中。我知道这一点,因为对象仍在屏幕上运行。

RecipeEditor上课:

package darnell.coldpresstycoon;

import android.support.v4.content.ContextCompat;
import android.view.View;
import android.widget.TextView;
import darnell.coldpresstycoon.Dialogs.*;

import java.util.ArrayList;
import java.util.Locale;

/**
 * Created by Darnell on 4/8/2017.
 */

public class RecipeEditor {
    private View layout;

    private Recipe recipe;

    private TextView ouncesRemaining;
    private int ouncesRemainingValue = 16;

    private IngredientSelector[] ingredientSelectors = new IngredientSelector[3];

    private GraphBar[] graphBars = new GraphBar[4];

    public RecipeEditor(View layout, ArrayList<Ingredient> ingredients, Recipe recipe) {
        this.layout = layout;

        this.recipe = recipe;

        ouncesRemaining = (TextView) layout.findViewById(R.id.ouncesRemaining);

        ingredientSelectors[0] = new IngredientSelector(
                layout.findViewById(R.id.ingredientSelector1),
                this,
                recipe,
                0);

        ingredientSelectors[1] = new IngredientSelector(
                layout.findViewById(R.id.ingredientSelector2),
                this,
                recipe,
                1);

        ingredientSelectors[2] = new IngredientSelector(
                layout.findViewById(R.id.ingredientSelector3),
                this,
                recipe,
                2);

        graphBars[0] = new GraphBar(layout.findViewById(R.id.sweetness),
                "SWEETNESS",
                recipe);

        graphBars[1] = new GraphBar(layout.findViewById(R.id.sourness),
                "SOURNESS",
                recipe);

        graphBars[2] = new GraphBar(layout.findViewById(R.id.flavor),
                "FLAVOR",
                recipe);

        graphBars[3] = new GraphBar(layout.findViewById(R.id.novelty),
                "NOVELTY",
                recipe);

        updateValues();
    }

    //Getters
    public int getOuncesRemainingValue() {
        return ouncesRemainingValue;
    }

    public void updateValues() {

        //Calculate ounces remaining
        ouncesRemainingValue = 16-recipe.getQuantitySum();

        //Set ounces remaing string
        ouncesRemaining.setText(String.format(Locale.US, "%d", ouncesRemainingValue));

        //Adjust color of ouncesRemaing TextView to reflect value
        if(ouncesRemainingValue == 0)
            ouncesRemaining.setTextColor(ContextCompat.getColor(layout.getContext(),
                    R.color.colorTextBright));
        else
            ouncesRemaining.setTextColor(ContextCompat.getColor(layout.getContext(),
                    R.color.colorTextLight));

        //Update sweetness
        graphBars[0].setBarValue(0.3f);

    }
}

IngredientSelector updateValues()方法:

public void updateValues(int quantityValue) {
    quantity.setText(String.format(Locale.US,
            "%d ounce%s",
            quantityValue,
            quantityValue == 1 ? "" : "s"));

    totalCost.setText(String.format(Locale.US,
            "$%3.2f",
            quantityValue*ingredient.getPricePerOunce()));

    recipe.setQuantityValue(index, quantityValue);
    recipeEditor.updateValues();
}

GraphBar setBarValue()方法:

public void setBarValue(float value) {
    //final TableRow.LayoutParams params = new TableRow.LayoutParams(0, TableRow.LayoutParams.MATCH_PARENT, );
    TableRow.LayoutParams params = new TableRow.LayoutParams(0,
            TableRow.LayoutParams.MATCH_PARENT,
            value);

    //params = (TableRow.LayoutParams) filled.getLayoutParams();
    //params.weight = value;
    filled.setLayoutParams(params);

    //empty.setLayoutParams(new TableRow.LayoutParams(0,
            //TableRow.LayoutParams.MATCH_PARENT,
            //1.0f-value));
}

堆栈追踪:

Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'void darnell.coldpresstycoon.GraphBar.setBarValue(float)' on a null object reference
at darnell.coldpresstycoon.RecipeEditor.updateValues(RecipeEditor.java:93)
at darnell.coldpresstycoon.IngredientSelector.updateValues(IngredientSelector.java:92)
at darnell.coldpresstycoon.IngredientSelector.<init>(IngredientSelector.java:60)
at darnell.coldpresstycoon.RecipeEditor.<init>(RecipeEditor.java:35)
at darnell.coldpresstycoon.Dialogs.RecipeDialog.<init>(RecipeDialog.java:40)
at darnell.coldpresstycoon.MainActivity.onCreate(MainActivity.java:96)

我是Stack Overflow的新成员,所以如果我的问题格式错误或过于冗长,我会道歉。

1 个答案:

答案 0 :(得分:2)

查看stacktrace中的调用堆栈:

at darnell.coldpresstycoon.RecipeEditor.updateValues(RecipeEditor.java:93)
at darnell.coldpresstycoon.IngredientSelector.updateValues(IngredientSelector.java:92)
at darnell.coldpresstycoon.IngredientSelector.<init>(IngredientSelector.java:60)
at darnell.coldpresstycoon.RecipeEditor.<init>(RecipeEditor.java:35)

RecipeEditor构造函数调用IngredientSelector构造函数,该构造函数调用IngredientSelector.updateValues(),在构造{{1}之前调用RecipeEditor.updateValue()完成了。

阵列尚未初始化。

重新思考你的逻辑。