В следующем приложении у вас есть в основном 2 фрагмента: 1) база данных продуктов питания, 2) список потребляемых продуктов питания
1) пользователь может вручную добавлять продукты с соответствующей информацией о питательных микроэлементах (ккал, углеводы, белок, et c.). Данные хранятся в базе данных SQL через Room и отслеживаются с помощью LiveData
2) фрагмента (FoodDiaryFragment.kt), который показывает «потребленную» пищу с помощью recyclerView. Пользователь может добавлять продукты, нажимая FAB, который отправляет пользователя к другому фрагменту (AddConsumedFoodFragment.kt). это показывает счетчик и форму. Вращатель показывает список продуктов из базы данных продуктов (из 1). В форме пользователь может просто ввести одно значение (сколько граммов выбранной пищи было потреблено). Эти данные также добавляются в ту же базу данных SQL в таблице с: id (автоматически сгенерированным), количеством (введенным пользователем), потребляемым продуктом питания (выбранным из счетчика и подключенным к другой таблице через внешний ключ) и потребляемой датой ( автоматически сгенерированная дата в момент добавления элемента).
Представление переработчика (2) показывает элементы с дополнительной информацией, которая рассчитывается в RecyclerViewAdapter (в основном, умножая количество и соответствующую информацию о питательных микроэлементах [ккал, углеводы) , et c.], см. getDailyValues () в адаптере), а также «группирует» элементы по дате. Это означает, что для каждого дня в представление recyclerView добавляется отдельный viewHolder (DateViewHolder), который отображает день (и сумму каждого макроса) (см. SortAndGroupFood () в FoodDiaryFragment.kt)

Поскольку я использую RecyclerView Selection, setStableIds () (см. Блок init) имеет значение true. StableIdKeyProvider. java добавляет объект ChildAttachStateChangeListener с функцией onChilViewDetachedFrom Windows ().
Я не уверен точно, когда вызывается эта функция (я хотел бы получить объяснение), но иногда это происходит, когда либо Элемент удален (элементы могут быть удалены через RecyclerView.Selection) или элемент добавлен. Приложение вылетает с показанным ниже исключением NullPointerException. Когда приложение перезапускается, действие, которое в конечном итоге закончилось в cra sh, было успешно выполнено.
Я действительно в отчаянии и пытался выяснить, почему нулевое представление передается этой функции в течение нескольких часов , но, очевидно, я не добился успеха.
В соответствии с docs findConistingViewHolder возвращает ноль, если предоставленное представление не является потомком этого RecyclerView
Вопрос: Какие проблемы вызывает возвращение нуля и как я могу превратить его? GitHub Depo Link
FoodDiaryFragment.kt
import android.os.Bundle
import android.view.*
import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider
import androidx.navigation.fragment.findNavController
import androidx.recyclerview.selection.*
import androidx.recyclerview.widget.RecyclerView
import com.hooni.macrotracker.R
import com.hooni.macrotracker.adapter.ConsumedFoodRecyclerViewAdapter
import com.hooni.macrotracker.data.ConsumedFood
import com.hooni.macrotracker.recyclerviewselector.ConsumedFoodItemDetailsLookup
import com.hooni.macrotracker.viewmodels.FoodViewModel
import kotlinx.android.synthetic.main.fragment_food_diary.view.*
import java.text.DateFormat
import java.text.SimpleDateFormat
class FoodDiaryFragment : Fragment() {
private lateinit var foodViewModel: FoodViewModel
private lateinit var recyclerView: RecyclerView
private lateinit var adapter: ConsumedFoodRecyclerViewAdapter
private val dateFormat = DateFormat.getDateInstance()
var tracker: SelectionTracker<Long>? = null
var actionMode: ActionMode? = null
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val v = inflater.inflate(R.layout.fragment_food_diary, container, false)
initRecyclerView(v)
initViewModel()
initButtons(v)
// this makes sure, that in case the last destination was addConsumedFoodFragment
// the 'back' button doesn't bring you back to the addConsumedFoodFragment, but to the one that
// has been visited before
findNavController().popBackStack(R.id.addConsumedFoodFragment, true)
return v
}
private fun initButtons(v: View) {
val addNewFood = v.addNewConsumedFood
addNewFood.setOnClickListener {
findNavController().navigate(R.id.action_diaryFragment_to_addConsumedFoodFragment)
}
}
private fun initRecyclerView(view: View) {
recyclerView = view.food_diary_recyclerView
adapter = ConsumedFoodRecyclerViewAdapter()
recyclerView.adapter = adapter
recyclerView.layoutManager = LinearLayoutManager(activity)
tracker = SelectionTracker.Builder<Long>(
"selectedItemsConsumedFoo",
recyclerView,
StableIdKeyProvider(recyclerView),
ConsumedFoodItemDetailsLookup(recyclerView),
StorageStrategy.createLongStorage()
).withSelectionPredicate(
SelectionPredicates.createSelectAnything()
).build()
val actionModeCallBack = object : ActionMode.Callback {
override fun onCreateActionMode(mode: ActionMode?, menu: Menu?): Boolean {
val inflater = mode?.menuInflater
actionMode = mode
actionMode?.title = getString(R.string.delete)
inflater?.inflate(R.menu.action_menu, menu)
return true
}
override fun onActionItemClicked(mode: ActionMode?, item: MenuItem?): Boolean {
return when (item?.itemId) {
R.id.action_menu_delete -> {
removeItems(tracker?.selection!!)
tracker?.clearSelection()
actionMode?.finish()
actionMode = null
return true
}
else -> false
}
}
override fun onPrepareActionMode(mode: ActionMode?, menu: Menu?): Boolean {
return false
}
override fun onDestroyActionMode(mode: ActionMode?) {
tracker?.clearSelection()
actionMode?.finish()
actionMode = null
}
}
tracker?.addObserver(
object : SelectionTracker.SelectionObserver<Long>() {
override fun onSelectionChanged() {
if (tracker?.selection!!.size() > 0) {
if (actionMode == null) activity?.startActionMode(actionModeCallBack)
} else {
actionMode?.finish()
actionMode = null
}
}
}
)
adapter.tracker = tracker
}
private fun removeItems(selection: Selection<Long>) {
val foodsToDelete = adapter.getFood(selection)
foodsToDelete.forEach {
foodViewModel.deleteConsumedFood(it)
}
}
private fun initViewModel() {
foodViewModel = ViewModelProvider(this).get(FoodViewModel::class.java)
foodViewModel.allConsumedFood.observe(viewLifecycleOwner, Observer { consumedFoodList ->
consumedFoodList?.let { adapter.setConsumedFood(sortAndGroupFood(consumedFoodList)) }
})
foodViewModel.allFood.observe(viewLifecycleOwner, Observer { food ->
food?.let { adapter.setFood(food.sortedBy {it.foodName}) }
})
}
private fun sortAndGroupFood(consumedFoodList: List<ConsumedFood>): List<ConsumedFood> {
val sortedList = consumedFoodList.sortedBy{it.consumedDate}
val groupedMap: Map<String,List<ConsumedFood>> = sortedList.groupBy { dateFormat.format(it.consumedDate)}
val finalizedList = mutableListOf<ConsumedFood>()
groupedMap.forEach {
finalizedList.add(createDateHeader(it.key))
finalizedList.addAll(it.value)
}
return finalizedList.toList()
}
private fun createDateHeader(dateString: String): ConsumedFood {
val date = dateFormat.parse(dateString)
return ConsumedFood(null,-1,"DATE_HEADER",date!!)
}
}
AddFoodFragment.kt
package com.hooni.macrotracker.fragments
import android.annotation.SuppressLint
import android.os.Build
import android.os.Bundle
import android.text.InputType
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModelProvider
import androidx.navigation.fragment.findNavController
import com.google.android.material.textfield.TextInputLayout
import com.hooni.macrotracker.R
import com.hooni.macrotracker.data.Food
import com.hooni.macrotracker.util.Tools
import com.hooni.macrotracker.viewmodels.FoodViewModel
import kotlinx.android.synthetic.main.fragment_add_food.view.*
import java.text.DecimalFormatSymbols
import java.util.*
class AddFoodFragment : Fragment() {
private lateinit var foodViewModel: FoodViewModel
private lateinit var enterTextFoodName: TextInputLayout
private lateinit var enterTextKcal: TextInputLayout
private lateinit var enterTextCarbs: TextInputLayout
private lateinit var enterTextProtein: TextInputLayout
private lateinit var enterTextFat: TextInputLayout
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val v = inflater.inflate(R.layout.fragment_add_food, container, false)
initButtons(v)
initViewModel()
initTextInPutLayouts(v)
return v
}
private fun initTextInPutLayouts(v: View) {
enterTextFoodName = v.enter_food_name
enterTextKcal = v.enter_kcal
enterTextCarbs = v.enter_carbs
enterTextProtein = v.enter_protein
enterTextFat = v.enter_fat
enterTextCarbs.setNumberDecimalInputOnly()
enterTextProtein.setNumberDecimalInputOnly()
enterTextFat.setNumberDecimalInputOnly()
}
private fun initButtons(view: View) {
view.cancel_add_food.setOnClickListener {
findNavController().navigate(R.id.action_addFoodFragment_to_foodListFragment)
Tools.hideSoftKeyboard(view, context)
}
view.add_food.setOnClickListener {
if (validateValues()) {
val newFood = createNewFood()
foodViewModel.insertFood(newFood)
showSuccessfulAdd()
view.cancel_add_food.performClick()
}
}
}
private fun validateValues(): Boolean {
val isFoodNameValid = enterTextFoodName.validateInput { it != null }
val isKcalValid = enterTextKcal.validateInput { it?.toIntOrNull() != null }
val isCarbsValid = enterTextCarbs.validateInput { it?.toDoubleOrNull() != null }
val isProteinValid = enterTextProtein.validateInput { it?.toDoubleOrNull() != null }
val isFatValid = enterTextFat.validateInput { it?.toDoubleOrNull() != null }
return (isFoodNameValid
&& isKcalValid
&& isCarbsValid
&& isProteinValid
&& isFatValid)
}
private fun initViewModel() {
foodViewModel = ViewModelProvider(this).get(FoodViewModel::class.java)
}
private fun createNewFood(): Food {
val foodName =
enterTextFoodName.editText?.text.toString().trim()
val kcal =
enterTextKcal.editText?.text.toString().trim().toInt()
val carbs =
enterTextCarbs.editText?.text.toString().replaceDecimalSeparator().toDouble()
val protein =
enterTextProtein.editText?.text.toString().replaceDecimalSeparator().toDouble()
val fat = enterTextFat.editText?.text.toString().replaceDecimalSeparator().toDouble()
return Food(foodName, kcal, carbs.round(), fat.round(), protein.round())
}
private fun showSuccessfulAdd() {
Toast.makeText(
activity,
"${enterTextFoodName.editText?.text.toString().trim()} added to database",
Toast.LENGTH_SHORT
).show()
}
private inline fun TextInputLayout.validateInput(validate: (String?) -> Boolean): Boolean {
val textToValidate = this.editText?.text.toString().replaceDecimalSeparator().trim()
when {
textToValidate.isEmpty() -> {
error = getString(R.string.cant_be_empty)
}
!validate(textToValidate) -> {
error = getString(R.string.invalid_value)
}
else -> {
error = null
return true
}
}
return false
}
private fun TextInputLayout.setNumberDecimalInputOnly() {
this.editText?.apply {
inputType = InputType.TYPE_CLASS_NUMBER or InputType.TYPE_NUMBER_FLAG_DECIMAL
}
}
private fun Double.round(decimals: Int = 1): Double = "%.${decimals}f".format(Locale.US,this).toDouble()
@SuppressLint("NewApi")
private fun String.replaceDecimalSeparator(): String {
val decimalSeparator = when(Build.VERSION.SDK_INT) {
in Int.MIN_VALUE..Build.VERSION_CODES.M -> {DecimalFormatSymbols(resources.configuration.locale).decimalSeparator}
else -> DecimalFormatSymbols(resources.configuration.locales[0]).decimalSeparator
}
return this.replace(decimalSeparator, '.')
}
}
ConsumedFoodRecyclerViewAdapter.kt
package com.hooni.macrotracker.adapter
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.recyclerview.selection.ItemDetailsLookup
import androidx.recyclerview.selection.Selection
import androidx.recyclerview.selection.SelectionTracker
import androidx.recyclerview.widget.RecyclerView
import com.hooni.macrotracker.R
import com.hooni.macrotracker.data.ConsumedFood
import com.hooni.macrotracker.data.Food
import kotlinx.android.synthetic.main.fragment_food_diary_date_list_item.view.*
import kotlinx.android.synthetic.main.fragment_food_diary_list_item.view.*
import java.text.DateFormat
import java.util.*
private const val DATE_VIEW_HOLDER = 0
private const val CONSUMED_FOOD_VIEW_HOLDER = 1
class ConsumedFoodRecyclerViewAdapter : RecyclerView.Adapter<ConsumedFoodRecyclerViewAdapter.BaseViewHolder<*>>() {
private var mConsumedFoodList = emptyList<ConsumedFood>()
private var mFoodList = emptyList<Food>()
var tracker: SelectionTracker<Long>? = null
init {
setHasStableIds(true)
}
abstract class BaseViewHolder<T>(itemView: View): RecyclerView.ViewHolder(itemView) {
abstract fun getItemDetails(): ItemDetailsLookup.ItemDetails<Long>
}
inner class ConsumedFoodViewHolder(mView: View) :BaseViewHolder<ConsumedFood>(mView) {
private val mConsumedFoodName: TextView = mView.consumed_food_name
private val mConsumedKcal: TextView = mView.consumed_kcal
private val mConsumedAmount: TextView = mView.consumed_amount
private val mConsumedCarbs: TextView = mView.consumed_carb_amount
private val mConsumedProtein: TextView = mView.consumed_protein_amount
private val mConsumedFat: TextView = mView.consumed_fat_amount
override fun getItemDetails(): ItemDetailsLookup.ItemDetails<Long> =
object : ItemDetailsLookup.ItemDetails<Long>() {
override fun getSelectionKey(): Long? = itemId
override fun getPosition(): Int = adapterPosition
}
fun bind(isActivated: Boolean = false, item: ConsumedFood) {
val consumedMacroOfFood = calculateConsumedMacro(item.amount,item.consumedFood)
itemView.isActivated = isActivated
mConsumedFoodName.text = item.consumedFood
mConsumedKcal.text = itemView.context.getString(R.string.list_item_kcal,consumedMacroOfFood[0].toInt())
mConsumedAmount.text = itemView.context.getString(R.string.list_item_amount,item.amount)
mConsumedCarbs.text = itemView.context.getString(R.string.list_item_macro,consumedMacroOfFood[1])
mConsumedProtein.text = itemView.context.getString(R.string.list_item_macro,consumedMacroOfFood[2])
mConsumedFat.text = itemView.context.getString(R.string.list_item_macro,consumedMacroOfFood[3])
}
}
inner class DateViewHolder(mView: View): BaseViewHolder<ConsumedFood>(mView) {
private val mConsumedDate: TextView = mView.food_diary_date
private val mTotalConsumedDayKcal: TextView = mView.food_diary_date_sum_kcal
private val mTotalConsumedDayCarbs: TextView = mView.food_diary_date_sum_carbs
private val mTotalConsumedDayProtein: TextView = mView.food_diary_date_sum_protein
private val mTotalConsumedDayFat: TextView = mView.food_diary_date_sum_fat
override fun getItemDetails(): ItemDetailsLookup.ItemDetails<Long> =
object : ItemDetailsLookup.ItemDetails<Long>() {
override fun getSelectionKey(): Long? = itemId
override fun getPosition(): Int = adapterPosition
}
fun bind(item: ConsumedFood) {
mConsumedDate.text = itemView.context
.getString(R.string.list_item_date,DateFormat.getDateInstance(DateFormat.MEDIUM,DateFormat.getAvailableLocales()[0]).format(item.consumedDate))
mTotalConsumedDayKcal.text = itemView.context.getString(R.string.list_item_kcal,getDailyValues(item.consumedDate)[0].toInt())
mTotalConsumedDayCarbs.text = itemView.context.getString(R.string.list_item_macro,getDailyValues(item.consumedDate)[1])
mTotalConsumedDayProtein.text = itemView.context.getString(R.string.list_item_macro,getDailyValues(item.consumedDate)[2])
mTotalConsumedDayFat.text = itemView.context.getString(R.string.list_item_macro,getDailyValues(item.consumedDate)[3])
}
}
override fun getItemViewType(position: Int): Int {
return if(mConsumedFoodList[position].amount < 0) {
DATE_VIEW_HOLDER
} else CONSUMED_FOOD_VIEW_HOLDER
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BaseViewHolder<ConsumedFood> {
return when(viewType) {
DATE_VIEW_HOLDER -> {
val view = LayoutInflater.from(parent.context)
.inflate(R.layout.fragment_food_diary_date_list_item,parent,false)
DateViewHolder(view)
}
//CONSUMED_FOOD_VIEW_HOLDER
else -> {
val view = LayoutInflater.from(parent.context)
.inflate(R.layout.fragment_food_diary_list_item,parent,false)
ConsumedFoodViewHolder(view)
}
}
}
override fun getItemCount(): Int = mConsumedFoodList.size
override fun onBindViewHolder(holder: BaseViewHolder<*>, position: Int) {
when(holder) {
is DateViewHolder -> {
tracker?.let {
holder.bind(mConsumedFoodList[position])
}
}
is ConsumedFoodViewHolder -> {
tracker?.let {
holder.bind(it.isSelected(position.toLong()),mConsumedFoodList[position])
}
}
}
}
override fun getItemId(position: Int): Long = position.toLong()
internal fun getFood(ids: Selection<Long>): List<ConsumedFood> {
val foodsToDelete: MutableList<ConsumedFood> = mutableListOf()
ids.forEach {
foodsToDelete.add(mConsumedFoodList[it.toInt()])
}
return foodsToDelete.toList()
}
internal fun setConsumedFood(consumedFood: List<ConsumedFood>) {
mConsumedFoodList = consumedFood
notifyDataSetChanged()
}
internal fun setFood(food: List<Food>) {
mFoodList = food
notifyDataSetChanged()
}
private fun calculateConsumedMacro(amount: Int, food: String): List<Double>{
val kcalOfTheFood = mFoodList.firstOrNull{ it.foodName == food}?.kcal?.toDouble() ?: 0.0
val carbsOfTheFood = mFoodList.firstOrNull{ it.foodName == food}?.carbs ?: 0.0
val proteinOfTheFood = mFoodList.firstOrNull{ it.foodName == food}?.protein ?: 0.0
val fatOfTheFood = mFoodList.firstOrNull{ it.foodName == food}?.fat ?: 0.0
return listOf(kcalOfTheFood.getAmountOfMacro(amount),
carbsOfTheFood.getAmountOfMacro(amount),
proteinOfTheFood.getAmountOfMacro(amount),
fatOfTheFood.getAmountOfMacro(amount))
}
private fun Double.getAmountOfMacro(amount: Int): Double {
return this * amount / 100
}
private fun getDailyValues(day: Date): List<Double> {
val foodsOfSameDay = mConsumedFoodList.filter{ DateFormat.getDateInstance().format(it.consumedDate) == DateFormat.getDateInstance().format(day)}
val macrosOfSameDay = mutableListOf<List<Double>>()
foodsOfSameDay.forEach {macrosOfSameDay.add(calculateConsumedMacro(it.amount,it.consumedFood))}
val sumKcal = macrosOfSameDay.sumByDouble { it[0] }
val sumCarbs = macrosOfSameDay.sumByDouble { it[1] }
val sumProtein = macrosOfSameDay.sumByDouble { it[2] }
val sumFat = macrosOfSameDay.sumByDouble { it[3] }
return listOf(sumKcal,sumCarbs,sumProtein,sumFat)
}
}
Ошибка
2020-02-18 18:34:07.287 28614-28614/com.hooni.macrotracker E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.hooni.macrotracker, PID: 28614
java.lang.NullPointerException: Attempt to invoke virtual method 'int androidx.recyclerview.widget.RecyclerView$ViewHolder.getAdapterPosition()' on a null object reference
at androidx.recyclerview.selection.StableIdKeyProvider.onDetached(StableIdKeyProvider.java:90)
at androidx.recyclerview.selection.StableIdKeyProvider$1.onChildViewDetachedFromWindow(StableIdKeyProvider.java:69)
at androidx.recyclerview.widget.RecyclerView.dispatchChildDetached(RecyclerView.java:7546)
at androidx.recyclerview.widget.RecyclerView.removeDetachedView(RecyclerView.java:4349)
at androidx.recyclerview.widget.RecyclerView$Recycler.getScrapOrCachedViewForId(RecyclerView.java:6738)
at androidx.recyclerview.widget.RecyclerView$Recycler.tryGetViewHolderForPositionByDeadline(RecyclerView.java:6189)
at androidx.recyclerview.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:6118)
at androidx.recyclerview.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:6114)
at androidx.recyclerview.widget.LinearLayoutManager$LayoutState.next(LinearLayoutManager.java:2303)
at androidx.recyclerview.widget.LinearLayoutManager.layoutChunk(LinearLayoutManager.java:1627)
at androidx.recyclerview.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1587)
at androidx.recyclerview.widget.LinearLayoutManager.onLayoutChildren(LinearLayoutManager.java:665)
at androidx.recyclerview.widget.RecyclerView.dispatchLayoutStep2(RecyclerView.java:4134)
at androidx.recyclerview.widget.RecyclerView.dispatchLayout(RecyclerView.java:3851)
at androidx.recyclerview.widget.RecyclerView.onLayout(RecyclerView.java:4404)
at android.view.View.layout(View.java:20672)
at android.view.ViewGroup.layout(ViewGroup.java:6194)
at androidx.constraintlayout.widget.ConstraintLayout.onLayout(ConstraintLayout.java:1915)
at android.view.View.layout(View.java:20672)
at android.view.ViewGroup.layout(ViewGroup.java:6194)
at android.widget.FrameLayout.layoutChildren(FrameLayout.java:323)
at android.widget.FrameLayout.onLayout(FrameLayout.java:261)
at android.view.View.layout(View.java:20672)
at android.view.ViewGroup.layout(ViewGroup.java:6194)
at androidx.constraintlayout.widget.ConstraintLayout.onLayout(ConstraintLayout.java:1915)
at android.view.View.layout(View.java:20672)
at android.view.ViewGroup.layout(ViewGroup.java:6194)
at android.widget.FrameLayout.layoutChildren(FrameLayout.java:323)
at android.widget.FrameLayout.onLayout(FrameLayout.java:261)
at android.view.View.layout(View.java:20672)
at android.view.ViewGroup.layout(ViewGroup.java:6194)
at android.widget.FrameLayout.layoutChildren(FrameLayout.java:323)
at android.widget.FrameLayout.onLayout(FrameLayout.java:261)
at android.view.View.layout(View.java:20672)
at android.view.ViewGroup.layout(ViewGroup.java:6194)
at android.widget.FrameLayout.layoutChildren(FrameLayout.java:323)
at android.widget.FrameLayout.onLayout(FrameLayout.java:261)
at android.view.View.layout(View.java:20672)
at android.view.ViewGroup.layout(ViewGroup.java:6194)
at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1812)
at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1656)
at android.widget.LinearLayout.onLayout(LinearLayout.java:1565)
at android.view.View.layout(View.java:20672)
at android.view.ViewGroup.layout(ViewGroup.java:6194)
at android.widget.FrameLayout.layoutChildren(FrameLayout.java:323)
at android.widget.FrameLayout.onLayout(FrameLayout.java:261)
at com.android.internal.policy.DecorView.onLayout(DecorView.java:753)
at android.view.View.layout(View.java:20672)
at android.view.ViewGroup.layout(ViewGroup.java:6194)
at android.view.ViewRootImpl.performLayout(ViewRootImpl.java:2792)
at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2319)
at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1460)
at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:7183)
2020-02-18 18:34:07.288 28614-28614/com.hooni.macrotracker E/AndroidRuntime: at android.view.Choreographer$CallbackRecord.run(Choreographer.java:949)
at android.view.Choreographer.doCallbacks(Choreographer.java:761)
at android.view.Choreographer.doFrame(Choreographer.java:696)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:935)
at android.os.Handler.handleCallback(Handler.java:873)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:6669)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
при добавлении нового элемента в recyclerView.