0

I've got a TextView and ImageButton objects in my android app, they appear correctly when the app starts (onCreate), but when saveInstanceState() and restoreInstanceState() are called the compiler throws nullPointerException (even though their states are loaded properly) when I try to setText or anything for that matter. I have some other ImageButtons that show correctly both times (on first onCreate, and when restoreInstanceState is called) so it puzzles me even further.

I had tried to create another instance of TextView, setText to it, and then set that TextView as the original, but it doesn't work.

public class MainActivity extends AppCompatActivity {
    private TextView score;
    private TextView labelPoints;
    private ImageButton finQuest;
    private int langFlag = 0;
    private PowerManager.WakeLock wakeLock;
    private int points = 0;
    private ListenerQuestionChooser lqc;
    //saving and loading the instanceState of the buttons bellow works perfectly
    private ImageButton btn1;
    private ImageButton btn2;
    private ImageButton btn3;
    private ImageButton btn4;
    private ImageButton btn5;
    private ImageButton btn6;

    @SuppressLint("InvalidWakeLockTag")
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
        PowerManager powerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);
        wakeLock = powerManager.newWakeLock(PowerManager.FULL_WAKE_LOCK, "My Lock");
        wakeLock.acquire();

        setContentView(R.layout.activity_main);

        labelPoints = findViewById(R.id.total_score);
        finQuest = findViewById(R.id.btn_finanswer);
        score = findViewById(R.id.text_points); 
        btn1 = findViewById(R.id.btn1);
        btn2 = findViewById(R.id.btn2);
        btn3 = findViewById(R.id.btn3);
        btn4 = findViewById(R.id.btn4);
        btn5 = findViewById(R.id.btn5);
        btn6 = findViewById(R.id.btn6);
        lqc = new ListenerQuestionChooser(this, this);

        if (savedInstanceState != null) {
            this.loadSettings(savedInstanceState);
        }

        btn1.setOnClickListener(lqc);
        btn2.setOnClickListener(lqc);
        btn3.setOnClickListener(lqc);
        btn4.setOnClickListener(lqc);
        btn5.setOnClickListener(lqc);
        btn6.setOnClickListener(lqc);

        if (getLangFlag() == 0){
            labelPoints.setVisibility(View.INVISIBLE);
            TextView s = findViewById(R.id.text_points);
            setScore(s);
            score.setVisibility(View.INVISIBLE);
        }else{
            //I have tried to directly set text to the original TextView, it didn't work
            //Then I tried like this, still doesn't work
            TextView s = findViewById(R.id.text_points);
            s.setText(getPoints()); //throws null pointer here
            setScore(s);
        }
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        //there are other things saved here that are not relevant to the question, which save and load perfectly
        if (getFinQuest().getVisibility()==View.VISIBLE) {
            outState.putInt(STATE_FINAL_BUTTON, 1);
        } else{
            outState.putInt(STATE_FINAL_BUTTON, 0);
        }
        if (btn1.getVisibility() == View.INVISIBLE) {
            outState.putInt(STATE_BUTTON_01, 1);
        } else{
            outState.putInt(STATE_BUTTON_01, 0);
        }
        if (btn2.getVisibility() == View.INVISIBLE) {
            outState.putInt(STATE_BUTTON_02, 1);
        } else{
            outState.putInt(STATE_BUTTON_02, 0);
        }
        if (btn3.getVisibility() == View.INVISIBLE) {
            outState.putInt(STATE_BUTTON_03, 1);
        }else{
            outState.putInt(STATE_BUTTON_03, 0);
        }
        if (btn4.getVisibility() == View.INVISIBLE) {
            outState.putInt(STATE_BUTTON_04, 1);
        }else{
            outState.putInt(STATE_BUTTON_04, 0);
        }
        if (btn5.getVisibility() == View.INVISIBLE) {
            outState.putInt(STATE_BUTTON_05, 1);
        }else{
            outState.putInt(STATE_BUTTON_05, 0);
        }
        if (btn6.getVisibility() == View.INVISIBLE) {
            outState.putInt(STATE_BUTTON_06, 1);
        }else{
            outState.putInt(STATE_BUTTON_06, 0);
        }
        outState.putCharSequence(STATE_USERNAME_LANG, String.valueOf(langFlag));
          outState.putInt(STATE_POINTS, getPoints());
   }

   private void loadSettings(Bundle savedInstanceState){
        //I printed logs after each of these lines and the values are loaded perfectly
        CharSequence lFlag = savedInstanceState.getCharSequence(STATE_USERNAME_LANG);
        setLangFlag(Integer.parseInt(lFlag.toString()));
        int butFin = savedInstanceState.getInt(STATE_FINAL_BUTTON);
        if (butFin == 1) {
            finQuest.setVisibility(View.VISIBLE);
        }
        int but01 = savedInstanceState.getInt(STATE_BUTTON_01);
        if (but01 == 1) {
            btn1.setVisibility(View.INVISIBLE);
        }
        int but02 = savedInstanceState.getInt(STATE_BUTTON_02);
        if (but02 == 1) {
            btn2.setVisibility(View.INVISIBLE);
        }
        int but03 = savedInstanceState.getInt(STATE_BUTTON_03);
        if (but03 == 1) {
            btn3.setVisibility(View.INVISIBLE);
        }
        int but04 = savedInstanceState.getInt(STATE_BUTTON_04);
        if (but04 == 1) {
            btn4.setVisibility(View.INVISIBLE);
        }
        int but05 = savedInstanceState.getInt(STATE_BUTTON_05);
        if (but05 == 1) {
            btn5.setVisibility(View.INVISIBLE);
        }
        int but06 = savedInstanceState.getInt(STATE_BUTTON_06);
        if (but06 == 1) {
            btn6.setVisibility(View.INVISIBLE);
        }
        int poeni = savedInstanceState.getInt(STATE_POINTS);
        setPoints(poeni);
   }
    public int getPoints() {
        return points;
    }

    public void setPoints(int points) {
        this.points = points;
    }
    public TextView getScore() {
        return score;
    }

    public void setScore(TextView score) {
        this.score = score;
    }
}

FINAL EDIT: After approximately 16 hours of banging my head against the wall, trying various things (both logical and illogical) and printing logs on every step, I had solved the problem. So here's the solution (I still don't understand why other objects work perfectly without this and these objects require it, but hey, as long as it works I down with it).

if (lqc == null) {
        lqc = new ListenerQuestionChooser(this, this);
    }

    if (savedInstanceState != null) {
        this.loadSettings(savedInstanceState);
    }

    if (finQuest == null) {
        try {
            finQuest = findViewById(R.id.btn_finansfer);
            finQuest.setOnClickListener(lqc);
            if (ListenerQuestionChooser.getCorrectAnswer() > 0) {
                finQuest.setVisibility(View.VISIBLE);
            } else {
                finQuest.setVisibility(View.INVISIBLE);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    if (labelPoints == null) {
        labelPoints = findViewById(R.id.total_score);
        score = findViewById(R.id.text_points);
        try {
            ss = new StringSetter(this);
            if (getLangFlag() == 0) {
                labelPoints.setVisibility(View.INVISIBLE);
                score.setVisibility(View.INVISIBLE);
            } else {
                score.setText(String.valueOf(getPoints()));
                labelPoints.setText(ss.podesiPromenljivu(brPoena, getLanguage()));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
 }

This is the log I get:

09-08 17:55:19.317 8848-8848/? E/AndroidRuntime: FATAL EXCEPTION: main Process: com.example.quizme, PID: 8848 java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.quizme/com.example.quizme.MainActivity}: java.lang.NullPointerException at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2338) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2390) at android.app.ActivityThread.handleRelaunchActivity(ActivityThread.java:3930) at android.app.ActivityThread.access$900(ActivityThread.java:151) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1327) at android.os.Handler.dispatchMessage(Handler.java:110) at android.os.Looper.loop(Looper.java:193) at android.app.ActivityThread.main(ActivityThread.java:5292) at java.lang.reflect.Method.invokeNative(Native Method) at java.lang.reflect.Method.invoke(Method.java:515) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:824) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:640) at dalvik.system.NativeStart.main(Native Method) Caused by: java.lang.NullPointerException at com.example.quizme.MainActivity.onCreate(MainActivity.java:256) at android.app.Activity.performCreate(Activity.java:5264) at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1088) at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2302) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2390)  at android.app.ActivityThread.handleRelaunchActivity(ActivityThread.java:3930)  at android.app.ActivityThread.access$900(ActivityThread.java:151)  at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1327)  at android.os.Handler.dispatchMessage(Handler.java:110)  at android.os.Looper.loop(Looper.java:193)  at android.app.ActivityThread.main(ActivityThread.java:5292)  at java.lang.reflect.Method.invokeNative(Native Method)  at java.lang.reflect.Method.invoke(Method.java:515)  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:824)  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:640)  at dalvik.system.NativeStart.main(Native Method)

Milos
  • 21
  • 6
  • Where is this created ```wakeLock``` ? – JakeB Sep 08 '19 at 16:49
  • @JakeB I did not copy that line into the question because it's of no importance to the problem. It is created above onCreate() method. – Milos Sep 08 '19 at 17:33
  • @GhostCat I don't think you're right. I have several other objects (ImageButtons) that are created and their instanceStates saved and loaded correctly. For example, when I comment out the lines that setText or manipulate in any way these three objects (ImageButton and two TextViews) the app works perfectly. It saves and loads everything else except these three objects. – Milos Sep 08 '19 at 18:57
  • @GhostCat I edited the code above and added the lines with ImageButtons that work perfectly. Everything about them and the one that doesn't work is the same, and still that finQuest button and these two TextView objects throw NPE. I mean, I wouldn't be confused if nothing worked, but this really got me stumped. – Milos Sep 08 '19 at 19:09
  • @GhostCat And what confuses me even more is that it doesn't throw the exception when the onCreate method is called first, just when I try to load instance state. The app starts, works perfectly, and when I lock the phone and unlock it it throws the exception and the app crashes. If I comment out these lines that are related to accessing the objects in question the app loads instance state perfectly and I can continue playing/testing/whatever... – Milos Sep 08 '19 at 19:16
  • @GhostCat Isn't that pointing in some built in class? I don't have that many lines in my Activity, and I don't really know how to see which line is that pointing to or where (it's not clickable). – Milos Sep 08 '19 at 19:38
  • @GhostCat I had solved the problem though I still don't understand why some of the objects load their states perfectly without this and these object require it. If you're interested in solution I've added it to the question above. – Milos Sep 12 '19 at 11:46
  • @GhostCat Ok, didn't know if that is allowed. Also, I figured since I don't understand why the solution works I should just post it like this. But, ok, I'll post an answer. – Milos Sep 12 '19 at 13:12

2 Answers2

1

After approximately 16 hours of banging my head against the wall, trying various things (both logical and illogical) and printing logs on every step, I had solved the problem. So here's the solution (I still don't understand why other objects work perfectly without this and these objects require it, but hey, as long as it works I down with it).

if (lqc == null) {
    lqc = new ListenerQuestionChooser(this, this);
}

if (savedInstanceState != null) {
    this.loadSettings(savedInstanceState);
}

if (finQuest == null) {
    try {
        finQuest = findViewById(R.id.btn_finansfer);
        finQuest.setOnClickListener(lqc);
        if (ListenerQuestionChooser.getCorrectAnswer() > 0) {
            finQuest.setVisibility(View.VISIBLE);
        } else {
            finQuest.setVisibility(View.INVISIBLE);
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
}

if (labelPoints == null) {
    labelPoints = findViewById(R.id.total_score);
    score = findViewById(R.id.text_points);
    try {
        ss = new StringSetter(this);
        if (getLangFlag() == 0) {
            labelPoints.setVisibility(View.INVISIBLE);
            score.setVisibility(View.INVISIBLE);
        } else {
            score.setText(String.valueOf(getPoints()));
            labelPoints.setText(ss.podesiPromenljivu(brPoena, getLanguage()));
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
}
Milos
  • 21
  • 6
0

This is obviously not the complete source so we can only guess. It looks like the first time you create this activity langFlag is set to 0. After you read it from bundle it must be a different value since you get into the else block. We don't know what is the getPoints - it is mentioned only once in place where you get NPE. So, it looks that getPoints is null but we can't tell why from the code you attached.

mlc
  • 415
  • 3
  • 7
  • I didn't post the entire code because the instructions for posting the question said not to do so, also it is very long with lots of stuff not related to the problem. LangFlag is 0 onCreate, then when the language of the app is chosen (the dialog is shown once so it doesn't need to be shown again when the instanceState has been loaded) langFlag is set to 1. I check which value it has since the TextView should only be visible after the language is chosen. getPoints() returns an int that has been saved through saveInstanceState. I printed it after loading and it is not null. – Milos Sep 08 '19 at 18:30
  • You should convert int to String. Try this: s.setText(String.valueOf(getPoints)); When you provide int it is treated as resource id and this is obviously incorrect id. Trying to load resource with incorrect id leads to NPE. – mlc Sep 08 '19 at 18:35
  • I had tried that, also it's getPoints() in my code, don't know why I typed that instead of copying. Anyway I edited the code in the question a bit, added some things that were previously not there (here in question, not in the project code itself). – Milos Sep 08 '19 at 18:38
  • I also tried this s.setText("radnom string here"); it still threw a NPE – Milos Sep 08 '19 at 18:40
  • Tried this too, still no luck, and NPE is still on setText() line - TextView s = getLayoutInflater().inflate(R.layout.activity_main, null).findViewById(R.id.text_points); s.setText("Random String"); – Milos Sep 08 '19 at 18:49