'Custom View Crashing Upon Inflation
My custom views are causing an app crash when they're inflated within their parent fragment.
I have a hunch that some update to either Kotlin or JDK may have contained a breaking change because these very same layouts used to work and inflate just fine.
What am I missing with rendering my custom views correctly?
Note I am using Kotlin synthetics.
Some things i've tried:
- Using findViewById instead of Kotlin synthetics
- Adding an attrs file (albeit the declare-styleable has no children since I don't use any custom attributes for this custom view)
- Commenting out usage of
rightArrowandleftArrowelements (this resolves the issue, but then my other custom views in the package throw the same inflation error)
The Error
The most base cause of the error taken from the full stacktrace below is:
Attempt to invoke interface method 'java.lang.Object java.util.Map.get(java.lang.Object)' on a null object reference at com.nu.rms.inspections.ui.widget.GarmentIssuePickerDialog._$_findCachedViewById(GarmentIssuePickerDialog.kt)
Full stack trace:
Caused by: android.view.InflateException: Binary XML file line #291: Binary XML file line #291: Error inflating class com.nu.rms.inspections.ui.widget.GarmentIssuePickerDialog
Caused by: android.view.InflateException: Binary XML file line #291: Error inflating class com.nu.rms.inspections.ui.widget.GarmentIssuePickerDialog
Caused by: java.lang.reflect.InvocationTargetException
at java.lang.reflect.Constructor.newInstance0(Native Method)
at java.lang.reflect.Constructor.newInstance(Constructor.java:430)
at android.view.LayoutInflater.createView(LayoutInflater.java:645)
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:787)
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:727)
at android.view.LayoutInflater.rInflate(LayoutInflater.java:858)
at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:821)
at android.view.LayoutInflater.inflate(LayoutInflater.java:518)
at android.view.LayoutInflater.inflate(LayoutInflater.java:426)
at com.nu.rms.inspections.ui.fragment.ContentFragment.onCreateView(ContentFragment.kt:98)
at androidx.fragment.app.Fragment.performCreateView(Fragment.java:2699)
at androidx.fragment.app.FragmentStateManager.createView(FragmentStateManager.java:320)
at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1199)
at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1368)
at androidx.fragment.app.FragmentManager.moveFragmentToExpectedState(FragmentManager.java:1446)
at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1509)
at androidx.fragment.app.BackStackRecord.executeOps(BackStackRecord.java:447)
at androidx.fragment.app.FragmentManager.executeOps(FragmentManager.java:2181)
at androidx.fragment.app.FragmentManager.executeOpsTogether(FragmentManager.java:2004)
at androidx.fragment.app.FragmentManager.removeRedundantOperationsAndExecute(FragmentManager.java:1959)
at androidx.fragment.app.FragmentManager.execPendingActions(FragmentManager.java:1861)
at androidx.fragment.app.FragmentManager.dispatchStateChange(FragmentManager.java:2641)
at androidx.fragment.app.FragmentManager.dispatchActivityCreated(FragmentManager.java:2589)
at androidx.fragment.app.FragmentController.dispatchActivityCreated(FragmentController.java:247)
at androidx.fragment.app.FragmentActivity.onStart(FragmentActivity.java:541)
at androidx.appcompat.app.AppCompatActivity.onStart(AppCompatActivity.java:210)
at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1248)
at android.app.Activity.performStart(Activity.java:6696)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2628)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2726)
at android.app.ActivityThread.-wrap12(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1477)
at android.os.Handler.dispatchMessage(Handler.java:102)
2022-05-04 12:53:31.557 4222-4222/com.nu.rms.inspections E/AndroidRuntime: at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6119)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)
Caused by: java.lang.NullPointerException: Attempt to invoke interface method 'java.lang.Object java.util.Map.get(java.lang.Object)' on a null object reference
at com.nu.rms.inspections.ui.widget.GarmentIssuePickerDialog._$_findCachedViewById(GarmentIssuePickerDialog.kt)
at com.nu.rms.inspections.ui.widget.GarmentIssuePickerDialog.<init>(GarmentIssuePickerDialog.kt:50)
at com.nu.rms.inspections.ui.widget.GarmentIssuePickerDialog.<init>(GarmentIssuePickerDialog.kt:25)
at com.nu.rms.inspections.ui.widget.GarmentIssuePickerDialog.<init>(GarmentIssuePickerDialog.kt)
... 38 more
The Custom View Class File
package com.nu.rms.inspections.ui.widget
import android.animation.ObjectAnimator
import android.animation.PropertyValuesHolder
import android.content.Context
import android.graphics.Typeface
import android.text.Spannable
import android.text.SpannableStringBuilder
import android.text.TextPaint
import android.text.style.MetricAffectingSpan
import android.util.AttributeSet
import android.view.LayoutInflater
import android.widget.FrameLayout
import androidx.core.content.res.ResourcesCompat
import com.nu.rms.data.models.GarmentIssueAreas
import com.nu.rms.data.models.InspectionLocation
import com.nu.rms.data.models.Issue
import com.nu.rms.inspections.R
import com.urbn.nu.sharedcore.ext.animateShow
import com.urbn.nu.sharedcore.ext.crossFadeTo
import com.urbn.nu.sharedcore.ext.setActive
import com.urbn.nu.sharedcore.ext.show
import kotlinx.android.synthetic.main.view_issue_picker_dialog.view.*
class GarmentIssuePickerDialog @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : FrameLayout(context, attrs, defStyleAttr) {
private lateinit var issue: Issue
private var garmentIssueArea: GarmentIssueAreas? = null
private var step: Steps = Steps.SELECT_ISSUE_AREA_BUTTON
private lateinit var listener: GarmentIssuePickerInterface
private var rightArrowEnlargeAnimator: ObjectAnimator
private var leftArrowEnlargeAnimator: ObjectAnimator
private var outsideIssueAreaDataChanged: Boolean = false
private var insideIssueAreaDataChanged: Boolean = false
interface GarmentIssuePickerInterface {
fun setupGarmentIssuePickerFragments(
numPages: Int,
issue: Issue,
issueArea: GarmentIssueAreas
)
}
init {
LayoutInflater.from(context).inflate(R.layout.view_issue_picker_dialog, this)
rightArrowEnlargeAnimator = ObjectAnimator.ofPropertyValuesHolder(
rightArrow, //<-------ERROR HAPPENS ON THIS LINE
PropertyValuesHolder.ofFloat("scaleX", 1.3f),
PropertyValuesHolder.ofFloat("scaleY", 1.3f)
)
leftArrowEnlargeAnimator = ObjectAnimator.ofPropertyValuesHolder(
leftArrow,
PropertyValuesHolder.ofFloat("scaleX", 1.3f),
PropertyValuesHolder.ofFloat("scaleY", 1.3f)
)
rightArrowEnlargeAnimator.duration =
resources.getInteger(R.integer.view_pager_dot_animation_duration).toLong()
leftArrowEnlargeAnimator.duration =
resources.getInteger(R.integer.view_pager_dot_animation_duration).toLong()
}
fun setListener(listener: GarmentIssuePickerInterface) {
this.listener = listener
}
...
tintedOverlay.setOnClickListener {
hideDialog()
}
closeButton.setOnClickListener {
hideDialog()
}
modal.setOnClickListener { }
rightArrow.setOnClickListener {
if (issueAreasViewPager.currentItem != 1) {
issueAreasViewPager.currentItem = 1
}
}
leftArrow.setOnClickListener {
if (issueAreasViewPager.currentItem != 0) {
issueAreasViewPager.currentItem = 0
}
}
}
}
The Custom View XML
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
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:id="@+id/tintedOverlay"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/black_80">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/modal"
android:layout_width="1760dp"
android:layout_height="920dp"
android:layout_gravity="center"
android:background="@color/white">
<TextView
android:id="@+id/issueName"
style="@style/alert_header"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:gravity="center"
android:maxLines="1"
android:textSize="48sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="@string/issue_missing_damaged_embellishment" />
<TextView
android:id="@+id/issueDescription"
style="@style/issue_description"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/exo2_medium"
android:textColor="@color/gray_subtext"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/issueName"
tools:text="Spotting" />
<ImageView
android:id="@+id/closeButton"
android:layout_width="64dp"
android:layout_height="64dp"
android:layout_margin="24dp"
android:src="@drawable/ic_close_light"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/continueButton"
style="@style/alert_error_button_action"
android:layout_width="417dp"
android:layout_height="96dp"
android:layout_marginBottom="40dp"
android:background="@drawable/action_button_pass_bg"
android:foreground="@drawable/ripple_press_dark"
android:gravity="center"
android:text="@string/action_continue"
android:textAllCaps="true"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/step1"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:layout_editor_absoluteX="0dp"
tools:layout_editor_absoluteY="0dp">
<TextView
android:id="@+id/locationPrompt"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="128dp"
android:fontFamily="@font/exo2_regular"
android:text="@string/where_is_the_issue_located"
android:textAlignment="center"
android:textColor="@color/black"
android:textSize="40sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/outsideButton"
style="@style/alert_error_button_action"
android:layout_width="417dp"
android:layout_height="96dp"
android:layout_marginTop="40dp"
android:background="@drawable/action_button_neutral_bg"
android:foreground="@drawable/ripple_press_dark"
android:gravity="center"
android:text="@string/outside"
android:textAllCaps="true"
android:textColor="@color/black"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/locationPrompt" />
<TextView
android:id="@+id/insideButton"
style="@style/alert_error_button_action"
android:layout_width="417dp"
android:layout_height="96dp"
android:layout_marginTop="32dp"
android:background="@drawable/action_button_neutral_bg"
android:foreground="@drawable/ripple_press_dark"
android:gravity="center"
android:text="@string/inside"
android:textAllCaps="true"
android:textColor="@color/black"
app:layout_constraintEnd_toEndOf="@id/outsideButton"
app:layout_constraintStart_toStartOf="@id/outsideButton"
app:layout_constraintTop_toBottomOf="@id/outsideButton" />
<TextView
android:id="@+id/outsideAndInsideButton"
style="@style/alert_error_button_action"
android:layout_width="417dp"
android:layout_height="96dp"
android:layout_marginTop="40dp"
android:background="@drawable/action_button_neutral_bg"
android:foreground="@drawable/ripple_press_dark"
android:gravity="center"
android:text="@string/outside_inside"
android:textAllCaps="true"
android:textColor="@color/black"
app:layout_constraintEnd_toEndOf="@id/insideButton"
app:layout_constraintStart_toStartOf="@id/insideButton"
app:layout_constraintTop_toBottomOf="@id/insideButton" />
<TextView
android:id="@+id/entireGarmentButton"
style="@style/alert_error_button_action"
android:layout_width="417dp"
android:layout_height="96dp"
android:layout_marginTop="40dp"
android:background="@drawable/action_button_neutral_bg"
android:foreground="@drawable/ripple_press_dark"
android:gravity="center"
android:text="@string/entire_garment"
android:textAllCaps="true"
android:textColor="@color/black"
app:layout_constraintEnd_toEndOf="@id/outsideAndInsideButton"
app:layout_constraintStart_toStartOf="@id/outsideAndInsideButton"
app:layout_constraintTop_toBottomOf="@id/outsideAndInsideButton" />
</androidx.constraintlayout.widget.ConstraintLayout>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/step2"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone">
<TextView
android:id="@+id/selectAreasPrompt"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="128dp"
android:fontFamily="@font/exo2_regular"
android:text="@string/select_areas_on_the_garment"
android:textColor="@color/black"
android:textSize="40sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<!--TODO: comment these, must remove selectableItemBackgroundBorderless for unit tests-->
<!-- <ImageView
android:id="@+id/leftArrow"
android:layout_width="60dp"
android:layout_height="60dp"
android:src="@drawable/ic_left_arrow"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="@id/issueAreasViewPager"
app:layout_constraintEnd_toStartOf="@id/issueAreasViewPager"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@id/issueAreasViewPager" />
<ImageView
android:id="@+id/rightArrow"
android:layout_width="60dp"
android:layout_height="60dp"
android:src="@drawable/ic_right_arrow"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="@id/issueAreasViewPager"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/issueAreasViewPager"
app:layout_constraintTop_toTopOf="@id/issueAreasViewPager" />-->
<!--TODO: uncomment these, the alternative is only used for unit testing-->
<ImageView
android:id="@+id/leftArrow"
android:layout_width="60dp"
android:layout_height="60dp"
android:background="?selectableItemBackgroundBorderless"
android:src="@drawable/ic_left_arrow"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="@id/issueAreasViewPager"
app:layout_constraintEnd_toStartOf="@id/issueAreasViewPager"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@id/issueAreasViewPager" />
<ImageView
android:id="@+id/rightArrow"
android:layout_width="60dp"
android:layout_height="60dp"
android:background="?selectableItemBackgroundBorderless"
android:src="@drawable/ic_right_arrow"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="@id/issueAreasViewPager"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/issueAreasViewPager"
app:layout_constraintTop_toTopOf="@id/issueAreasViewPager" />
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/issueAreasViewPager"
android:layout_width="1061dp"
android:layout_height="585dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/selectAreasPrompt" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
</FrameLayout>
The Custom View being Referenced in Parent Fragment Layout
<com.nu.rms.inspections.ui.widget.GarmentIssuePickerDialog
android:id="@+id/garmentIssuePickerDialog"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone" />
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|
