I followed a tutorial on how to do a listview in kotlin and I encountered this problem. I'm new to Kotlin and I don't understand what are the getters and setters for my activity. From what I read it should be put automatically.
private lateinit var listView ListView
Property getter or setter expected
All code:
package com.example.librariasemnelor;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button
import android.widget.ListView;
private lateinit var listView ListView
class SecondActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_second)
val actionBar = supportActionBar
if(actionBar != null){
actionBar.title = "Meniu principal"
actionBar.setDisplayHomeAsUpEnabled(true)
}
listView = findViewById<ListView>(R.id.recipe_list_view)
// 1
val recipeList = Recipe.getRecipesFromFile("recipes.json", this)
// 2
val listItems = arrayOfNulls<String>(recipeList.size)
// 3
for (i in 0 until recipeList.size) {
val recipe = recipeList[i]
listItems[i] = recipe.title
}
// 4
val adapter = ArrayAdapter(this, android.R.layout.simple_list_item_1, listItems)
listView.adapter = adapter
}
}
private lateinit ... should be placed inside the class block.
And : must be added just after listView.
class SecondActivity : AppCompatActivity() {
private lateinit var listView: ListView
override fun onCreate(savedInstanceState: Bundle?) {
...
}
...
}
Related
Trying to add an onclicklistener to the items in my recycler view, that will use an intent to open another activity. I've tried finding examples, but I can only find examples using Java or Kotlin examples that aren't using viewbinding.
package com.truuce.anotherrvtest
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import androidx.recyclerview.widget.GridLayoutManager
import com.truuce.anotherrvtest.databinding.ActivityHeroBinding
class HeroActivity : AppCompatActivity() {
var binding: ActivityHeroBinding? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityHeroBinding.inflate(layoutInflater)
setContentView(binding?.root)
val adapter = CardAdapter(HeroList.heroList)
binding?.heroRV?.adapter = adapter
binding?.heroRV?.layoutManager = GridLayoutManager(applicationContext, 3)
}
override fun onDestroy() {
super.onDestroy()
binding = null
}
}
package com.truuce.anotherrvtest
import android.content.Context
import android.content.Intent
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import com.truuce.anotherrvtest.databinding.HeroCardBinding
class CardAdapter(val heroList: List<Hero>) : RecyclerView.Adapter<CardAdapter.MainViewHolder>() {
inner class MainViewHolder(val heroBinding: HeroCardBinding) :
RecyclerView.ViewHolder(heroBinding.root) {
fun bindHero(hero: Hero){
heroBinding.heroNameTV.text = hero.heroName
heroBinding.heroIV.setImageResource(hero.image)
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MainViewHolder {
return MainViewHolder(HeroCardBinding.inflate(LayoutInflater.from(parent.context), parent, false))
}
override fun onBindViewHolder(holder: MainViewHolder, position: Int) {
val hero = heroList[position]
holder.bindHero(hero)
}
override fun getItemCount() = heroList.size
}
tried adding View.OnClickListener to MainViewHolder, then implemented a member. OnClick(p0: View){}, but no idea how to get it working.
You should add a functional property for a click listener in your adapter.
The Activity can set the item click listener behavior.
class CardAdapter(
val heroList: List<Hero>,
val itemClickListener: (Hero)->Unit
) : RecyclerView.Adapter<CardAdapter.MainViewHolder>() {
inner class MainViewHolder(val heroBinding: HeroCardBinding) :
RecyclerView.ViewHolder(heroBinding.root) {
fun bindHero(hero: Hero) = with(heroBinding) {
heroNameTV.text = hero.heroName
heroIV.setImageResource(hero.image)
root.setOnClickListener { itemClickListener(hero) }
}
}
//...
}
// In Activity:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityHeroBinding.inflate(layoutInflater)
setContentView(binding?.root)
val adapter = CardAdapter(HeroList.heroList) { hero ->
// do something with hero item when it's clicked
}
binding?.heroRV?.adapter = adapter
binding?.heroRV?.layoutManager = GridLayoutManager(applicationContext, 3)
}
Im trying to proceed on the next activty from Kotlin to Java it gives me a red line in ".java"
in
val intent = Intent(this, MainActivity::class.java)
startActivity(intent)
This is my whole code:
package com.heyletscode.artutorial
import android.content.Intent
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.View
import android.widget.Button
class Garlic : AppCompatActivity() {
lateinit var button : Button
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_garlic)
button = findViewById(R.id.Button)
button.setOnClickListener(listener)
}
val listener= View.OnClickListener { view ->
when (view.getId()) {
R.id.Button -> {
val intent = Intent(this, MainActivity::class.java)
startActivity(intent)
}
}
}
}
Ive tried different methods to proceed to next activty but give me red line in .java
I'd suggest moving your listener set-up to your onCreate like this
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_garlic)
button = findViewById(R.id.Button)
button.setOnClickListener { ->
val intent = Intent(this#Garlic, MainActivity::class.java)
startActivity(intent)
}
}
and the this is referencing to your onClickListener, append it with # followed by your activity name
val intent = Intent(this#Garlic, MainActivity::class.java)
may be you provide wrong context to Intent try below code
package com.heyletscode.artutorial
import android.content.Intent
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.View
import android.widget.Button
class Garlic : AppCompatActivity() {
lateinit var button : Button
private lateinit var context: Context //create object of context
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_garlic)
context= this#MainActivity // init context here
button = findViewById(R.id.Button)
button.setOnClickListener(listener)
}
val listener= View.OnClickListener { view ->
when (view.getId()) {
R.id.Button -> {
val intent = Intent(context, MainActivity::class.java) //replace this with context
startActivity(intent)
}
}
}
}
I have an adapter for my RecyclerView where I program that when I click on the element (of my RecyclerView) it executes an Intent with a putExtra to take me to another activity, the variable that contains my putExtra comes from the element that I clicked, but now I need to add a More variable that comes from the activity. The issue is that I don't know how to send it from the adapter.
this is my adapter.
package com.example.atipicoapp
import android.app.Activity
import android.content.Intent
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.AdapterView
import android.widget.LinearLayout
import android.widget.TextView
import android.widget.Toast
import androidx.appcompat.view.menu.ActionMenuItemView
import androidx.core.content.ContextCompat.startActivity
import androidx.recyclerview.widget.RecyclerView
import kotlinx.android.synthetic.main.activity_main.*
import kotlinx.android.synthetic.main.list_item.view.*
class MyAdapter(private val platoList : ArrayList<Plato>
) : RecyclerView.Adapter<MyAdapter.MyViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyAdapter.MyViewHolder {
val itemView =
LayoutInflater.from(parent.context).inflate(R.layout.list_item, parent, false)
itemView.platoTouch.setOnClickListener(View.OnClickListener { v: View ->
})
return MyViewHolder(itemView)
}
override fun onBindViewHolder(holder: MyAdapter.MyViewHolder, position: Int) {
val plato: Plato = platoList[position]
holder.platoName.text = plato.platoName
holder.platoDescription.text = plato.platoDescription
holder.platoPrecio.text = plato.platoPrecio.toString()
holder.platoCantidad.text = plato.platoCantidad.toString()
when(holder){
is MyViewHolder -> {
holder.bind(platoList[position])
}
}
}
override fun getItemCount(): Int {
return platoList.size
}
public class MyViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val platoName: TextView = itemView.findViewById(R.id.platoNombre)
val platoDescription: TextView = itemView.findViewById(R.id.platoDescripcion)
val platoPrecio: TextView = itemView.findViewById(R.id.platoPrecio)
val platoTouch: LinearLayout = itemView.findViewById(R.id.platoTouch)
val platoCantidad: TextView = itemView.findViewById(R.id.platoCant)
private val mActivity = itemView.context as Activity
private val intent = Intent(mActivity,SlotActivity::class.java)
fun bind(plato: Plato){
platoTouch.setOnClickListener{
intent.putExtra("id", platoName.text.toString())
mActivity.startActivity(intent)
}
}
}
}
And this is my Activity which contains my RecyclerView and the variable I want to send.
package com.example.atipicoapp
import android.content.Intent
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.widget.Toast
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.google.firebase.firestore.*
import kotlinx.android.synthetic.main.activity_main.*
import kotlinx.android.synthetic.main.activity_menu_atipico.*
class MenuAtipicoActivity : AppCompatActivity() {
private lateinit var recyclerView: RecyclerView
private lateinit var platoArrayList: ArrayList<Plato>
private lateinit var myAdapter: MyAdapter
private lateinit var db: FirebaseFirestore
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_menu_atipico)
recyclerView = findViewById(R.id.recyclerView)
recyclerView.layoutManager = LinearLayoutManager(this)
recyclerView.setHasFixedSize(true)
platoArrayList = arrayListOf()
myAdapter = MyAdapter(platoArrayList)
recyclerView.adapter = myAdapter
pedidoId = intent.extras?.getString("pedidoId") //This is the variable I need to send
EventChangeListener()
Setup()
}
private fun EventChangeListener() {
db = FirebaseFirestore.getInstance()
db.collection("Platos").addSnapshotListener(object : EventListener<QuerySnapshot> {
override fun onEvent(
value: QuerySnapshot?,
error: FirebaseFirestoreException?
) {
if (error != null) {
Log.e("Firestore Error", error.message.toString())
return
}
for (dc: DocumentChange in value?.documentChanges!!) {
if (dc.type == DocumentChange.Type.ADDED) {
platoArrayList.add(dc.document.toObject(Plato::class.java))
}
}
myAdapter.notifyDataSetChanged()
}
})
}
private fun Setup() {
botonAceptar.setOnClickListener {
val SlotIntent = Intent(this, SlotActivity::class.java).apply {
}
startActivity(SlotIntent)
}
}
}
How can I send the variable if the Intent is executed from the Adapter?
Or... If it is not recommended to send intent from my Adapter, how can I send them from the activity?
Knowing that I have to carry a variable that is in the item of the RecyclerView.
Thanks for your help <3
Firstly, create a MyAdapter constructor where you pass arrayList as well as pedidoId like, your MyAdapter should be something like below:
MyAdapter.class
class MyAdapter(private val platoList : ArrayList<Plato>, val pedidoId:String
) : RecyclerView.Adapter<MyAdapter.MyViewHolder>() {
........
.....
....
//in your bind(..) method
fun bind(plato: Plato){
platoTouch.setOnClickListener{
intent.putExtra("id", platoName.text.toString())
intent.putExtra("pedidoId", pedidoId)
mActivity.startActivity(intent)
}
}
}
And, in your MenuAtipicoActivity you need to do something like:
MenuAtipicoActivity
class MenuAtipicoActivity : AppCompatActivity() {
...............
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_menu_atipico)
recyclerView = findViewById(R.id.recyclerView)
recyclerView.layoutManager = LinearLayoutManager(this)
recyclerView.setHasFixedSize(true)
platoArrayList = arrayListOf()
pedidoId = intent.extras?.getString("pedidoId") //This is the variable I need to send
myAdapter = MyAdapter(platoArrayList,pedidoId)
recyclerView.adapter = myAdapter
EventChangeListener()
Setup()
}
..........
........
}
I want to make an application with Kotlin and Google Maps in which the user can add markers on the Google Map and that these markers are sent to Firebase and other users can see those same markers on the map.
This is what I have done but it is not working well for me.
package com.racrapa.displayinglocationapp
import android.content.ContentValues
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.widget.Toast
import androidx.annotation.NonNull
import com.google.android.gms.maps.CameraUpdateFactory
import com.google.android.gms.maps.GoogleMap
import com.google.android.gms.maps.OnMapReadyCallback
import com.google.android.gms.maps.SupportMapFragment
import com.google.android.gms.maps.model.BitmapDescriptorFactory
import com.google.android.gms.maps.model.LatLng
import com.google.android.gms.maps.model.Marker
import com.google.android.gms.maps.model.MarkerOptions
import com.google.firebase.database.*
import com.google.firebase.database.ktx.database
import com.google.firebase.ktx.Firebase
import com.google.firebase.database.ValueEventListener
import com.google.firebase.database.DataSnapshot
import com.google.firebase.database.DatabaseError
import com.google.firebase.database.DatabaseReference
private const val TAG = "MapsActivity"
class MapsActivity : AppCompatActivity(), OnMapReadyCallback {
private lateinit var mMap: GoogleMap
public lateinit var databaseRef: DatabaseReference
private lateinit var database: DatabaseReference
private var markers: MutableList<Marker> = mutableListOf()
private var postListener: ValueEventListener? = null
var mDatabase: DatabaseReference? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_maps)
// Obtain the SupportMapFragment and get notified when the map is ready to be used.
val mapFragment = supportFragmentManager
.findFragmentById(R.id.map) as SupportMapFragment
mapFragment.getMapAsync(this)
databaseRef = Firebase.database.reference
mDatabase = FirebaseDatabase.getInstance().reference.child("userlocation")
database = Firebase.database.reference
}
This is to get the data from Firebase
public override fun onStart() {
super.onStart()
var postListener: ValueEventListener = object : ValueEventListener {
override fun onDataChange(dataSnapshot: DataSnapshot) {
if (dataSnapshot.exists()) {
val locationlogging = dataSnapshot.child("userlocation").getValue(LocationLogging::class.java)
var driverLat=locationlogging?.Latitude
var driverLong=locationlogging?.Longitude
if (driverLat != null && driverLong != null) {
val driverLoc = LatLng(driverLat, driverLong)
val markerOptions = MarkerOptions().position(driverLoc).title("Driver")
mMap.addMarker(markerOptions)
Toast.makeText(applicationContext, "Locations accessed from the database", Toast.LENGTH_LONG).show()
}
}
}
override fun onCancelled(error: DatabaseError) {}
}
databaseRef.addValueEventListener(postListener)
}
override fun onMapReady(googleMap: GoogleMap) {
mMap = googleMap
mMap.setOnMapLongClickListener { latLng ->
Log.i(TAG, "onMapLongClickListener")
setMapLongClick(latLng)
}
}
This is the function of sending coordinates to Firebase
private fun setMapLongClick(latLng: LatLng) {
if (latLng != null) {
Log.e("Latitude: ", latLng.latitude.toString() + "longitude: " + latLng.longitude)
val latlang: MutableMap<String, Double> = HashMap()
latlang["latitude"] = latLng.latitude
latlang["longitude"] = latLng.longitude
mDatabase!!.child("userlocation").push().setValue(latlang)
onStart()
}
}
}
I am currently building an app with a main activity which hosts a navHostFragment, and 3 fragments that are connected by a bottom navigation bar. My goal is to have each fragment use a Recycler View. I am using a Room database with an Adapter and LiveData for the "data". When I launch the app, I want to go to the Wallet fragment and see a vertical list of textViews. Because I am new and just starting out with this, I just wanted to have a very simple database of just text and then lay it out in a vertical format. Nothing too crazy yet. Any help would be greatly appreciated.
MainActivity
package com.example.android.pointmax
import android.os.Bundle
import com.google.android.material.bottomnavigation.BottomNavigationView
import androidx.appcompat.app.AppCompatActivity
import androidx.navigation.findNavController
import androidx.navigation.ui.AppBarConfiguration
import androidx.navigation.ui.setupActionBarWithNavController
import androidx.navigation.ui.setupWithNavController
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import timber.log.Timber
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// Plant tree to enable Debugging with Timber
Timber.plant(Timber.DebugTree())
// Find the bottomNavigation bar
val navView: BottomNavigationView = findViewById(R.id.nav_view)
// Find the fragment that will host the different fragments
val navController = findNavController(R.id.nav_host_fragment)
// Passing each menu ID as a set of Ids because each
// menu should be considered as top level destinations.
val appBarConfiguration = AppBarConfiguration(
setOf(
R.id.navigation_home, R.id.navigation_wallet, R.id.navigation_recommended
)
)
setupActionBarWithNavController(navController, appBarConfiguration)
navView.setupWithNavController(navController)
}
}
WalletFragment
package com.example.android.pointmax.ui.wallet
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.example.android.pointmax.CardAdapter
import com.example.android.pointmax.R
class WalletFragment : Fragment() {
private lateinit var viewManager: RecyclerView.LayoutManager
private lateinit var viewAdapter: RecyclerView.Adapter<*>
private lateinit var recyclerView: RecyclerView
private lateinit var viewModel: WalletViewModel
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val rootView = inflater.inflate(R.layout.fragment_wallet, container, false)
recyclerView = rootView.findViewById(R.id.wallet_recyclerview)
viewModel = ViewModelProvider(
this
).get(WalletViewModel::class.java)
val linearLayoutManager = LinearLayoutManager(context, RecyclerView.VERTICAL, false)
viewManager = linearLayoutManager
// Observe the ViewModel
viewModel.allCards.observe(viewLifecycleOwner, Observer { cards ->
viewAdapter = CardAdapter(cards)
})
return rootView
}
}
WalletViewModel
package com.example.android.pointmax.ui.wallet
import android.app.Application
import androidx.lifecycle.*
import com.example.android.pointmax.database.Card
import com.example.android.pointmax.database.CardRepository
import com.example.android.pointmax.database.CardRoomDatabase
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
class WalletViewModel(application: Application) : AndroidViewModel(application) {
private val repository: CardRepository
// Using LiveData and caching what getAlphabetizedWords returns has several benefits:
// - We can put an observer on the data (instead of polling for changes) and only update the
// the UI when the data actually changes.
// - Repository is completely separated from the UI through the ViewModel.
val allCards: LiveData<List<Card>>
init {
val cardsDao = CardRoomDatabase.getDatabase(application, viewModelScope).cardDao()
repository = CardRepository(cardsDao)
allCards = repository.allCards
}
/**
* Launching a new coroutine to insert the data in a non-blocking way
*/
fun insert(card: Card) = viewModelScope.launch(Dispatchers.IO) {
repository.insert(card)
}
}
CardAdapter
package com.example.android.pointmax
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import com.example.android.pointmax.database.Card
class CardAdapter internal constructor(
private var cards: List<Card>
) : RecyclerView.Adapter<CardAdapter.CardViewHolder>() {
inner class CardViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val cardItemView: TextView = itemView.findViewById(R.id.textView)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CardViewHolder {
val itemView = LayoutInflater.from(parent.context)
.inflate(R.layout.recyclerview_item, parent, false)
return CardViewHolder(itemView)
}
override fun onBindViewHolder(holder: CardViewHolder, position: Int) {
val current = cards[position]
holder.cardItemView.text = current.toString()
}
internal fun setWords(cards: List<Card>) {
this.cards = cards
notifyDataSetChanged()
}
override fun getItemCount() = cards.size
}
CardRepository
package com.example.android.pointmax.database
import androidx.lifecycle.LiveData
// Declares the DAO as a private property in the constructor. Pass in the DAO
// instead of the whole database, because you only need access to the DAO
class CardRepository(private val cardDao: CardDao) {
// Room executes all queries on a separate thread.
// Observed LiveData will notify the observer when the data has changed.
val allCards: LiveData<List<Card>> = cardDao.getCards()
suspend fun insert(card: Card) {
cardDao.insert(card)
}
}
CardRoomDatabase
package com.example.android.pointmax.database
import android.content.Context
import androidx.room.Database
import androidx.room.Room
import androidx.room.RoomDatabase
import androidx.sqlite.db.SupportSQLiteDatabase
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
// Annotates class to be a Room Database with a table (entity) of the Word class
#Database(entities = arrayOf(Card::class), version = 1, exportSchema = false)
public abstract class CardRoomDatabase : RoomDatabase() {
abstract fun cardDao(): CardDao
companion object {
// Singleton prevents multiple instances of database opening at the
// same time.
#Volatile
private var INSTANCE: CardRoomDatabase? = null
fun getDatabase(
context: Context,
scope: CoroutineScope
): CardRoomDatabase {
val tempInstance = INSTANCE
if (tempInstance != null) {
return tempInstance
}
synchronized(this) {
val instance = Room.databaseBuilder(
context.applicationContext,
CardRoomDatabase::class.java,
"card_database"
).addCallback(CardDatabaseCallback(scope)).build()
INSTANCE = instance
return instance
}
}
private class CardDatabaseCallback(
private val scope: CoroutineScope
) : RoomDatabase.Callback() {
override fun onOpen(db: SupportSQLiteDatabase) {
super.onOpen(db)
INSTANCE?.let { database ->
scope.launch {
populateDatabase(database.cardDao())
}
}
}
suspend fun populateDatabase(cardDao: CardDao) {
// Delete all content here.
cardDao.deleteAll()
// Add sample words.
var card = Card("Petal Credit Card")
cardDao.insert(card)
card = Card("Discover IT")
cardDao.insert(card)
}
}
}
}
Card
package com.example.android.pointmax.database
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
#Entity(tableName = "card_table")
data class Card(
#PrimaryKey
#ColumnInfo(name = "cardName")
var card: String
)
CardDao
package com.example.android.pointmax.database
import androidx.lifecycle.LiveData
import androidx.room.Dao
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
#Dao
interface CardDao {
#Query("SELECT * from card_table")
fun getCards(): LiveData<List<Card>>
#Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insert(card: Card)
#Query("DELETE FROM card_table")
suspend fun deleteAll()
}
I can launch the application but as soon as I go to the Wallet fragment, the application crashes with the following:
2020-04-23 19:24:18.676 5048-5048/com.example.android.pointmax E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.android.pointmax, PID: 5048
java.lang.RuntimeException: Cannot create an instance of class com.example.android.pointmax.ui.wallet.WalletViewModel
at androidx.lifecycle.ViewModelProvider$AndroidViewModelFactory.create(ViewModelProvider.java:275)
at androidx.lifecycle.SavedStateViewModelFactory.create(SavedStateViewModelFactory.java:106)
at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.java:185)
at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.java:150)
at com.example.android.pointmax.ui.wallet.WalletFragment.onCreateView(WalletFragment.kt:31)
at androidx.fragment.app.Fragment.performCreateView(Fragment.java:2698)
at androidx.fragment.app.FragmentStateManager.createView(FragmentStateManager.java:320)
at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1187)
at androidx.fragment.app.FragmentManager.addAddedFragments(FragmentManager.java:2224)
at androidx.fragment.app.FragmentManager.executeOpsTogether(FragmentManager.java:1997)
at androidx.fragment.app.FragmentManager.removeRedundantOperationsAndExecute(FragmentManager.java:1953)
at androidx.fragment.app.FragmentManager.execPendingActions(FragmentManager.java:1849)
at androidx.fragment.app.FragmentManager$4.run(FragmentManager.java:413)
at android.os.Handler.handleCallback(Handler.java:883)
at android.os.Handler.dispatchMessage(Handler.java:100)
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.java:267)
at androidx.lifecycle.SavedStateViewModelFactory.create(SavedStateViewModelFactory.java:106)
at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.java:185)
at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.java:150)
at com.example.android.pointmax.ui.wallet.WalletFragment.onCreateView(WalletFragment.kt:31)
at androidx.fragment.app.Fragment.performCreateView(Fragment.java:2698)
at androidx.fragment.app.FragmentStateManager.createView(FragmentStateManager.java:320)
at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1187)
at androidx.fragment.app.FragmentManager.addAddedFragments(FragmentManager.java:2224)
at androidx.fragment.app.FragmentManager.executeOpsTogether(FragmentManager.java:1997)
at androidx.fragment.app.FragmentManager.removeRedundantOperationsAndExecute(FragmentManager.java:1953)
at androidx.fragment.app.FragmentManager.execPendingActions(FragmentManager.java:1849)
at androidx.fragment.app.FragmentManager$4.run(FragmentManager.java:413)
at android.os.Handler.handleCallback(Handler.java:883)
at android.os.Handler.dispatchMessage(Handler.java:100)
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.RuntimeException: cannot find implementation for com.example.android.pointmax.database.CardRoomDatabase. CardRoomDatabase_Impl does not exist
at androidx.room.Room.getGeneratedImplementation(Room.java:94)
at androidx.room.RoomDatabase$Builder.build(RoomDatabase.java:952)
at com.example.android.pointmax.database.CardRoomDatabase$Companion.getDatabase(CardRoomDatabase.kt:37)
at com.example.android.pointmax.ui.wallet.WalletViewModel.(WalletViewModel.kt:20)
The most essential part of your stack trace is here
`Caused by: java.lang.RuntimeException: cannot find implementation for com.example.android.pointmax.database.CardRoomDatabase. CardRoomDatabase_Impl does not exist at androidx.room.Room.getGeneratedImplementation(Room.java:94) at androidx.room.RoomDatabase$Builder.build(RoomDatabase.java:952) at com.example.android.pointmax.database.CardRoomDatabase$Companion.getDatabase(CardRoomDatabase.kt:37) at com.example.android.pointmax.ui.wallet.WalletViewModel.(WalletViewModel.kt:20)`
So the problem is Room couldn't generate class CardRoomDatabase_Impl (implementation of your abstract class CardRoomDatabase). Since you use Room annotation correctly, the only reason of your problem I could guess - you haven't included annotation processor in your build.gradle (app level). Check if it is in dependencies-section:
kapt "androidx.room:room-compiler:2.2.5"