В настоящее время я создаю приложение с основным действием, которое содержит navHostFragment и 3 фрагмента, которые связаны нижней панелью навигации. Моя цель - чтобы каждый фрагмент использовал вид Recycler. Я использую базу данных Room с адаптером и LiveData для «данных». Когда я запускаю приложение, я хочу go к фрагменту Wallet и видеть вертикальный список textViews. Поскольку я новичок и только начинаю с этого, я просто хотел создать очень простую базу данных, содержащую только текст, а затем выложить ее в вертикальном формате. Ничего особенного пока нет. Любая помощь будет принята с благодарностью.
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)
}
}
}
}
Карта
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()
}
Я могу запустить приложение, но как только Я go к фрагменту кошелька, приложение вылетает со следующим:
2020-04-23 19: 24: 18.676 5048-5048 / com.example. android .pointmax E / AndroidRuntime: FATAL EXCEPTION: main Процесс: com.example. android .pointmax, PID: 5048 java .lang.RuntimeException: Невозможно создать экземпляр класса com.example. android .pointmax.ui.wallet.WalletViewModel в androidx.lifecycle.ViewModelProvider $ AndroidViewModelFactory.create (ViewModelProvider. java: 275) в androidx.lifecycle.SavedStateViewModelFactory.create (SavedStateViewModelFactory. java : 106) в androidx.lifecycle.ViewModelProvider.get (ViewModelProvider. java: 185) в androidx.lifecycle.ViewModelProvider.get (ViewModelProvider. java: 150) в com.example. android .pointmax.ui. wallet.WalletFragment.onCreateView (WalletFragment.kt: 31) в androidx.fragment.app.Fragment.performCreateView (Fragment. java: 2698) в androidx.fragment.app.FragmentStateManager.createView (FragmentStateManager. java 320): на androidx.fragment.app.FragmentManager.moveToState (FragmentManager. java: 1187) на androidx.fragment.app.FragmentManager.addAddedFragments (FragmentManager. java: 2224) на androidx.fragment.app.FragmentManagerMo . java: 1997) в androidx.fragment.app.FragmentManager.removeRedundantOperationsAndExecute (FragmentManager. java: 1953) в androidx.fragment.app.FragmentManager.execPendingActions (FragmentManager. java: 1849ragment) в android app.FragmentManager $ 4.run (FragmentManager. java: 413) в android .os.Handler.handleCallback (Обработчик. java: 883) в * 10 69 * .os.Handler.dispatchMessage (Обработчик. java: 100) в android .os.Looper.l oop (Looper. java: 214) в android .app.ActivityThread.main ( ActivityThread. java: 7356) в java .lang.reflect.Method.invoke (собственный метод) в com. android .internal.os.RuntimeInit $ MethodAndArgsCaller.run (RuntimeInit. java: 492) в com. android .internal.os.ZygoteInit.main (ZygoteInit. java: 930) Вызывается: java .lang.reflect.InvocationTargetException в java .lang.reflect.Constructor.newInstance0 (собственный метод) в java .lang.reflect.Constructor.newInstance (Constructor. java: 343) в androidx.lifecycle.ViewModelProvider $ AndroidViewModelFactory.create (ViewModelProvider. java: 267) в androidx.lifecycle.SavedSactFateFateSateFateSateFateSateFateSateMatelateFrateStateMtateCateFateSateFrateStateMtateCateFateSateFrateStateMtateCateFateSateFrateStateMtateCateFateSateFateStateMateCateFateStateMateFateStateMateCateMateCateMateCateMateCodeMed . java: 106) в androidx.lifecycle.ViewModelProvider.get (ViewModelProvider. java: 185) в androidx.lifecycle.ViewModelProvider.get (ViewModelProvider. java: 150) в com.example. android. pointmax.ui.wallet.WalletFragment.onCreateView (WalletFragment.kt: 31) в androidx .fragment.app.Fragment.performCreateView (Fragment. java: 2698) в androidx.fragment.app. FragmentStateManager.createView (FragmentStateManager. java: 320) в androidx.fragment.app.FragmentManager.moveToState (FragmentManager. java: 1187) в androidx.fragment.app.FragmentManager.addAddedFragments (FragmentManager * 2224): 2224. в androidx.fragment.app.FragmentManager.executeOpsTogether (FragmentManager. java: 1997) в androidx.fragment.app.FragmentManager.removeRedundantOperationsAndExecute (FragmentManager. java: 1953) в androidx.fragmentManagerFanager.exe) ( . java: 1849) в androidx.fragment.app.FragmentManager $ 4.run (FragmentManager. java: 413) в android .os.Handler.handleCallback (Обработчик. java: 883) в android .os.Handler.dispatchMessage (Обработчик. java: 100) в android .os.Looper.l oop (Looper. java: 214) в android .app.ActivityThread.main (ActivityThread. java: 7356) в java .lang.reflect.Method.invoke (собственный метод) в com. android .internal.os.RuntimeInit $ MethodAndArgsCaller.run (RuntimeInit. java: 492) в com. android .internal.os.ZygoteInit.main (Zygo teInit. java: 930) Причина: java .lang.RuntimeException: не удается найти реализацию для com.example. android .pointmax.database.CardRoomDatabase. CardRoomDatabase_Impl не существует в androidx.room.Room.getGeneratedImplementation (Room. java: 94) в androidx.room.RoomDatabase $ Builder.build (RoomDatabase. java: 952) в com.example. android .pointmax .database.CardRoomDatabase $ Companion.getDatabase (CardRoomDatabase.kt: 37) в com.example. android .pointmax.ui.wallet.WalletViewModel. (WalletViewModel.kt: 20)