williamchart
williamchart copied to clipboard
kotlin.UninitializedPropertyAccessException: lateinit property chartConfiguration has not been initialized
I'm using LineChartView
in a custom view, and using that custom view in an item view of a RecyclerView
. Each rv item has a different number of entries set using show(...)
in onBindViewHolder(...)
as expected. However, when I scroll down, I get the following error and app crashes:
Process: com.myapp.app, PID: 16397
kotlin.UninitializedPropertyAccessException: lateinit property chartConfiguration has not been initialized
at com.db.williamchart.renderer.LineChartRenderer.draw(LineChartRenderer.kt:103)
at com.db.williamchart.view.AxisChartView.onDraw(AxisChartView.kt:118)
at android.view.View.draw(View.java:22350)
at android.view.View.updateDisplayListIfDirty(View.java:21226)
at android.view.View.draw(View.java:22081)
at android.view.ViewGroup.drawChild(ViewGroup.java:4516)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4277)
at androidx.constraintlayout.widget.ConstraintLayout.dispatchDraw(ConstraintLayout.java:1882)
at android.view.View.updateDisplayListIfDirty(View.java:21217)
at android.view.View.draw(View.java:22081)
at android.view.ViewGroup.drawChild(ViewGroup.java:4516)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4277)
at androidx.constraintlayout.widget.ConstraintLayout.dispatchDraw(ConstraintLayout.java:1882)
at android.view.View.draw(View.java:22353)
at android.view.View.updateDisplayListIfDirty(View.java:21226)
at android.view.View.draw(View.java:22081)
at android.view.ViewGroup.drawChild(ViewGroup.java:4516)
at androidx.recyclerview.widget.RecyclerView.drawChild(RecyclerView.java:5030)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4277)
at android.view.View.draw(View.java:22353)
at androidx.recyclerview.widget.RecyclerView.draw(RecyclerView.java:4429)
at android.view.View.updateDisplayListIfDirty(View.java:21226)
at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:4500)
at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:4473)
at android.view.View.updateDisplayListIfDirty(View.java:21186)
at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:4500)
at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:4473)
at android.view.View.updateDisplayListIfDirty(View.java:21186)
at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:4500)
at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:4473)
at android.view.View.updateDisplayListIfDirty(View.java:21186)
at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:4500)
at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:4473)
at android.view.View.updateDisplayListIfDirty(View.java:21186)
at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:4500)
at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:4473)
at android.view.View.updateDisplayListIfDirty(View.java:21186)
at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:4500)
at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:4473)
at android.view.View.updateDisplayListIfDirty(View.java:21186)
at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:4500)
at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:4473)
at android.view.View.updateDisplayListIfDirty(View.java:21186)
at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:4500)
at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:4473)
Running device: Pixel 4 emulator, Android API 30
I've done that as a workaround in my fragment (for DonutChartView). How it works? The chartConfiguration lateinit property of ChartRenderer is initialized in show() and animate() methods of DonutChartView, so you have to invoke one of these methods before View's onDraw(), because chartConfiguration is accessed in onDraw().
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return super.onCreateView(inflater, container, savedInstanceState).also { view ->
view?.findViewById<DonutChartView>(R.id.donutChartView)
?.show(listOf())
}
}
@swistak7171 Unfortunately this solution doesn't work for charts in recyclerview. I'm doing the following as workaround: In my custom rv item view that includes chart as child, I override the following methods:
override fun onAttachedToWindow() {
super.onAttachedToWindow()
binding.chart.show(values)
}
override fun onDetachedFromWindow() {
super.onDetachedFromWindow()
binding.chart.show(listOf())
}
This resolves the issue kotlin.UninitializedPropertyAccessException: lateinit property chartConfiguration has not been initialized
.
@diogobernardino any comment from your side would be great!
I couldn't yet reproduce it. Can someone provide a bit more context (e.g. data, rv adapter, rv view holder)?
I have the same problem as @swistak7171 @ugurcany, but I am using the DonutChartView. I am using the new Compose UI Toolkit (the DonutChartView is wrapped in AndroidView) and the crashes happen in android 10 and 11 in the Android 9 I have no issues.
@diogobernardino,
I hope these details will help you . I'm using the LineChartView
. The App crashes when scrolling in my RecyclerView
inside of a Fragment
.
Java
@NonNull
@Override
public AssetsHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.assets_item,parent,false);
AssetsHolder assetsHolder = new AssetsHolder(itemView);
return assetsHolder;
}
@Override
public void onBindViewHolder(@NonNull final AssetsHolder holder, int position) {
String currentName = OurData.items.get(position);
HashMap<String, List<Pair<String,Float>>> allcharts = OurData.chartMap;
if(allcharts != null){
List<Pair<String,Float>> list = allcharts.get(currentName);
if(list != null) {
holder.lineChartView.show(list);
}
}
}
XML
.
<com.db.williamchart.view.LineChartView
android:id="@+id/chartView"
android:layout_width="92dp"
android:layout_height="58dp"
android:layout_toStartOf="@id/remove"
android:layout_marginEnd="4dp"
android:layout_marginTop="4dp"
android:layout_marginRight="4dp"
android:layout_marginLeft="10dp"
android:layout_toEndOf="@id/name_Frame"
android:layout_marginStart="10dp"
app:chart_lineColor="#FF163A9A"
app:chart_smoothLine="true"
app:chart_axis="none"
app:chart_gridEffect="dotted"
android:background="?attr/colorPrimaryDark"
android:layout_marginBottom="4dp"
android:layout_centerVertical="true"
android:layout_centerHorizontal="true"
/>
Error
kotlin.UninitializedPropertyAccessException: lateinit property innerFrame has not been initialized
at com.db.williamchart.renderer.LineChartRenderer.processTouch(LineChartRenderer.kt:180)
at com.db.williamchart.view.AxisChartView.onTouchEvent(AxisChartView.kt:144)
at android.view.View.dispatchTouchEvent(View.java:12513)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3024)
build.gradle
dependencies {
implementation 'com.diogobernardino:williamchart:3.10.1'
}
Having a second look at the exceptions, my guess is that the init
block of chart views can be executed before a touch event or onDraw
Unfortunately I still couldn't come up with a sample project to reproduce the crash. @AnregendSchoenerelch I tried using your snippets but I think it's not enough to see the crash. Any chance I can have a repository with a sample project where I can reproduce it? Thanks in advance.
Same Issue using DonutChartView with data binding. Only XML code
<com.db.williamchart.view.DonutChartView
android:layout_width="100dp"
android:layout_height="100dp"
app:chart_donutRoundCorners="true"
android:id="@+id/donut_chart"
app:chart_donutThickness="12dp"
app:chart_donutTotal="100"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="parent"
app:layout_constraintTop_toTopOf="parent" />
Data binding:
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
viewDataBinging = DataBindingUtil.inflate(inflater, getLayoutId(), container, false);
rootView = viewDataBinging.getRoot();
return rootView;
}
Same issue. Using chart inside onViewCreated/onResume of the viewPager fragment. Lateinit property innerFrame has not been initialized. The chart is drawn blank despite getting the data populated. Trying to click a blank chart results in a crash. Clearly a library issue not initializing properly. And using lateinit was a bad idea to begin with. Using databinding. Populating the chart in onResume()
I faced the same exception on Andorid11 with LineChart. I share this proj (https://github.com/vicpls/WChart) and Log.txt
i think it happen because the graph is init in hurry time. i use graph in ViewPager2
i solved it by give some delay
bind.barChart.postDelayed(Runnable { bind.barChart.show(datas) }, 5)