Neil
Neil

Reputation: 151

Recycler View crashes when navigating up to parent activity

I'm very new to Android, Java, and Kotlin and am trying to port my app over, originally written for iOS in Swift.

The data the app is using is an ArrayList of my Speaker object, coming from a JSON file.

My MainActivity displays a RecyclerView populated by the "brand" parameter of each speaker. The onClick for each row launches BrandMenuActivity with a recyclerView with all the speakers for that brand. The onClick for these then shows a detailView.

Everything works fine when navigating using the "hardware" back button in the emulator, but if I try to implement setDisplayHomeAsUpEnabled in the action bar of the detailView, the app crashes because the intent for BrandMenuActivity is now null.

My AndroidManifest:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.speakerskotlin">

<application
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:roundIcon="@mipmap/ic_launcher_round"
    android:supportsRtl="true"
    android:theme="@style/AppTheme">
    <activity android:name=".SpeakerDetailActivity"
        android:parentActivityName=".BrandMenuActivity">
    </activity>
    <activity android:name=".BrandMenuActivity"
        android:parentActivityName=".MainActivity" >
    </activity>
    <activity android:name=".MainActivity">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
</application>

MainActivity:

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

    setSupportActionBar(findViewById(R.id.speakerToolbar))
    supportActionBar?.title = "Speakers"
    
    val jsonFileString = getJsonDataFromAsset(applicationContext, "SpeakerData.json")

    val gson = Gson()
    val listSpeakerType = object : TypeToken<ArrayList<Speaker>>() {}.type
    val allSpeakers: ArrayList<Speaker> = gson.fromJson(jsonFileString, listSpeakerType)

    brandsRecView.layoutManager = LinearLayoutManager(this)
    brandsRecView.adapter = SpeakerBrandAdapter(allSpeakers){
        val intent = Intent(this, BrandMenuActivity::class.java)
        intent.putExtra("allSpeakers", allSpeakers)
        intent.putExtra("brand", it)
        startActivity(intent)
    }

}

BrandMenuActivity:

    class BrandMenuActivity() : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_brand_menu)

    setSupportActionBar(findViewById(R.id.brandToolbar))
    supportActionBar?.title = intent.getStringExtra("brand")
    supportActionBar?.setDisplayHomeAsUpEnabled(true)

    val brand = intent.getStringExtra("brand")
    val allSpeakers: ArrayList<Speaker> = intent.getParcelableArrayListExtra("allSpeakers")

    brandMenuRecView.layoutManager = LinearLayoutManager(this.applicationContext)
    brandMenuRecView.adapter = BrandMenuAdapter(brand, allSpeakers) {
        val intent = Intent(this, SpeakerDetailActivity::class.java)
        intent.putExtra("speaker", it)
        startActivity(intent)
    }
}

DetailActivity:

    class SpeakerDetailActivity: AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_speaker_detail)

    setSupportActionBar(findViewById(R.id.detailToolbar))
    supportActionBar?.setDisplayHomeAsUpEnabled(true)

    val speaker = intent.getParcelableExtra<Speaker>("speaker")

    val modelImage = findViewById<ImageView>(R.id.imgSpeakerImage)
    val brandText = findViewById<TextView>(R.id.txtBrandName)
    val modelText = findViewById<TextView>(R.id.txtModel)

    brandText.text = speaker.brand
    modelText.text = speaker.model
    val resID = resources.getIdentifier(speaker.imgString, "drawable", packageName)
    modelImage.setImageResource(resID)

    speakerDetailRecView.layoutManager = LinearLayoutManager(this.applicationContext)
    speakerDetailRecView.adapter = SpeakerDetailAdapter(speaker)
}

The Log at the time of crash:

    E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.speakerskotlin, PID: 12099
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.speakerskotlin/com.example.speakerskotlin.BrandMenuActivity}: java.lang.IllegalStateException: intent.getParcelableArrayListExtra("allSpeakers") must not be null
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3270)
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3409)
    at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:83)
    at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
    at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2016)
    at android.os.Handler.dispatchMessage(Handler.java:107)
    at android.os.Looper.loop(Looper.java:214)
    at android.app.ActivityThread.main(ActivityThread.java:7356)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)
 Caused by: java.lang.IllegalStateException: intent.getParcelableArrayListExtra("allSpeakers") must not be null
    at com.example.speakerskotlin.BrandMenuActivity.onCreate(BrandMenuActivity.kt:20)
    at android.app.Activity.performCreate(Activity.java:7802)
    at android.app.Activity.performCreate(Activity.java:7791)
    at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1299)
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3245)
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3409) 
    at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:83) 
    at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135) 
    at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95) 
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2016) 
    at android.os.Handler.dispatchMessage(Handler.java:107) 
    at android.os.Looper.loop(Looper.java:214) 
    at android.app.ActivityThread.main(ActivityThread.java:7356) 
    at java.lang.reflect.Method.invoke(Native Method) 
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492) 
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930) 

Upvotes: 0

Views: 176

Answers (1)

Gunaseelan
Gunaseelan

Reputation: 15515

Two ways to do it.

First one is, you can try calling finish() while tap on android.R.id.home

override fun onOptionsItemSelected(item: MenuItem): Boolean {
    if (item.itemId == android.R.id.home) {
        finish()
        return true
    }
    return super.onOptionsItemSelected(item)
}

this just resume your BrandMenuActivity, so that onCreate will not get called, you can see complete video tutorial here.

Second one is, if you want same intent data while coming from SpeakerDetailActivity simply pass the data between activities like as explained here

Upvotes: 1

Related Questions