Problem setting up view model adapter during inflate XML - android

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.

Related

Kotlin App: IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first

I was developing an App in kotlin, which let the users publish and contract differents services from the App.
So, in the fragment where I manage the publication of a new services, I get the following error when I try to raise a custom AlertDiolog to ask for the details of the service.
IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first.
The code of my fragment is the next:
package com.example.appadoskotlin2.ui.publish
import android.annotation.SuppressLint
import android.content.ContentValues
import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.fragment.app.DialogFragment
import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModelProvider
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.example.appadoskotlin2.R
import com.example.appadoskotlin2.data.Service
import com.example.appadoskotlin2.databinding.FragmentPublishBinding
import com.example.appadoskotlin2.ui.adapters.AdapterPublish
import com.example.appadoskotlin2.ui.diologs.PublishDiolog
import com.example.appadoskotlin2.ui.utils.SimpleDividerItemDecoration
import com.google.firebase.database.*
class PublishFragment : Fragment(), (Service) -> Unit, PublishDiolog.ConfirmationDialogListener {
private lateinit var publishViewModel: PublishViewModel
private var _binding: FragmentPublishBinding? = null
private lateinit var rvPublish: RecyclerView
private lateinit var adapter: AdapterPublish
//TODO("Inicialmente proporcionamos los servicios de manera local.
// En el futuro hacerlo a traves de una API.")
private lateinit var user_description: String
private lateinit var linearLayoutManager: LinearLayoutManager
// This property is only valid between onCreateView and
// onDestroyView.
//private val binding get() = _binding!!
private var services = ArrayList<Service>()
private lateinit var database: DatabaseReference
override fun onViewStateRestored(savedInstanceState: Bundle?) {
super.onViewStateRestored(savedInstanceState)
user_description = savedInstanceState?.getString("user_des").toString()
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?,
): View? {
publishViewModel =
ViewModelProvider(this).get(PublishViewModel::class.java)
_binding = FragmentPublishBinding.inflate(inflater, container, false)
val root: View = _binding!!.root
//TODO("Cargar array services con servicios de BBDD.")
val postListener = object : ValueEventListener {
override fun onDataChange(dataSnapshot: DataSnapshot) {
// Get Post object and use the values to update the UI
if(dataSnapshot != null){
this#PublishFragment.services = ArrayList()
services = dataSnapshot.getValue() as ArrayList<Service>
}else{
Toast.makeText(context, "No hay ningun servicio disponible", Toast.LENGTH_LONG).show()
}
}
override fun onCancelled(databaseError: DatabaseError) {
// Getting Post failed, log a message
Toast.makeText(context, "Operación cancelada", Toast.LENGTH_LONG).show()
Log.w(ContentValues.TAG, "loadPost:onCancelled", databaseError.toException())
}
}
database = FirebaseDatabase.getInstance().reference
database.addValueEventListener(postListener)
services.add(Service("Ofertar", "Carpinteria"))
services.add(Service("Ofertar", "Fontaneria"))
services.add(Service("Ofertar", "Electricidad"))
services.add(Service("Ofertar", "Otros"))
rvPublish = root.findViewById(R.id.rvPublish)
rvPublish.addItemDecoration(SimpleDividerItemDecoration(this.context, R.drawable.line_divider))
linearLayoutManager = LinearLayoutManager(this.context)
rvPublish.layoutManager = linearLayoutManager
adapter = AdapterPublish(this, services)
rvPublish.adapter = adapter
return root
}
override fun invoke(s: Service) {
//TODO("Mostrar Alert Diolog pidiendiendo los detalles del servicio: descripción y precio")
//TODO("Si es "Otros" permitir al usuario que introduzca la descripcion")
//val parent = view?.parent as ViewGroup
//parent.removeAllViewsInLayout()
//parent.removeAllViews()
val parent = this.parentFragment?.requireView() as ViewGroup
parent.removeAllViews()
showdialog(s)
}
fun showdialog(s:Service){
fragmentManager?.let {
val confirmationDialogFragment = PublishDiolog
.newInstance(
"Confirmar: " + s.type,
"Introduzca la descripción y precio."
)
//TODO("java.lang.IllegalStateException: The specified child already has a parent.
// You must call removeView() on the child's parent first.")
if(confirmationDialogFragment.parentFragment != null){
(confirmationDialogFragment.parentFragment as ViewGroup).removeAllViews()
}
confirmationDialogFragment.setTargetFragment(this, 0)
// confirmationDialogFragment.
confirmationDialogFragment.show(it, "Confirm")
}
}
override fun onDialogPositiveClick(dialog: DialogFragment) {
//TODO("add to remomte DDBB la publicación del servicio.")
//TODO("Rescatar los servicios publicados para usarlos en el ContractFragment")
Toast.makeText(context, "Servicio publicado correctamente", Toast.LENGTH_LONG).show()
}
override fun onDialogNegativeClick(dialog: DialogFragment) {
Toast.makeText(context, "Operación cancelada", Toast.LENGTH_SHORT).show()
dialog.dismiss()
}
#SuppressLint("UseRequireInsteadOfGet")
override fun onDestroyView() {
super.onDestroyView()
_binding = null
if (view != null) {
val parent = view!!.parent as ViewGroup
parent.removeAllViews()
}
}
}
And the custom diolog I try to raise is the following:
package com.example.appadoskotlin2.ui.diologs
import android.annotation.SuppressLint
import android.app.Dialog
import android.content.DialogInterface
import android.os.Bundle
import android.text.InputType
import android.view.View
import android.widget.EditText
import androidx.appcompat.app.AlertDialog
import androidx.fragment.app.DialogFragment
import com.example.appadoskotlin2.R
import com.example.appadoskotlin2.R.id.dialog_publish
import com.example.appadoskotlin2.ui.publish.PublishFragment
import com.google.android.material.button.MaterialButton
import com.google.android.material.textfield.TextInputEditText
private const val TITLE = "Confirmar"
private const val DESCRIPTION = "description_param"
private const val PRICE = "20"
class PublishDiolog: DialogFragment() {
internal lateinit var listener: ConfirmationDialogListener
private var title: String? = null
private var description: String? = null
private var price: String? = null
private lateinit var input: TextInputEditText
private lateinit var input_price: TextInputEditText
private lateinit var btn_publish: MaterialButton
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
try {
listener = targetFragment as ConfirmationDialogListener
} catch (e: ClassCastException) {
throw ClassCastException((targetFragment.toString() + " must implement ConfirmationDialogListener"))
}
arguments?.let {
title = it.getString(TITLE)
description = it.getString(DESCRIPTION)
price = it.getString(PRICE)
}
}
//TODO("Crear custom Diolog para solicitar descripción y precio del servicio.")
#SuppressLint("ResourceType")
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
return activity?.let {
val builder = AlertDialog.Builder(it)
title?.let { title -> builder.setTitle(title) }
val inflater = requireActivity().layoutInflater
val view: View = inflater.inflate(R.layout.dialog_publish, null, false)
builder.setView(view)
initView(view)
input.setHint("Descripción")
input.inputType = InputType.TYPE_CLASS_TEXT
input_price.setHint("€")
input_price.inputType = InputType.TYPE_CLASS_NUMBER
builder
.setMessage(description)
.setPositiveButton("Yes",
DialogInterface.OnClickListener { _, _ ->
var d_Text = input.text.toString()
savedInstanceState?.putString("user_des", d_Text)
listener.onDialogPositiveClick(this)
})
.setNegativeButton("No",
DialogInterface.OnClickListener { _, _ ->
listener.onDialogNegativeClick(this)
})
.setView(input)
builder.create()
} ?: throw IllegalStateException("Activity cannot be null")
}
private fun initView(view: View) {
input = view.findViewById(R.id.description_input_text)
input_price = view.findViewById(R.id.price_input_edit)
btn_publish = view.findViewById(R.id.btn_publish)
}
interface ConfirmationDialogListener {
fun onDialogPositiveClick(dialog: DialogFragment)
fun onDialogNegativeClick(dialog: DialogFragment)
}
companion object {
#JvmStatic
fun newInstance(title: String?, description: String) =
PublishDiolog().apply {
arguments = Bundle().apply {
putString(TITLE, title)
putString(DESCRIPTION, description)
putString(PRICE, price)
}
}
}
}
As you see I try to called the removeAllVIews() method into parent fragment but doen't work anyway.
The main point is I tryy to remove the child's parent, on differents ways an anyone works..
If you know differents options why the error comes, take thanks in advance !
[EDIT]
Added the completed logcat message of the error:
java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first.
at android.view.ViewGroup.addViewInner(ViewGroup.java:5038)
at android.view.ViewGroup.addView(ViewGroup.java:4869)
at android.view.ViewGroup.addView(ViewGroup.java:4841)
at androidx.appcompat.app.AlertController.setupCustomContent(AlertController.java:657)
at androidx.appcompat.app.AlertController.setupView(AlertController.java:475)
at androidx.appcompat.app.AlertController.installContent(AlertController.java:233)
at androidx.appcompat.app.AlertDialog.onCreate(AlertDialog.java:279)
at android.app.Dialog.dispatchOnCreate(Dialog.java:407)
at android.app.Dialog.show(Dialog.java:302)
at androidx.fragment.app.DialogFragment.onStart(DialogFragment.java:687)
at androidx.fragment.app.Fragment.performStart(Fragment.java:3021)
at androidx.fragment.app.FragmentStateManager.start(FragmentStateManager.java:589)
at androidx.fragment.app.FragmentStateManager.moveToExpectedState(FragmentStateManager.java:300)
at androidx.fragment.app.FragmentManager.executeOpsTogether(FragmentManager.java:2189)
at androidx.fragment.app.FragmentManager.removeRedundantOperationsAndExecute(FragmentManager.java:2100)
at androidx.fragment.app.FragmentManager.execPendingActions(FragmentManager.java:2002)
at androidx.fragment.app.FragmentManager$5.run(FragmentManager.java:524)
at android.os.Handler.handleCallback(Handler.java:873)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:201)
at android.app.ActivityThread.main(ActivityThread.java:6861)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:547)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:873)
I see that in your dialog you have two calls to builder.setView, that seems unusual. Which one do you actually want to be the view?
In the second call you pass input which is a subview of view. So that view already has a parent, and throws the exception. If you want input to be the view to display, instantiate it separate from the binding and pass it.

ArrayList is throwing IndexOutOfBoundsException despite it being initialized in function and being populated using add function

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)

kotlin.UninitializedPropertyAccessException - lateinit property mAdapter has not been initialized - Android Development

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)
}

Kotlin - How can I use a recyclerView in a fragment? [closed]

Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 2 years ago.
Improve this question
I started using fragments and I'm still trying to learn how to use them properly. On the project I'm doing I want to use a recyclerView that shows a list of items that are stored in a database. I'm having some trouble doing it though as my recyclerView doesn't show any of the items.
The fragment where I want to show the recyclerView is like this:
package com.example.is4gestaointegrada.fragments
import android.content.Context
import android.net.Uri
import android.os.Bundle
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.example.is4gestaointegrada.Adapter.ArtigoAdapter
import com.example.is4gestaointegrada.DBHandlers.DBHandler
import com.example.is4gestaointegrada.MainActivity.Companion.dbHandler
import com.example.is4gestaointegrada.R
import kotlinx.android.synthetic.main.fragment_ver_artigos.view.*
private const val ARG_PARAM1 = "param1"
private const val ARG_PARAM2 = "param2"
class VerArtigos : Fragment() {
private var param1: String? = null
private var param2: String? = null
private var listener: OnFragmentInteractionListener? = null
override fun onAttach(context: Context) {
super.onAttach(context)
if (context is OnFragmentInteractionListener) {
listener = context
} else {
throw RuntimeException(context.toString() + " must implement OnFragmentInteractionListener")
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
arguments?.let {
param1 = it.getString(ARG_PARAM1)
param2 = it.getString(ARG_PARAM2)
}
dbHandler = DBHandler(context!!, null, null, 1)
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val view : View = inflater.inflate(R.layout.fragment_ver_artigos, container, false)
viewArtigos(view)
return view
}
override fun onDetach() {
super.onDetach()
listener = null
}
interface OnFragmentInteractionListener {
// TODO: Update argument type and name
fun onFragmentInteraction(uri: Uri)
}
private fun viewArtigos(view : View){
val artigosList = dbHandler.getArtigos(context!!)
val adapter = ArtigoAdapter(context!!, artigosList)
val rv : RecyclerView = view.rv_artigos
rv.layoutManager = LinearLayoutManager(context, RecyclerView.VERTICAL, false)
rv.adapter = adapter
}
companion object {
// TODO: Rename and change types and number of parameters
#JvmStatic
fun newInstance(param1: String, param2: String) =
VerArtigos().apply {
arguments = Bundle().apply {
putString(ARG_PARAM1, param1)
putString(ARG_PARAM2, param2)
}
}
}
}
The Handler's function code is this:
fun getArtigos(mCtx : Context) : ArrayList<Artigo>{
val qry = "SELECT * FROM $DB_ARTIGO_TABLE"
val db = this.readableDatabase
val cursor = db.rawQuery(qry, null)
val artigos = ArrayList<Artigo>()
if (cursor.count == 0){
Toast.makeText(mCtx, "Não foram encontrados artigos", Toast.LENGTH_LONG).show()
} else {
while (cursor.moveToNext()){
val artigo = Artigo()
artigo.artigoNome = cursor.getString(cursor.getColumnIndex(DB_ARTIGO_NOME))
artigo.artigoAbreviada = cursor.getString(cursor.getColumnIndex(DB_ARTIGO_ABREVIADA))
artigo.artigoExtensa = cursor.getString(cursor.getColumnIndex(DB_ARTIGO_EXTENSA))
artigo.artigoFamiliaCodigo = cursor.getInt(cursor.getColumnIndex(DB_ARTIGO_FAMILIACODIGO))
artigo.artigoFamiliaDescricao = cursor.getString(cursor.getColumnIndex(DB_ARTIGO_FAMILIADESCRICAO))
artigo.artigoCodigoIVA = cursor.getInt(cursor.getColumnIndex(DB_ARTIGO_CODIGOIVA))
artigo.artigoPreco = cursor.getDouble(cursor.getColumnIndex(DB_ARTIGO_PRECO))
}
}
cursor.close()
db.close()
return artigos
}
The Adapter is like this:
package com.example.is4gestaointegrada.Adapter
import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.example.is4gestaointegrada.DBModels.Artigo
import com.example.is4gestaointegrada.R
import kotlinx.android.synthetic.main.lo_artigos.view.*
class ArtigoAdapter (mCtx : Context, val artigos : ArrayList<Artigo>) : RecyclerView.Adapter<ArtigoAdapter.ViewHolder>(){
val mCtx = mCtx
class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView){
val txtArtigoNome = itemView.txt_NomeArtigo
val txtArtigoDesc = itemView.txt_ArtigoDesc
val txtArtigoPreco = itemView.txt_ArtigoPreco
}
override fun onCreateViewHolder(p0: ViewGroup, p1: Int): ArtigoAdapter.ViewHolder {
val v = LayoutInflater.from(p0.context).inflate(R.layout.lo_artigos, p0, false)
return ViewHolder(v)
}
override fun getItemCount(): Int {
return artigos.size
}
override fun onBindViewHolder(p0: ArtigoAdapter.ViewHolder, p1: Int) {
val artigo : Artigo = artigos[p1]
p0.txtArtigoNome.text = artigo.artigoNome
p0.txtArtigoDesc.text = artigo.artigoAbreviada
p0.txtArtigoDesc.text = artigo.artigoPreco.toString()
}
}
Your getArtigos function never adds anything to artigos, so you always return an empty ArrayList.
You need to add it to the list in your while (cursor.moveToNext()){ loop.

SQLite - Datebase colums

Can you help solve the problem with the missing column? It seems to me that I did everything right, but I get the error that something is wrong with one column.
ERROR
E/SQLiteLog: (1) no such column: Stezenie D/AndroidRuntime: Shutting down VM E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.apkadlapacjenta, PID: 11261
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.apkadlapacjenta/com.example.apkadlapacjenta.HistoriaPomiarow}:
android.database.sqlite.SQLiteException: no such column: Stezenie
(code 1 SQLITE_ERROR): , while compiling: SELECT Id, Stezenie, Zegar,
Data, Posilek, Stres, Samopoczucie, Hiperglikemia FROM Pomiary
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.database.sqlite.SQLiteException: no such column: Stezenie (code 1 SQLITE_ERROR): , while compiling: SELECT Id,
Stezenie, Zegar, Data, Posilek, Stres, Samopoczucie, Hiperglikemia
FROM Pomiary
at android.database.sqlite.SQLiteConnection.nativePrepareStatement(Native
Method)
at android.database.sqlite.SQLiteConnection.acquirePreparedStatement(SQLiteConnection.java:986)
at android.database.sqlite.SQLiteConnection.prepare(SQLiteConnection.java:593)
at android.database.sqlite.SQLiteSession.prepare(SQLiteSession.java:590)
at android.database.sqlite.SQLiteProgram.(SQLiteProgram.java:61)
at android.database.sqlite.SQLiteQuery.(SQLiteQuery.java:37)
at android.database.sqlite.SQLiteDirectCursorDriver.query(SQLiteDirectCursorDriver.java:46)
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.example.apkadlapacjenta.DbMenager.Query(DbMenager.kt:65)
at com.example.apkadlapacjenta.HistoriaPomiarow.LoadQuery(HistoriaPomiarow.kt:55)
at com.example.apkadlapacjenta.HistoriaPomiarow.onCreate(HistoriaPomiarow.kt:33)
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) 
I/Process: Sending signal. PID: 11261 SIG: 9 Disconnected from the
target VM, address: 'localhost:8630', transport: 'socket'
MAIN ACTIVITY
package com.example.apkadlapacjenta
import android.annotation.SuppressLint
import android.app.AlertDialog
import android.app.SearchManager
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.view.Menu
import android.view.MenuItem
import android.view.View
import android.view.ViewGroup
import android.widget.BaseAdapter
import android.widget.SearchView
import androidx.appcompat.app.AppCompatActivity
import kotlinx.android.synthetic.main.activity_historia_pomiarow.*
import kotlinx.android.synthetic.main.content_historia_pomiarow.*
import kotlinx.android.synthetic.main.row.view.deleteBtn
import kotlinx.android.synthetic.main.row1.view.*
#Suppress("DEPRECATION")
class HistoriaPomiarow : AppCompatActivity() {
var listaWynikow = ArrayList<FIrebaseVal>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_historia_pomiarow)
setSupportActionBar(toolbar)
//Wczytujemy baze danych
LoadQuery("%")
}
override fun onResume() {
super.onResume()
LoadQuery("%")
}
private fun LoadQuery(pomiary: String) {
val dbManager = DbMenager(this)
val projections = arrayOf(
"Id",
"Stezenie",
"Zegar",
"Data",
"Posilek",
"Stres",
"Samopoczucie",
"Hiperglikemia"
)
val selectionArgs = arrayOf(pomiary)
val cursor =
dbManager.Query(projections,null,null,null)
listaWynikow.clear()
if (cursor.moveToFirst()) {
do {
val ID = cursor.getInt(cursor.getColumnIndex("Id"))
val Stezenie = cursor.getString(cursor.getColumnIndex("Stezenie"))
val Zegar = cursor.getString(cursor.getColumnIndex("Zegar"))
val Data = cursor.getString(cursor.getColumnIndex("Data"))
val Posilek = cursor.getString(cursor.getColumnIndex("Posilek"))
val Stres = cursor.getString(cursor.getColumnIndex("Stres"))
val Samopoczucie = cursor.getString(cursor.getColumnIndex("Samopoczucie"))
val Hiperglikemia = cursor.getString(cursor.getColumnIndex("Hiperglikemia"))
listaWynikow.add(
FIrebaseVal(
ID,
Stezenie,
Zegar,
Data,
Posilek,
Stres,
Samopoczucie,
Hiperglikemia ))
} while (cursor.moveToNext())
}
//Adapter
val ListaWynikowAdapter = MylistApdater(this, listaWynikow)
//ustawienia adaptera
listapomiarow.adapter = ListaWynikowAdapter
// Wszystkie zadania
val total = listapomiarow.count
//actionbar
val mActionBar = supportActionBar
if(mActionBar !=null){
//ustawienia Action Bara
mActionBar.subtitle = "Masz $total wyników"
}
}
override fun onCreateOptionsMenu(menu: Menu?):Boolean {
menuInflater.inflate(R.menu.notemenu, menu)
//searchView
val sv: SearchView = menu!!.findItem(R.id.app_bar_search).actionView as SearchView
val sm = getSystemService(Context.SEARCH_SERVICE) as SearchManager
sv.setSearchableInfo(sm.getSearchableInfo(componentName))
sv.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
//implementujemy dwie metody
override fun onQueryTextSubmit(query: String?): Boolean {
LoadQuery("%$query%")
return false
}
override fun onQueryTextChange(newText: String?): Boolean {
LoadQuery("%$newText%")
return false
}
})
return super.onCreateOptionsMenu(menu)
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
when(item.itemId){
R.id.dodaj_notatke->{
startActivity(Intent(this,AddNote::class.java))
}
R.id.sortuj->{
showSortDialog()
}
}
return super.onOptionsItemSelected(item)
}
private fun showSortDialog() {
//lista opcji
val sortOption = arrayListOf("Najnowsze","starsze","Tytul rosnaco","Tytul malejaco")
val mBuilder = AlertDialog.Builder(this)
mBuilder.setTitle("Sort by")
mBuilder.setIcon(R.drawable.ic_sort)
}
inner class MylistApdater(
context: Context,
private var ListaWynikowAdapter: ArrayList<FIrebaseVal>
) : BaseAdapter() {
var listWynikiArray = ArrayList<FIrebaseVal>()
var context: Context? = context
#SuppressLint("ViewHolder","InflateParams")
override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View {
val myView = layoutInflater.inflate(R.layout.row1, null)
val Wynik = ListaWynikowAdapter[position]
myView.stezenienumberpicker.text = Wynik.nodeNumberPicker.toString()
myView.godzina.text = Wynik.nodezegar
myView.data.text = Wynik.nodedata
myView.posilekRG.text = Wynik.nodeposilek
myView.SP1.text = Wynik.nodehiperglikemia
myView.SP2.text = Wynik.nodestres
myView.SP3.text = Wynik.nodesamopoczucie
//Przycisk kasowania
myView.deleteBtn.setOnClickListener {
val dbMenager = DbMenager(this.context!!)
val selectionArgs = arrayOf(Wynik.nodeID.toString())
dbMenager.delete("ID=?", selectionArgs)
LoadQuery("%")
}
return myView
}
override fun getItem(position: Int): Any {
return ListaWynikowAdapter[position]
}
override fun getItemId(position: Int): Long {
return position.toLong()
}
override fun getCount(): Int {
return ListaWynikowAdapter.size
}
}
private fun GoToUpdateFun(Wyniki: FIrebaseVal) {
val intent = Intent(this,AddPomiary::class.java)
intent.putExtra("Id",Wyniki.nodeID)//wpisz Id
intent.putExtra("Stezenie",Wyniki.nodeNumberPicker)
intent.putExtra("Zegar",Wyniki.nodezegar)
intent.putExtra("Data",Wyniki.nodedata)
intent.putExtra("Posilek",Wyniki.nodeposilek)
intent.putExtra("Hiperglikemia",Wyniki.nodehiperglikemia)
intent.putExtra("Stres",Wyniki.nodestres)
intent.putExtra("Samopoczucie",Wyniki.nodesamopoczucie)
startActivity(intent)
}
}
DBMENAGER
package com.example.apkadlapacjenta
import android.content.ContentValues
import android.content.Context
import android.database.Cursor
import android.database.sqlite.SQLiteDatabase
import android.database.sqlite.SQLiteOpenHelper
import android.database.sqlite.SQLiteQueryBuilder
import android.widget.RadioGroup
import android.widget.Toast
class DatebaseMenagerPomiary(context: Context) {
//Database name
var dbName = "Historia Pomiarów"
//table name
var dbTable = "Wyniki"
//kolumny
var colID = "Id"
var colStezenie = "Stezenie"
var colZegar = "Zegar"
var colData = "Data"
var colPosilek = "Posilek"
var colStres = "Stres"
var colSamopoczucie = "Samopoczucie"
var colHiperglikemia = "Hiperglikemia"
//wersja
var dbVersion = 1
//Tworzymy tabele
val sqlCreateTable =
"CREATE TABLE$dbTable($colID INTEGER PRIMARY KEY, $colStezenie TEXT, $colZegar TEXT, $colData TEXT, $colPosilek TEXT, $colStres TEXT,$colSamopoczucie TEXT, $colHiperglikemia TEXT)"
var sqlDB: SQLiteDatabase? = null
init {
val db = DatabaseHelperWyniki(context)
sqlDB = db.writableDatabase
}
inner class DatabaseHelperWyniki : SQLiteOpenHelper {
var context: Context? = null
constructor(context: Context) : super(context, dbName, null, dbVersion) {
this.context = context
}
override fun onCreate(db: SQLiteDatabase?) {
db!!.execSQL(sqlCreateTable)
Toast.makeText(this.context,"baza danych utworzona...",Toast.LENGTH_SHORT).show()
}
override fun onUpgrade(db: SQLiteDatabase?, oldVersion: Int, newVersion: Int) {
db!!.execSQL("zamknij tabele jeśli nie istnieje" + dbTable)
}
}
fun insert(values:ContentValues):Long{
val ID = sqlDB!!.insert(dbTable,"",values)
return ID
}
fun Query(projection:Array<String>,selection:String,selectionArgs:Array<String>,sorOrder:String): Cursor {
val qb = SQLiteQueryBuilder()
qb.tables=dbTable
val cursor = qb.query(sqlDB,projection,selection,selectionArgs,null,null,sorOrder)
return cursor
}
fun delete(selection: String,selectionArgs: Array<String>):Int{
val count = sqlDB!!.delete(dbTable,selection,selectionArgs)
return count
}
fun update(values:ContentValues,selection: String,selectionArgs: Array<String>): Int {
val count = sqlDB!!.update(dbTable,values,selection,selectionArgs)
return count
}
}
NODE CLASS dont see on name :D
package com.example.apkadlapacjenta
class FIrebaseVal(
nodeID: Int, nodeNumberPicker:String,
nodezegar:String,
nodedata:String,
nodeposilek: String,
nodehiperglikemia: String,
nodestres: String,
nodesamopoczucie: String
) {
var nodeID: Int?= nodeID
var nodeNumberPicker: String? = nodeNumberPicker
var nodezegar:String?=nodezegar
var nodedata:String?=nodedata
var nodeposilek: String? =nodeposilek
var nodehiperglikemia:String?=nodehiperglikemia
var nodestres:String?=nodestres
var nodesamopoczucie:String?=nodesamopoczucie
}
Mates can you explain me what is wrong ? Thx
Probably you add this column but forget to add migration from old database version. You can check it by clear all application data (or delete and install it). If reinstall fix the problem you should create migration from old database verstion to new
Also you can refactor all your database to use Room instead of ugly ORMLite.
It's friendly and powerfull persistance library from google
I believe that your issue may be due to the line :-
val sqlCreateTable =
"CREATE TABLE$dbTable($colID INTEGER PRIMARY KEY, $colStezenie TEXT, $colZegar TEXT, $colData TEXT, $colPosilek TEXT, $colStres TEXT,$colSamopoczucie TEXT, $colHiperglikemia TEXT)"
There is no space between the TABLE keyword and the table name.
Try changing to :-
val sqlCreateTable =
"CREATE TABLE $dbTable($colID INTEGER PRIMARY KEY, $colStezenie TEXT, $colZegar TEXT, $colData TEXT, $colPosilek TEXT, $colStres TEXT,$colSamopoczucie TEXT, $colHiperglikemia TEXT)"
And then after uninstalling the App or deleting the App's data try rerunning.

Categories

Resources