I am working on an app, written purely in Java (no NDK), in Android Studio. The app began crashing a few days ago and telling me that I was trying to invoke an abstract class method on a null object reference. The object references the output console was referring to, however, are only modified once (when they are instantiated for the first time).
我正在开发一个在Android Studio中纯粹用Java(无NDK)编写的应用程序。该应用程序几天前开始崩溃并告诉我,我正在尝试在空对象引用上调用抽象类方法。但是,输出控制台引用的对象引用仅被修改一次(当它们第一次被实例化时)。
I have a custom class named RecipeEditor
that contains private member object arrays of two other custom classes: IngredientSelector
and GraphBar
. When I instantiate RecipeEditor
, it instantiates both the array of IngredientSelector
objects and GraphBar
objects one by one.
我有一个名为RecipeEditor的自定义类,它包含两个其他自定义类的私有成员对象数组:IngredientSelector和GraphBar。当我实例化RecipeEditor时,它逐个实例化IngredientSelector对象和GraphBar对象的数组。
Both RecipeEditor
and IngredientSelector
contain a method, updateValues()
. When an IngredientSelector
object is instantiated, it is passed a reference to the RecipeEditor
object it belongs to. Furthermore, when the IngredientSelector
object calls updateValues()
within itself, it updates a few variables and then calls the updateValues()
function of the RecipeEditor
object passed to it earlier.
RecipeEditor和IngredientSelector都包含一个方法updateValues()。当实例化一个IngredientSelector对象时,它会传递一个对它所属的RecipeEditor对象的引用。此外,当IngredientSelector对象在其自身内部调用updateValues()时,它会更新一些变量,然后调用之前传递给它的RecipeEditor对象的updateValues()函数。
This is where things get screwy: the updateValues()
function in the RecipeEditor
object crashes the app when it tries to call the setBarValue()
method contained within the GraphBar class. Even worse, the debugger says that both the array of IngredientSelector
objects and the array of GraphBar
objects are null. To make things even more bizarre, the objects that were once contained in the arrays still exist in memory. I know this because the objects still function onscreen.
事情变得棘手:RecipeEditor对象中的updateValues()函数在尝试调用GraphBar类中包含的setBarValue()方法时会崩溃应用程序。更糟糕的是,调试器说,IngredientSelector对象数组和GraphBar对象数组都是null。为了使事情变得更奇怪,曾经包含在数组中的对象仍然存在于内存中。我知道这是因为对象仍在屏幕上运行。
RecipeEditor
class:
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()
method:
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()
method:
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));
}
Stack trace:
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)
I'm new to Stack Overflow as a member, so I apologize if my question is oddly formatted or too verbose.
我是Stack Overflow的新成员,所以如果我的问题格式错误或过于冗长,我会道歉。
1 个解决方案
#1
2
Look at the call stack in the stacktrace:
查看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)
The RecipeEditor
constructor calls the IngredientSelector
constructor, which calls IngredientSelector.updateValues()
, which calls RecipeEditor.updateValue()
, before the construction of the RecipeEditor
is done.
RecipeEditor构造函数调用IngredientSelector构造函数,在构造RecipeEditor之前调用IngredientSelector.updateValues()调用RecipeEditor.updateValue()。
The array hasn't been initialized yet.
该阵列尚未初始化。
Re-think your logic.
重新思考你的逻辑。
#1
2
Look at the call stack in the stacktrace:
查看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)
The RecipeEditor
constructor calls the IngredientSelector
constructor, which calls IngredientSelector.updateValues()
, which calls RecipeEditor.updateValue()
, before the construction of the RecipeEditor
is done.
RecipeEditor构造函数调用IngredientSelector构造函数,在构造RecipeEditor之前调用IngredientSelector.updateValues()调用RecipeEditor.updateValue()。
The array hasn't been initialized yet.
该阵列尚未初始化。
Re-think your logic.
重新思考你的逻辑。