0

When app is on portrait, everything is fine, but when I use landscape (I create 2 vision of the app, but only portrait works), the app suddenly closes and shows that java.lang.NullPointerException: findViewById(R.id.roll_button) must not be null or Unable to start activity ComponentInfo{MainActivity}: java.lang.NullPointerException.

I added some solutions from internet including adding android:configchanges or android:scrrenOrientation="portrait", it didnot help.

The code is show below:

MainActivity:

class MainActivity : AppCompatActivity() {
        lateinit var diceImage: ImageView
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val rollButton: Button = findViewById(R.id.roll_button)!!
        rollButton.setOnClickListener {
            rollDice()
        }
        diceImage = findViewById(R.id.dice_image)
    }

    private fun rollDice() {
        val randomInt = Random().nextInt(6) + 1
        val drawableResource = when (randomInt) {
            1 -> R.drawable.dice_1
            2 -> R.drawable.dice_2
            3 -> R.drawable.dice_3
            4 -> R.drawable.dice_4
            5 -> R.drawable.dice_5
            else -> R.drawable.dice_6
        }
        diceImage.setImageResource(drawableResource)
    }
}

Code below is activity_main.xml: (Most would be fine below)

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:configChanges="orientation|screenSize"
    tools:context=".MainActivity"
    >

    <ImageView
        android:id="@+id/dice_image"
        android:layout_width="123dp"
        android:layout_height="96dp"
        android:layout_marginStart="144dp"
        android:layout_marginTop="112dp"
        android:configChanges="orientation|screenSize"
        android:src="@drawable/empty_dice"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        android:contentDescription="TODO" />

    <Button
        android:id="@+id/roll_button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="6dp"
        android:text="@string/roll"
        android:configChanges="orientation|screenSize"
        app:layout_constraintBottom_toTopOf="@+id/textView2"
        app:layout_constraintStart_toEndOf="@+id/textView2"/>
</android.support.constraint.ConstraintLayout> 
Mark Rotteveel
  • 100,966
  • 191
  • 140
  • 197

3 Answers3

0

Please Add your LogCat Error and LandscapeMode layout details.

I have suggestion for you use below solution.

Use View Binding Or Data Binding avoid to findViewById() more easy to use in development.

Just Follow Some Step

  1. add below line in build.gradle app

    android {
    
        buildFeatures {
            viewBinding true
    
        }
    }
    

2.Use this keyword tools:viewBindingIgnore="true" in parent Layout. Like this.

<LinearLayout
      
 tools:viewBindingIgnore="true" >
 
</LinearLayout>
  1. Your onCreate() of activity be like this.

    private lateinit var binding: ResultProfileBinding
    
    override fun onCreate(savedInstanceState: Bundle?) {
         super.onCreate(savedInstanceState)
         binding = ResultProfileBinding.inflate(layoutInflater)
         val view = binding.root
         setContentView(view)
    }
    
  2. Now you can access all id easily.

    binding.name.text = viewModel.name
    binding.button.setOnClickListener { viewModel.userClicked() } 
    

For more details visit https://developer.android.com/topic/libraries/view-binding

For DataBinding Visit https://developer.android.com/topic/libraries/data-binding

Umesh Yadav
  • 1,042
  • 9
  • 17
0

never ever use !!(not null assertion opeartor)..No good production app usage it..the problem is that the id is not found in file activity_main.are you using 2 different XML files, one for landscape and one for portrait. if yes, just check if the configuration in which u get crash has that id, otherwise, there is no reason for crash..data binding and view binding is a good way to avoid null pouiter exception

Rishabh Ritweek
  • 550
  • 3
  • 10
0

One of the tags of the question is Kotlin, so here's a simple example demonstrating savedInstanceState(). It's a very simple slot machine 'game' that preserves the state of the fruit images and the score.

MainActivity.kt

// I've missed out the imports, just for the sake of brievity

class MainActivity : AppCompatActivity() {
    private lateinit var binding: ActivityMainBinding
    private lateinit var images: IntArray

    private val spinButton by lazy {binding.spinButton}
    private val scoreText by lazy {binding.scoreTextView}
    private val imageViews by lazy {
        listOf<ImageView>(binding.imageView1, binding.imageView2, binding.imageView3)
    }
    private var score = 10

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        val view = binding.root
        setContentView(view)
        images = savedInstanceState?.getIntArray(IMAGES)
            ?: intArrayOf( R.drawable.cherries, R.drawable.cherries, R.drawable.cherries)
        score = savedInstanceState?.getInt(SCORE)
            ?: 10
        drawFruit()
        spinButton.setOnClickListener { drawslotMachine() }
    }
    
// when the screen is rotated (I think onDestroy is called) the app saves images and score in a  
// key value pair, IMAGES and SCORE being the keys     
    override fun onSaveInstanceState(outState: Bundle) {
        super.onSaveInstanceState(outState)
        outState.putIntArray(IMAGES, images)
        outState.putInt(SCORE, score)
    }
    
    private fun drawslotMachine() {
        score += 10
        setRandomImages()
        drawFruit()
    }

    private fun drawFruit() {
        for (i in 0..(imageViews.size - 1)) {
            imageViews[i].setImageResource(images[i])
        }
        scoreText.text = score.toString()
    }

    private fun setRandomImages() {
        images = intArrayOf(randomImage(), randomImage(), randomImage())
    }

    private fun randomImage(): Int{
        val r = Random.nextInt(15)
        return when(r){
            in 0..4 -> R.drawable.apple
            in 5..8 -> R.drawable.green_apple
            9 -> R.drawable.cherries
            in 10..12 -> R.drawable.mushroom
            in 13..14 -> R.drawable.orange
            else -> R.drawable.mushroom
        }
    }
}

This is the Constants.kt file, which contains the keys for saveInstanceState with some dummy values ("Int Array" & "Score"). It's in the same directory as MainActivity.kt


package com.example.gambling

const val IMAGES = "Int Array"
const val SCORE = "Score"

A mistake I made was blithely accepting Android Studios code completion and using:

override fun onSaveInstanceState(outState: Bundle, outPersistentState: PersistableBundle)

instead of just:

onSaveInstanceState(outState: Bundle)

This is also an answer to this question which goes into some of the potential pitfalls Also a Massive Credit to Joed Goh, this answer is based on this work

Lozminda
  • 45
  • 8
  • Just to say that Joed Goh's youtube channel I've found really good for entry level Android developers, (specifically me). I'm not affiliated with him in any way other than being an appreciant. – Lozminda Jan 17 '23 at 19:46