I am making a news app in android but I am getting error when I call a API(http) from my app. I don't know why the error is coming I implemented all the class, memebers, function.
Pleas help me.
Here is the error description
2021-01-21 09:21:25.896 18052-18052/com.arne.khabriapp E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.arne.khabriapp, PID: 18052
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.arne.khabriapp/com.arne.khabriapp.MainActivity}: kotlin.UninitializedPropertyAccessException: lateinit property mAdapter has not been initialized
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: kotlin.UninitializedPropertyAccessException: lateinit property mAdapter has not been initialized
at com.arne.khabriapp.MainActivity.onCreate(MainActivity.kt:25)
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)
2021-01-21 09:21:25.912 18052-18090/com.arne.khabriapp D/NetworkSecurityConfig:
No Network Security Config specified, using platform default
Here is my MainActivity.kt
package com.arne.khabriapp
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Toast
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.android.volley.Request
import com.android.volley.toolbox.JsonObjectRequest
class MainActivity : AppCompatActivity(), NewsItemClicked {
private lateinit var mAdapter: NewsListAdapter
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val recyclerView = findViewById<RecyclerView>(R.id.rView)
recyclerView.layoutManager = LinearLayoutManager(this)
// recyclerView.layoutManager = GridLayoutManager(this,12)
// recyclerView.layoutManager = StaggeredGridLayoutManager(15,12)
fetchData()
recyclerView.adapter = mAdapter
}
private fun fetchData() {
// val list = ArrayList<String>()
// for(i in 0 until 100){
// list.add("item $i")
// }
// return list
val url = "https://newsapi.org/v2/top-headlines?country=in&apiKey=9bb7bf6152d147ad8ba14cd0e7452f2f"
val jsonObjectRequest = JsonObjectRequest(
Request.Method.GET,
url,
null,
{
val newsJsonArray = it.getJSONArray("articles")
val newsArray = ArrayList<NewsClass>()
for (i in 0 until newsJsonArray.length()){
val newsJsonObject = newsJsonArray.getJSONObject(i)
val news =NewsClass(
newsJsonObject.getString("title"),
newsJsonObject.getString("author"),
newsJsonObject.getString("url"),
newsJsonObject.getString("urlToImage")
)
newsArray.add(news)
}
mAdapter.updateNews(newsArray)
},
{
}
)
MySingletonClass.getInstance(this).addRequestQueue(jsonObjectRequest)
}
override fun OnItemClick(item: NewsClass) {
}
}
Here is my NewsAdapter.kt
package com.arne.khabriapp
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
//class Name: extendItForRecyclerView.Adapter<ViewHolderClass>
class NewsListAdapter( private val listener: NewsItemClicked): RecyclerView.Adapter<NewsViewHolder>()
{
private val items: ArrayList<NewsClass> = ArrayList()
// call me when each time one viewholder is created
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): NewsViewHolder {
//Layout Inflater - Converts XML into View
val view = LayoutInflater.from(parent.context).inflate(R.layout.itemnews, parent, false)
val viewHolder = NewsViewHolder(view)
view.setOnClickListener{
//this is a call back to main activity so the main activity knows that any item is clicked and then the mainn activity behave according to this.
listener.OnItemClick(items[viewHolder.adapterPosition])
}
return viewHolder
}
// I will bind the item with viewholder
override fun onBindViewHolder(holder: NewsViewHolder, position: Int) {
val currentItem = items[position]
holder.titleView.text = currentItem.title
}
// call me only one time i will give you how many item will be here in list
override fun getItemCount(): Int {
return items.size
}
fun updateNews(updatedNews: ArrayList<NewsClass>){
items.clear()
items.addAll(updatedNews)
notifyDataSetChanged()
}
}
class NewsViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView){
val titleView: TextView = itemView.findViewById(R.id.title)
}
interface NewsItemClicked{
fun OnItemClick(item: NewsClass)
}
Please Give Some Answer
Thank you very much in advanced
You can do it like this.
private lateinit var mAdapter: NewsListAdapter
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val recyclerView = findViewById<RecyclerView>(R.id.rView)
recyclerView.layoutManager = LinearLayoutManager(this)
// recyclerView.layoutManager = GridLayoutManager(this,12)
// recyclerView.layoutManager = StaggeredGridLayoutManager(15,12)
mAdapter = NewsListAdapter(this)//should be inited before use.
fetchData()
recyclerView.adapter = mAdapter
}
Or you can do it this way
private val mAdapter: NewsListAdapter by lazy{
NewsListAdapter(this)
}
Related
I have a MainFragment.kt
package com.funkytwig.tasktimer
import android.content.Context
import android.os.Bundle
import android.util.Log
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider
import androidx.recyclerview.widget.LinearLayoutManager
import com.funkytwig.tasktimer.databinding.FragmentMainBinding
private const val TAG = "MainFragmentXX"
/**
* A simple [Fragment] subclass as the default destination in the navigation.
*/
class MainFragment : Fragment() {
private var _binding: FragmentMainBinding? = null
private val viewModel by lazy { ViewModelProvider(this)[TaskTimerViewModel::class.java] } // New
private val mAdapter = CursorRecyclerViewAdapter(null) // null=view with instructions NEW
// This property is only valid between onCreateView and
// onDestroyView.
private val binding get() = _binding!!
override fun onCreate(savedInstanceState: Bundle?) {
val funct = "onCreate"
Log.d(TAG, funct)
super.onCreate(savedInstanceState)
Log.d(TAG, "$funct about to register viewModel")
viewModel.cursor.observe( // New
this, Observer { cursor -> mAdapter.swapCursor(cursor)?.close() }
)
Log.d(TAG, "$funct done")
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
): View? {
Log.d(TAG, "onCreateView")
_binding = FragmentMainBinding.inflate(inflater, container, false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
Log.d(TAG, "onViewCreated")
super.onViewCreated(view, savedInstanceState)
binding.taskList.layoutManager =
LinearLayoutManager(context) // Set layout manager to Linear NEW
binding.taskList.adapter = mAdapter // Attach Adapter to Recyclerview New
}
override fun onDestroyView() {
Log.d(TAG, "onDestroyView")
super.onDestroyView()
_binding = null
}
// ** From here ist just logging functions **
override fun onAttach(context: Context) {
Log.d(TAG, "onAttach")
super.onAttach(context)
}
// override fun onActivityCreated(savedInstanceState: Bundle?) { // depreciated
// Log.d(TAG, "onActivityCreated(depreciated)")
// super.onActivityCreated(savedInstanceState)
// }
override fun onViewStateRestored(savedInstanceState: Bundle?) {
Log.d(TAG, "onViewStateRestored")
super.onViewStateRestored(savedInstanceState)
}
override fun onStart() {
Log.d(TAG, "onStart")
super.onStart()
}
override fun onResume() {
Log.d(TAG, "onResume")
super.onResume()
}
override fun onPause() {
Log.d(TAG, "onPause")
super.onPause()
}
override fun onSaveInstanceState(outState: Bundle) {
Log.d(TAG, "onSaveInstanceState")
super.onSaveInstanceState(outState)
}
override fun onStop() {
Log.d(TAG, "onStop")
super.onStop()
}
override fun onDestroy() {
Log.d(TAG, "onDestroy")
super.onDestroy()
}
override fun onDetach() {
Log.d(TAG, "onDetach")
super.onDetach()
}
}
And am getting the following errors in Logcat when
viewModel.cursor.observe( // New
this, Observer { cursor -> mAdapter.swapCursor(cursor)?.close() }
)
runs in onCreate (i.e. if I comment out this it works)
FATAL EXCEPTION: main
Process: com.funkytwig.takstimer, PID: 7099
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.funkytwig.takstimer/com.funkytwig.tasktimer.MainActivity}: android.view.InflateException: Binary XML file line #25 in com.funkytwig.takstimer:layout/activity_main: Binary XML file line #15 in com.funkytwig.takstimer:layout/content_main: Error inflating class androidx.fragment.app.FragmentContainerView
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: android.view.InflateException: Binary XML file line #25 in com.funkytwig.takstimer:layout/activity_main: Binary XML file line #15 in com.funkytwig.takstimer:layout/content_main: Error inflating class androidx.fragment.app.FragmentContainerView
Caused by: android.view.InflateException: Binary XML file line #15 in com.funkytwig.takstimer:layout/content_main: Error inflating class androidx.fragment.app.FragmentContainerView
Caused by: java.lang.RuntimeException: Cannot create an instance of class com.funkytwig.tasktimer.TaskTimerViewModel
at androidx.lifecycle.ViewModelProvider$AndroidViewModelFactory.create(ViewModelProvider.kt:320)
at androidx.lifecycle.ViewModelProvider$AndroidViewModelFactory.create(ViewModelProvider.kt:304)
at androidx.lifecycle.ViewModelProvider$AndroidViewModelFactory.create(ViewModelProvider.kt:278)
at androidx.lifecycle.SavedStateViewModelFactory.create(SavedStateViewModelFactory.kt:128)
at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.kt:187)
at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.kt:153)
at com.funkytwig.tasktimer.MainFragment$viewModel$2.invoke(MainFragment.kt:23)
at com.funkytwig.tasktimer.MainFragment$viewModel$2.invoke(MainFragment.kt:23)
at kotlin.SynchronizedLazyImpl.getValue(LazyJVM.kt:74)
at com.funkytwig.tasktimer.MainFragment.getViewModel(MainFragment.kt:23)
at com.funkytwig.tasktimer.MainFragment.onCreate(MainFragment.kt:35)
at androidx.fragment.app.Fragment.performCreate(Fragment.java:3090)
at androidx.fragment.app.FragmentStateManager.create(FragmentStateManager.java:475)
at androidx.fragment.app.FragmentStateManager.moveToExpectedState(FragmentStateManager.java:257)
at androidx.fragment.app.FragmentManager.executeOpsTogether(FragmentManager.java:1890)
at androidx.fragment.app.FragmentManager.removeRedundantOperationsAndExecute(FragmentManager.java:1814)
at androidx.fragment.app.FragmentManager.execSingleAction(FragmentManager.java:1720)
at androidx.fragment.app.BackStackRecord.commitNowAllowingStateLoss(BackStackRecord.java:323)
at androidx.fragment.app.FragmentContainerView.<init>(FragmentContainerView.kt:158)
at androidx.fragment.app.FragmentLayoutInflaterFactory.onCreateView(FragmentLayoutInflaterFactory.java:53)
at androidx.fragment.app.FragmentController.onCreateView(FragmentController.java:136)
at androidx.fragment.app.FragmentActivity.dispatchFragmentsOnCreateView(FragmentActivity.java:248)
at androidx.fragment.app.FragmentActivity.onCreateView(FragmentActivity.java:227)
at android.view.LayoutInflater.tryCreateView(LayoutInflater.java:1069)
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:997)
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:961)
at android.view.LayoutInflater.rInflate(LayoutInflater.java:1123)
at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:1084)
at android.view.LayoutInflater.parseInclude(LayoutInflater.java:1263)
at android.view.LayoutInflater.rInflate(LayoutInflater.java:1119)
at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:1084)
at android.view.LayoutInflater.inflate(LayoutInflater.java:682)
at android.view.LayoutInflater.inflate(LayoutInflater.java:534)
at com.funkytwig.tasktimer.databinding.ActivityMainBinding.inflate(ActivityMainBinding.java:55)
at com.funkytwig.tasktimer.databinding.ActivityMainBinding.inflate(ActivityMainBinding.java:49)
at com.funkytwig.tasktimer.MainActivity.onCreate(MainActivity.kt:27)
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)
Caused by: java.lang.reflect.InvocationTargetException
at java.lang.reflect.Constructor.newInstance0(Native Method)
at java.lang.reflect.Constructor.newInstance(Constructor.java:343)
at androidx.lifecycle.ViewModelProvider$AndroidViewModelFactory.create(ViewModelProvider.kt:312)
... 50 more
Caused by: java.lang.IllegalArgumentException: Cannot bind argument at index 3 because the index is out of range. The statement has 0 parameters.
at android.database.sqlite.SQLiteProgram.bind(SQLiteProgram.java:215)
at android.database.sqlite.SQLiteProgram.bindString(SQLiteProgram.java:169)
at android.database.sqlite.SQLiteProgram.bindAllArgsAsStrings(SQLiteProgram.java:203)
at android.database.sqlite.SQLiteDirectCursorDriver.query(SQLiteDirectCursorDriver.java:49)
at android.database.sqlite.SQLiteDatabase.rawQueryWithFactory(SQLiteDatabase.java:1443)
at android.database.sqlite.SQLiteQueryBuilder.query(SQLiteQueryBuilder.java:515)
at android.database.sqlite.SQLiteQueryBuilder.query(SQLiteQueryBuilder.java:392)
at com.funkytwig.tasktimer.AppProvider.query(AppProvider.kt:125)
at android.content.ContentProvider.query(ContentProvider.java:1214)
at android.content.ContentProvider.query(ContentProvider.java:1307)
at android.content.ContentProvider$Transport.query(ContentProvider.java:267)
at android.content.ContentResolver.query(ContentResolver.java:944)
at android.content.ContentResolver.query(ContentResolver.java:880)
at android.content.ContentResolver.query(ContentResolver.java:836)
at com.funkytwig.tasktimer.TaskTimerViewModel.loadTasks(TaskTimerViewModel.kt:32)
at com.funkytwig.tasktimer.TaskTimerViewModel.<init>(TaskTimerViewModel.kt:19)
... 53 more
TaskTimerViewModel.kt is
package com.funkytwig.tasktimer
import android.app.Application
import android.database.Cursor
import android.util.Log
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
private const val TAG = "TaskTimerViewModelXX"
class TaskTimerViewModel(application: Application) : AndroidViewModel(application) {
private val dbCursor = MutableLiveData<Cursor>()
val cursor: LiveData<Cursor>
get() = dbCursor
init {
Log.d(TAG, "init")
loadTasks()
}
private fun loadTasks() {
val funct = "loadTasks"
Log.d(TAG, funct)
val projection = arrayOf(
TasksContract.Columns.TASK_NAME,
TasksContract.Columns.TASK_DESCRIPTION,
TasksContract.Columns.TASK_SORT_ORDER
)
val sortOrder =
"${TasksContract.Columns.TASK_SORT_ORDER}, ${TasksContract.Columns.TASK_NAME}"
val cursor = getApplication<Application>().contentResolver.query(
TasksContract.CONTENT_URI, null, null, projection, sortOrder
)
dbCursor.postValue(cursor!!) // Update on different thread
Log.d(TAG, "$funct done")
}
}
CursorViewRecyclerAdapter.kt is
package com.funkytwig.tasktimer
import android.database.Cursor
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageButton
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import com.funkytwig.tasktimer.databinding.TaskListItemsBinding
private const val TAG = "CurRecViewAdapterXX"
class TaskViewHolder(private val binding: TaskListItemsBinding) :
RecyclerView.ViewHolder(binding.root) {
val taskListName: TextView = binding.taskListName
val taskListDescription: TextView = binding.taskListDescription
val taskListEdit: ImageButton = binding.taskListEdit
val taskListDelete: ImageButton = binding.taskListDelete
}
class CursorRecyclerViewAdapter(private var cursor: Cursor?) :
RecyclerView.Adapter<TaskViewHolder>() {
// Called by Recyclerview when it needs new view to display
// viewType allows different types to be shows on different lines of view,
// to find out more google 'Recyclerview getItemViewType
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TaskViewHolder {
Log.d(TAG, "onCreateViewHolder (new view requested)")
val viewHolder = TaskListItemsBinding.inflate(LayoutInflater.from(parent.context), parent, false)
return TaskViewHolder(viewHolder)
}
// When Recycler view wants new data to be displayed and is providing existing view to be reused
override fun onBindViewHolder(holder: TaskViewHolder, position: Int) {
val func = "onBindViewHolder"
Log.d(TAG, "$func (bind data to view)")
val cursor = cursor // Smart Cast Hack
if (cursor == null || cursor.count == 0) { // No items in cursor
Log.d(TAG, "$func: providing instructions ")
holder.taskListName.setText(R.string.instructions_heading)
holder.taskListDescription.setText(R.string.instructions)
holder.taskListEdit.visibility = View.GONE
holder.taskListDelete.visibility = View.GONE
} else { // Cursor not empty
if (!cursor.moveToPosition(position)) throw IllegalStateException("Could not move cursor to position $position")
// Create Task object from data in cursor
val task = Task(
cursor.getString(cursor.getColumnIndex(TasksContract.Columns.TASK_NAME)),
cursor.getString(cursor.getColumnIndex(TasksContract.Columns.TASK_DESCRIPTION)),
cursor.getInt(cursor.getColumnIndex(TasksContract.Columns.TASK_SORT_ORDER))
)
// Remember ID is not set in constructor
task.id = cursor.getLong(cursor.getColumnIndex(TasksContract.Columns.ID))
holder.taskListName.text = task.name
holder.taskListDescription.text = task.description
holder.taskListEdit.visibility = View.VISIBLE // TODO: add onclick
holder.taskListDelete.visibility = View.VISIBLE // TODO: add onclick
}
}
override fun getItemCount(): Int {
val func = "getItemCount"
Log.d(TAG, func)
val count = cursor?.count
if (count == 0 || cursor == null) {
Log.d(TAG, "$func: no items so return 1")
return 1 // So Instructions are displayed if cursor empty
} else {
Log.d(TAG, "$func: $count items")
return count!!.toInt()
}
}
/**
* Swap is a new cursor, returning the old cursor.
* The returned cursor is *not* closed
*
* This allows underlying cursor to be swapped if data changes and we need to re query
* Should be called when the cursor that the adapter is using is changed.
* Reruns previous cursor so it can be closed.
*
* #param newCursor The new cursor to be used if there was not one.
* If the given new cursor is the same as the previous set cursor, null is also returned.
*/
fun swapCursor(newCursor: Cursor?): Cursor? {
if (newCursor === cursor) return null
val numItems = itemCount
val oldCursor = cursor
if (newCursor != null) {
// notify observer about cursor
notifyDataSetChanged()
} else { // cursor has changed
// Notify observer about lack of dataset, all of it from 0 to newItems,
// i.e. whole range of records has gone
notifyItemRangeChanged(0, numItems)
}
return oldCursor
}
}
All the code is at https://github.com/funkytwig/tasktimer/tree/master/app/src/main
Ive been googling and trying to work this out for a few houres but no joy.
I am retrieving data from a json weblink using retrofit2 which is working as intended and I checked the debugger and it shows that the elements are being added in the private variables, however, I am attempting to display the String elements that I obtained from the json link and added to an ArrayList and when I call the RecyclerViewAdapter to display the results I keep getting an IndexOutOfBoundsException saying that the elements are in fact null?
In the FetchContent object init block I am calling getRetroFitData() to connect to the json URL and retrieve the data in the json link and then save the results in the private variables in that same function. After that when I call the recycler view I add the results to the data class by using the getter functions to create each Item in the jsonITEMS variable but during this process I get the exception thrown.
I cannot figure out why or how the ArrayList becomes null after I iterate them:
ItemFragment.kt
package com.example.fetch_coding_exercise
import android.os.Bundle
import android.util.Log
import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
/**
* A fragment representing a list of Items.
*/
const val PRIMARY_URL = "" // Intentionally left empty do to contents of link
class ItemFragment : Fragment() {
private var columnCount = 1
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
arguments?.let {
columnCount = it.getInt(ARG_COLUMN_COUNT)
}
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val view = inflater.inflate(R.layout.fragment_item_list, container, false)
// Set the adapter
if (view is RecyclerView) {
with(view) {
layoutManager = when {
columnCount <= 1 -> LinearLayoutManager(context)
else -> GridLayoutManager(context, columnCount)
}
adapter = MyItemRecyclerViewAdapter(FetchContent.jsonITEMS)
}
}
return view
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
}
companion object {
// TODO: Customize parameter argument names
const val ARG_COLUMN_COUNT = "column-count"
// TODO: Customize parameter initialization
#JvmStatic
fun newInstance(columnCount: Int) =
ItemFragment().apply {
arguments = Bundle().apply {
putInt(ARG_COLUMN_COUNT, columnCount)
}
}
}
}
MyItemRecyclerViewAdapter.kt
package com.example.fetch_coding_exercise
import androidx.recyclerview.widget.RecyclerView
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import android.widget.Toast
import com.example.fetch_coding_exercise.placeholder.PlaceholderContent.PlaceholderItem
import com.example.fetch_coding_exercise.databinding.FragmentItemBinding
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
/**
* [RecyclerView.Adapter] that can display a [PlaceholderItem].
* TODO: Replace the implementation with code for your data type.
*/
class MyItemRecyclerViewAdapter(private val values: List<FetchContent.FetchDataItem>)
: RecyclerView.Adapter<MyItemRecyclerViewAdapter.ViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
return ViewHolder(
FragmentItemBinding.inflate(
LayoutInflater.from(parent.context),
parent,
false
)
)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val item = values[position]
holder.userIdView.text = item.id
holder.listIdView.text = item.listId
holder.nameView.text = item.name
}
override fun getItemCount(): Int = values.size
inner class ViewHolder(binding: FragmentItemBinding) : RecyclerView.ViewHolder(binding.root) {
val userIdView: TextView = binding.userID
val listIdView: TextView = binding.listID
val nameView: TextView = binding.name
override fun toString(): String {
return super.toString() + " '" + nameView.text + "'"
}
}
}
FetchContent.kt
package com.example.fetch_coding_exercise
import java.util.ArrayList
import java.util.HashMap
object FetchContent {
val jsonITEMS: MutableList<FetchDataItem> = ArrayList()
private val COUNT = 25
init {
fetchedData().getRetroFitData()
for (i in 0..COUNT) {
addItem(createFetchItem(i))
}
}
private fun addItem(item: FetchDataItem) {
jsonITEMS.add(item)
}
private fun createFetchItem(position: Int): FetchDataItem {
return FetchDataItem(
fetchedData().getID(position), fetchedData().getListID(position), fetchedData().getName(position))
}
data class FetchDataItem(val id: String, val listId: String, val name: String) {
override fun toString(): String = listId
}
}
fetchedData.kt
package com.example.fetch_coding_exercise
import android.util.Log
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import java.util.jar.Attributes
class fetchedData : ArrayList<fetchedDataItem>() {
private val retroId = arrayListOf<String>()
private val retroListId = arrayListOf<String>()
private val retroName = arrayListOf<String>()
private var retroCOUNT = 0
fun getRetroFitData() {
val retrofitBuilder = Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create())
.baseUrl(PRIMARY_URL)
.build()
.create(interfaceAPI::class.java)
val retrofitData = retrofitBuilder.getData()
retrofitData.enqueue(object : Callback<List<FetchContent.FetchDataItem>?> {
override fun onResponse(
call: Call<List<FetchContent.FetchDataItem>?>,
response: Response<List<FetchContent.FetchDataItem>?>
) {
val responseBody = response.body()!!
retroCOUNT = responseBody.size
for (i in responseBody.indices) {
if (!responseBody[i].name.isNullOrEmpty()) {
retroId.add(responseBody[i].id)
retroListId.add(responseBody[i].listId)
retroName.add(responseBody[i].name)
} else {
retroCOUNT--
}
}
println("retroId: " + retroId)
println("retroListId: " + retroListId)
println("retroName: " + retroName)
}
override fun onFailure(call: Call<List<FetchContent.FetchDataItem>?>, t: Throwable) {
Log.d("FetchContent", "onFailure:"+t.message)
}
})
}
fun getID(index: Int): String {
return if (retroId[index].isEmpty())
"null"
else
retroId[index]
}
fun getListID(index: Int): String {
return retroListId[index]
}
fun getName(index: Int): String {
return retroName[index]
}
}
Logcat Error Message
2021-09-30 14:26:54.022 28416-28416/? E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.fetch_coding_exercise, PID: 28416
java.lang.ExceptionInInitializerError
at com.example.fetch_coding_exercise.ItemFragment.onCreateView(ItemFragment.kt:48)
at androidx.fragment.app.Fragment.performCreateView(Fragment.java:2963)
at androidx.fragment.app.FragmentStateManager.createView(FragmentStateManager.java:518)
at androidx.fragment.app.FragmentStateManager.moveToExpectedState(FragmentStateManager.java:282)
at androidx.fragment.app.FragmentStore.moveToExpectedState(FragmentStore.java:112)
at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1647)
at androidx.fragment.app.FragmentManager.dispatchStateChange(FragmentManager.java:3128)
at androidx.fragment.app.FragmentManager.dispatchActivityCreated(FragmentManager.java:3072)
at androidx.fragment.app.FragmentController.dispatchActivityCreated(FragmentController.java:251)
at androidx.fragment.app.FragmentActivity.onStart(FragmentActivity.java:502)
at androidx.appcompat.app.AppCompatActivity.onStart(AppCompatActivity.java:246)
at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1435)
at android.app.Activity.performStart(Activity.java:8018)
at android.app.ActivityThread.handleStartActivity(ActivityThread.java:3475)
at android.app.servertransaction.TransactionExecutor.performLifecycleSequence(TransactionExecutor.java:221)
at android.app.servertransaction.TransactionExecutor.cycleToPath(TransactionExecutor.java:201)
at android.app.servertransaction.TransactionExecutor.executeLifecycleState(TransactionExecutor.java:173)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:97)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2066)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:223)
at android.app.ActivityThread.main(ActivityThread.java:7656)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)
Caused by: java.lang.IndexOutOfBoundsException: Index: 0, Size: 0
at java.util.ArrayList.get(ArrayList.java:437)
at com.example.fetch_coding_exercise.fetchedData.getID(fetchedData.kt:57)
at com.example.fetch_coding_exercise.FetchContent.createFetchItem(FetchContent.kt:48)
at com.example.fetch_coding_exercise.FetchContent.<clinit>(FetchContent.kt:33)
com.google.firebase.database.DatabaseException: Can't convert an object of type java.lang.String to type, seem this error always happens but I still don't know how to solve it.
This is my activity to display RecyclerView:
package com.example.budget
import android.content.Intent
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.Gravity
import android.view.View
import android.widget.ImageButton
import android.widget.TextView
import androidx.drawerlayout.widget.DrawerLayout
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.example.budget.data.bill
import com.example.budget.login_register.LoginActivity
import com.google.firebase.database.*
import com.google.android.material.navigation.NavigationView
import com.google.firebase.auth.FirebaseAuth
import com.google.firebase.database.DatabaseReference
class TransactionActivity : AppCompatActivity(),NavigationView.OnNavigationItemSelectedListener {
lateinit var drawer_layout: DrawerLayout
lateinit var ref: DatabaseReference
lateinit var database: FirebaseDatabase
lateinit var nav_view: NavigationView
lateinit var btnMenu: ImageButton
var isbtnMenuClicked: Boolean = false
var id: Int = 0
var strName =""
var strEmail = ""
lateinit var nav_header : View
lateinit var tvName: TextView
lateinit var tvEmail: TextView
lateinit var auth: FirebaseAuth
lateinit var list_bill : ArrayList<bill>
lateinit var billRecycleView : RecyclerView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_transaction)
billRecycleView = findViewById(R.id.list_bill)
database = FirebaseDatabase.getInstance()
auth = FirebaseAuth.getInstance()
drawer_layout = findViewById(R.id.drawer_layout)
nav_view = findViewById(R.id.nav_view)
btnMenu = findViewById(R.id.btnMenu)
nav_header = nav_view.getHeaderView(0)
tvName = nav_header.findViewById(R.id.tvName)
tvEmail = nav_header.findViewById(R.id.tvEmail)
setUsername()
setEmail()
nav_view.setNavigationItemSelectedListener(this)
btnMenuClicked()
auth= FirebaseAuth.getInstance()
billRecycleView.layoutManager= LinearLayoutManager(this)
billRecycleView.setHasFixedSize(true)
list_bill = arrayListOf<bill>()
getTransaction()
}
fun getTransaction(){
val uid = auth.currentUser!!.uid
ref = database.getReference("Bill").child(uid)
ref.addValueEventListener(object : ValueEventListener{
override fun onDataChange(snapshot: DataSnapshot) {
if (snapshot.exists()){
for (data in snapshot.children){
val model = data.getValue(bill::class.java)
list_bill.add(model!!)
}
billRecycleView.adapter = Myadpater(list_bill)
}
}
override fun onCancelled(error: DatabaseError) {
TODO("Not yet implemented")
}
})
}
This is Myadapter class
class Myadpater(val list_bill: ArrayList<bill>) :
RecyclerView.Adapter<Myadpater.MyViewHolder>() {
class MyViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val category: TextView = itemView.findViewById(R.id.TCategory)
val expense: TextView = itemView.findViewById(R.id.TExpense)
val date :TextView = itemView.findViewById(R.id.TDate)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
val itemView =
LayoutInflater.from(parent.context).inflate(R.layout.transaction_history, parent, false)
return MyViewHolder(itemView)
}
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
holder.category.text = list_bill[position].category
holder.expense.text = list_bill[position].expense
holder.date.text = list_bill[position].date
}
override fun getItemCount(): Int {
return list_bill.size
}
}
class Myadpater(val list_bill: ArrayList<bill>) :
RecyclerView.Adapter<Myadpater.MyViewHolder>() {
class MyViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val category: TextView = itemView.findViewById(R.id.TCategory)
val expense: TextView = itemView.findViewById(R.id.TExpense)
val date :TextView = itemView.findViewById(R.id.TDate)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
val itemView =
LayoutInflater.from(parent.context).inflate(R.layout.transaction_history, parent, false)
return MyViewHolder(itemView)
}
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
holder.category.text = list_bill[position].category
holder.expense.text = list_bill[position].expense
holder.date.text = list_bill[position].date
}
override fun getItemCount(): Int {
return list_bill.size
}
}
enter image description here
this is the error that I get
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.budget, PID: 5201
com.google.firebase.database.DatabaseException: Can't convert object of type java.lang.String to type com.example.budget.data.bill
at com.google.firebase.database.core.utilities.encoding.CustomClassMapper.convertBean(CustomClassMapper.java:436)
at com.google.firebase.database.core.utilities.encoding.CustomClassMapper.deserializeToClass(CustomClassMapper.java:232)
at com.google.firebase.database.core.utilities.encoding.CustomClassMapper.convertToCustomClass(CustomClassMapper.java:80)
at com.google.firebase.database.DataSnapshot.getValue(DataSnapshot.java:203)
at com.example.budget.TransactionActivity$getTransaction$1.onDataChange(TransactionActivity.kt:71)
at com.google.firebase.database.core.ValueEventRegistration.fireEvent(ValueEventRegistration.java:75)
at com.google.firebase.database.core.view.DataEvent.fire(DataEvent.java:63)
at com.google.firebase.database.core.view.EventRaiser$1.run(EventRaiser.java:55)
at android.os.Handler.handleCallback(Handler.java:938)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:223)
at android.app.ActivityThread.main(ActivityThread.java:7656)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)
When you are using the following reference:
ref = database.getReference("Bill").child(uid)
And looping through the DataSnapshot using the following loop:
for (data in snapshot.children){
val model = data.getValue(bill::class.java)
list_bill.add(model!!)
}
It means that you are trying to get each child that exists within the UID node and convert it to an object of type model. Seeing your screenshot, I can say that there are no model objects under the UID node, but only String objects. Since there is no way in Kotlin in which you can convert a String to an object of type model, you get the mentioned error. If you want to have multiple model objects under the UID node, then you should use push(), every time you add data:
ref.push().setValue(yourModelObj).addOnCompleteListener(/* ... /*)
// ^^^^^
Your new database schema will look like this:
Firebase-root
|
--- Bill
|
--- KoqT...O6H3
|
--- $pushedId //Newly added level
|
--- categoryy: "food"
|
--- date: "22 Jul, 2021"
|
--- expense: "20"
To get all model objects back, there is nothing to do, your actual code will work perfectly fine.
P.S. Don't forget to remove the String values that exist right now, otherwise, you'll continue to get that Exception.
Mostly the exact code works fine in another type of code structure yet doesn't work here although the structure of DB is perfectly aligned like it should be
Favourites:
+-UID:
+---id: restaurant_id
+---name: "name"
+---rating: rating
+image_url:"image_url"
FavrouiteFragment code:
package com.reazon.foodrunner.fragment
import android.os.Bundle
import android.util.Log
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.google.firebase.auth.FirebaseAuth
import com.google.firebase.database.*
import com.reazon.foodrunner.R
import com.reazon.foodrunner.adapter.FavouriteRecyclerAdapter
import com.reazon.foodrunner.model.Favourite
class FavouriteFragment : Fragment() {
private var recyclerAdapter: FavouriteRecyclerAdapter? = null
private var recyclerFavourite: RecyclerView? = null
internal var favouritesList: MutableList<Favourite> = ArrayList()
private var layoutManager: RecyclerView.LayoutManager? = null
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
val view = inflater.inflate(R.layout.fragment_favourite, container, false)
recyclerFavourite = view.findViewById(R.id.recyclerFavouriteAll)
layoutManager = LinearLayoutManager(activity)
recyclerFavourite!!.layoutManager = layoutManager
retrieveAllFavouriteRestaurants()
return view
}
private fun retrieveAllFavouriteRestaurants() {
favouritesList.clear()
val firebaseUser = FirebaseAuth.getInstance().currentUser!!.uid
val mDatabaseReference = FirebaseDatabase.getInstance().reference.child("Favourites/$firebaseUser")//.child()
mDatabaseReference.addValueEventListener(object : ValueEventListener {
override fun onCancelled(error: DatabaseError) {
Log.d("ERROR ", "" + error.message)
}
override fun onDataChange(p0: DataSnapshot) {
for (snapshot in p0.children) {
val favorite = snapshot.getValue(Favourite::class.java)
recyclerAdapter = FavouriteRecyclerAdapter(context!! , favouritesList)
recyclerFavourite?.adapter = recyclerAdapter
if (favorite != null) {
favouritesList.add(favorite)
}
}
}
})
}
}
Model Class:
package com.reazon.foodrunner.model
data class Favourite (
var id:Int? = null,
var name:String? = null,
var rating:Double? = null,
var cost_for_one:Int? = null,
var image_url:String? = null
)
LogCat Window Error identification:
2020-09-05 09:22:07.520 5208-5208/com.reazon.foodrunner E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.reazon.foodrunner, PID: 5208
com.google.firebase.database.DatabaseException: Can't convert object of type java.lang.String to type com.reazon.foodrunner.model.Favourite
at com.google.firebase.database.core.utilities.encoding.CustomClassMapper.convertBean(CustomClassMapper.java:435)
at com.google.firebase.database.core.utilities.encoding.CustomClassMapper.deserializeToClass(CustomClassMapper.java:231)
at com.google.firebase.database.core.utilities.encoding.CustomClassMapper.convertToCustomClass(CustomClassMapper.java:79)
at com.google.firebase.database.DataSnapshot.getValue(DataSnapshot.java:203)
at com.reazon.foodrunner.fragment.FavouriteFragment$retrieveAllFavouriteRestaurants$1.onDataChange(FavouriteFragment.kt:50)
at com.google.firebase.database.core.ValueEventRegistration.fireEvent(ValueEventRegistration.java:75)
at com.google.firebase.database.core.view.DataEvent.fire(DataEvent.java:63)
at com.google.firebase.database.core.view.EventRaiser$1.run(EventRaiser.java:55)
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)
Since you have the following db:
Favorites
Uid
id : id
name : name
Therefore you have to use the following code:
override fun onDataChange(p0: DataSnapshot) {
val favorite = p0.getValue(Favourite::class.java)
Remove the for loop because when you iterate you will get the data as String instead of your custom object.
I am making an app where each user can add to his Todo List, I have a problem with folder paths.
this is the part of reading data code was adding "child(auth.currentUser?.uid!!)" makes everything crash. without it though it works but shows information of all users with dictionary form.
db.child(auth.currentUser?.uid!!).addValueEventListener(object : ValueEventListener {
override fun onCancelled(p0: DatabaseError) {
println("The read failed")
}
override fun onDataChange(p0: DataSnapshot) {
for (i in p0.children) {
val notToDo: String = i.value.toString()
notToDos.add(notToDo)
}
listView = findViewById(R.id.listview)
listView.adapter = ArrayAdapter<String>(
this#ToDoActivity,
R.layout.listview,
notToDos
)
}
})
This is the whole code, but neither the adding part works
package ge.msda.firebaseauth
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.ArrayAdapter
import android.widget.ListView
import android.widget.Toast
import com.google.firebase.auth.FirebaseAuth
import com.google.firebase.database.*
import kotlinx.android.synthetic.main.activity_to_do.*
class ToDoActivity : AppCompatActivity() {
private lateinit var db: DatabaseReference
lateinit var listView: ListView
private lateinit var auth: FirebaseAuth
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_to_do)
db = FirebaseDatabase.getInstance().getReference("UserInfo")
val notToDos = arrayListOf<String>()
TodoSubmit.setOnClickListener {
val text = TodoText.text.toString()
db.child(auth.currentUser?.uid!!).child("ToDos").push().setValue(text).addOnCompleteListener {
if(it.isSuccessful()){
Toast.makeText(this, "Success", Toast.LENGTH_LONG).show()
}
else {
Toast.makeText(this, it.exception.toString(), Toast.LENGTH_LONG).show() }
}
TodoText.setText("")
notToDos.clear()
}
db.child(auth.currentUser?.uid!!).addValueEventListener(object : ValueEventListener {
override fun onCancelled(p0: DatabaseError) {
println("The read failed")
}
override fun onDataChange(p0: DataSnapshot) {
for (i in p0.children) {
val notToDo: String = i.value.toString()
notToDos.add(notToDo)
}
listView = findViewById(R.id.listview)
listView.adapter = ArrayAdapter<String>(
this#ToDoActivity,
R.layout.listview,
notToDos
)
}
})
}
}
error tracktrace
E/AndroidRuntime: FATAL EXCEPTION: main
Process: ge.msda.firebaseauth, PID: 11939
java.lang.RuntimeException: Unable to start activity ComponentInfo{ge.msda.firebaseauth/ge.msda.firebaseauth.ToDoActivity}: kotlin.UninitializedPropertyAccessException: lateinit property auth has not been initialized
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: kotlin.UninitializedPropertyAccessException: lateinit property auth has not been initialized
at ge.msda.firebaseauth.ToDoActivity.onCreate(ToDoActivity.kt:41)
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)
This is the way the database looks like and I want to add a new folder in each user named "ToDos" where I can add other items.
You are getting that error because you forgot to initialize your auth object. To solve this, simply add the following line of code:
auth = FirebaseAuth.getInstance()
Right after the following line of code:
db = FirebaseDatabase.getInstance().getReference("UserInfo")