【问题标题】:Attempt to invoke virtual method on a null object reference when taking values from another class从另一个类获取值时尝试在空对象引用上调用虚方法
【发布时间】:2019-01-18 22:04:37
【问题描述】:

我有一个包含两个类的“游戏”,一个负责管理布局和视图,另一个负责执行所需的所有计算。没有走得太远,因为当我单击 TextView 而不是显示值时,应用程序崩溃并提供以下错误:

尝试调用虚方法'void android.widget.TextView.setText(java.lang.CharSequence)' 为空 对象引用

通常,当我单击一个字段时,它应该转到第二个活动中的一个方法,增加一个索引,然后在单击的 TextView 中显示该值。

这是我的主要活动:

public class MainGame extends AppCompatActivity {

ConstraintLayout layout;
ConstraintSet mainLayout = new ConstraintSet();
ConstraintSet optionalLayout = new ConstraintSet();
ConstraintSet armbandLayout = new ConstraintSet();
ConstraintSet armbandOptionalLayout = new ConstraintSet();

private boolean isArmband = false;
private boolean isOptional = false;

TextView player1Name;
TextView fullNameP2;
TextView shortNameP1;
TextView shortNameP2;

TextView gameScoreP1;
TextView gameScoreP2;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main_game);


    initializeLayoutViews();
    initializeLayoutValues();

    final ScoreSetter scoreSetter = new ScoreSetter(this);

    scoreSetter.initIndex();

    //scoreSetter.initAfterGameWon();

    gameScoreP1.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            scoreSetter.clickedByP1();
        }
    });

    }

private void initializeLayoutViews() {

    layout = findViewById(R.id.gameLayout);
    mainLayout.clone(layout);
    optionalLayout.clone(this, R.layout.activity_main_game_optional);
    armbandLayout.clone(this, R.layout.activity_main_armband);
    armbandOptionalLayout.clone(this, R.layout.activity_main_armband_optional);


    player1Name = findViewById(R.id.fullNameP1);
    fullNameP2 = findViewById(R.id.fullNameP2);
    shortNameP1 = findViewById(R.id.shortNameP1);
    shortNameP2 = findViewById(R.id.shortNameP2);
    gameScoreP1 = findViewById(R.id.gameScoreP1);
    gameScoreP2 = findViewById(R.id.gameScoreP2);
}

private void initializeLayoutValues() {
    player1Name.setText("Player 1");
    fullNameP2.setText("Player 2");
    shortNameP1.setText("P1");
    shortNameP2.setText("P2");

    gameScoreP1.setText("0");
    gameScoreP2.setText("0");

}

void writeGameScoreP1(int valP1) {
    Log.i("MainGame_value", String.valueOf(valP1));
    gameScoreP1.setText(String.valueOf(valP1));
}
}

这里奇怪的是日志显示正确的值,它只是没有显示在屏幕上;相反,它会使应用程序崩溃。

这是我的第二节课:

class ScoreSetter {

private int[] GAME_SCORE_VALUES = new int[] {0, 15, 30, 40};

private int indexP1 = 0;
private int indexP2 = 0;

private int gameScoreP1;
private int gameScoreP2;

public String gameValueP1;
private String gameValueP2;

private MainGame mainGame = new MainGame();

ScoreSetter(Context context){
}

public void initIndex() {
    indexP2 = 0;
    indexP1 = 0;
}

public void initAfterGameWon() {
}

public void clickedByP1() {
    ++indexP1;
    mainGame.writeGameScoreP1(indexP1);

}
}

这是日志:

2019-01-18 23:56:22.989 6684-6684/com.andygix.a40love I/MainGame_value: 1 2019-01-18 23:56:22.991 6684-6684/com.andygix.a40love E/AndroidRuntime:致命异常:主要 进程:com.andygix.a40love,PID:6684 java.lang.NullPointerException:尝试调用虚拟方法 'void android.widget.TextView.setText(java.lang.CharSequence)' 空对象引用 在 com.andygix.a40love.MainGame.writeGameScoreP1(MainGame.java:116) 在 com.andygix.a40love.ScoreSetter.clickedByP1(ScoreSetter.java:33) 在 com.andygix.a40love.MainGame$1.onClick(MainGame.java:59) 在 android.view.View.performClick(View.java:6294) 在 android.view.View$PerformClick.run(View.java:24770) 在 android.os.Handler.handleCallback(Handler.java:790) 在 android.os.Handler.dispatchMessage(Handler.java:99) 在 android.os.Looper.loop(Looper.java:164) 在 android.app.ActivityThread.main(ActivityThread.java:6494) 在 java.lang.reflect.Method.invoke(本机方法) 在 com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438) 在 com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807) 2019-01-18 23:56:23.002 1693-1953/system_process W/ActivityManager:
强制整理活动 com.andygix.a40love/.MainGame 2019-01-18 23:56:23.528 1693-1712/system_process W/ActivityManager:活动 ActivityRecord{ea4853d u0 的暂停超时 com.andygix.a40love/.MainGame t48 f} 2019-01-18 23:56:34.370 1693-1712/system_process W/ActivityManager:活动销毁超时 对于 ActivityRecord{ea4853d u0 com.andygix.a40love/.MainGame t48 f}

其中提到问题是由以下方法引起的:

gameScoreP1.setText(String.valueOf(valP1));

mainGame.writeGameScoreP1(indexP1);

scoreSetter.clickedByP1();

我搜索了很多,尝试了很多不同的方法,但似乎没有任何效果。 xml 文件中的所有 id 都是正确的,并经过三重检查。我想再次提一下对我来说似乎很奇怪的事情:事实上,我在应该写入之前记录了值,它是正确的但没有被 TextView 接收。

【问题讨论】:

  • 您不能实例化活动。除非引用 Activity 的类由该 Activity 实例化,并且该 Activity 以某种方式传递给包含的类,否则您不能直接引用 Activity。
  • 我对此很陌生。我不太清楚如何通过活动实例化一个类。
  • 我刚刚发布了一个答案。

标签: android nullpointerexception textview settext charsequence


【解决方案1】:

您不能直接实例化 Activity 或直接引用 Activity 方法,除非您的引用类是由目标 Activity 实例化的。

在你的情况下,你不能这样做:

private MainGame mainGame = new MainGame();

但是,您正在从 MainGame Activity 实例化 ScoreSetter,这意味着您拥有所需的参考。在 ScoreSetter 的构造函数中不要使用Context,而是使用MainGame

private MainGame mainGame; //don't instantiate it here

public ScoreSetter(MainGame mainGame) {
        this.mainGame = mainGame; //do it here instead
}

现在您可以引用 Activity 的实际实例了。

如果您遇到需要更新的 Activity 不包含您的类的情况,您应该查看broadcasts

【讨论】:

  • 不知道他们被称为广播。我会留意他们的。你的方法奏效了。很多事情我应该避免在 cmets 中说。 :)
【解决方案2】:

检查是否为空

if (gameScoreP1 != null) {
    gameScoreP1.setText(String.valueOf(valP1));
} else {
    Logger.d(TAG, "gameScoreP1 is null");
}

【讨论】:

  • 它为null,但值增加。如何解决显示值而不是给出错误?这是我得到的点击:I/MainGame_value: 5 2019-01-19 00:17:01.749 7934-7934/com.andygix.a40love I/MainGame:: gameScoreP1 is null! 2019-01-19 00:17:02.485 7934-7934/com.andygix.a40love I/MainGame_value: 6 2019-01-19 00:17:02.485 7934-7934/com.andygix.a40love I/MainGame:: gameScoreP1 is null!
  • 这是不对的。 OP 误解了活动的工作方式。空检查不会解决任何问题。
猜你喜欢
  • 2023-03-13
  • 1970-01-01
  • 1970-01-01
  • 2021-11-07
  • 1970-01-01
  • 1970-01-01
  • 2019-05-10
  • 2015-06-26
相关资源
最近更新 更多