I'm sorry to ask the repeatedly answered question but I just couldn't solve this relating to my specific case, maybe I'm missing something. The error is E/RecyclerView: No adapter attached; skipping layout and I'm not sure, is the problem with an adapter I set or the RecyclerView per se? Also, I was following a tutorial and this was the code that was presented.
(I tried brining the initRecyclerView() into the main onCreateView but no luck. Some answers say to set an empty adapter first and notify it with the changes later but I don't know how to do that.)
This is my HomeFragment:
open class HomeFragment() : Fragment() {
private lateinit var homeViewModel: HomeViewModel
private lateinit var binding: FragmentHomeBinding
private val language = arrayOf("English", "German", "Arabic", "Spanish", "Chinese", "French")
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
binding = DataBindingUtil.inflate(inflater, R.layout.fragment_home, container, false)
val dao = VocabData.getInstance(this).VocabDao
val repository = VocabRepository(dao)
val factory = HomeViewModelFactory(repository, application = activity?.applicationContext as Application)
homeViewModel = ViewModelProvider(this, factory).get(HomeViewModel::class.java)
binding.myViewModel = homeViewModel
binding.lifecycleOwner = this
initRecyclerView()
homeViewModel.message.observe(viewLifecycleOwner, Observer {
it.getContentIfNotHandled()?.let {
Toast.makeText(requireContext(), it, Toast.LENGTH_LONG).show()
}
})
// create an adapter
val arrayAdapter =
ArrayAdapter(requireContext(), android.R.layout.simple_spinner_dropdown_item, language)
binding.spinner.adapter = arrayAdapter
// Set layout to use when the list of choices appear
arrayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
// Set Adapter to Spinner
binding.spinner.setAdapter(arrayAdapter)
val button = binding.tagButton
button.setOnClickListener{
GlobalScope.launch(Dispatchers.IO) {
homeViewModel.tagger(binding.spinner)
}
}
return binding.root
}
private fun initRecyclerView(){
binding.vocabRecyclerView.layoutManager = LinearLayoutManager(requireContext())
displayVocabsList()
}
private fun displayVocabsList() {
homeViewModel.vocabs.observe(viewLifecycleOwner, Observer {
Log.i("MYTAG", it.toString())
binding.vocabRecyclerView.adapter = MyRecyclerViewAdapter(it, { selectedItem: Vocab -> listItemClicked(selectedItem) })
})
}
private fun listItemClicked(vocab: Vocab){
Toast.makeText(requireContext(), "selected sentence is ${vocab.sentString}", Toast.LENGTH_LONG).show()
}
}
And this is my RecyclerViewAdapter, which is really just boilerplate code:
class MyRecyclerViewAdapter(private val vocabsList: List<Vocab>, private val clickListener:(Vocab)->Unit) :
RecyclerView.Adapter<MyViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
val layoutInflater = LayoutInflater.from(parent.context)
val binding : ListItemBinding =
DataBindingUtil.inflate(layoutInflater, R.layout.list_item, parent, false)
return MyViewHolder(binding)
}
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
holder.bind(vocabsList[position], clickListener)
}
override fun getItemCount(): Int {
return vocabsList.size
}
}
class MyViewHolder(private val binding: ListItemBinding):RecyclerView.ViewHolder(binding.root){
fun bind(vocab: Vocab, clickListener:(Vocab)->Unit){
binding.sentenceTextView.text = vocab.sentString
binding.listItemLayout.setOnClickListener{
clickListener(vocab)
}
}
}
I think that's all the related code. If you have an idea please let me know how to avoid this error/lag, thank you!
UPDATE
activity_main.xml
<layout xmlns:tools="http://schemas.android.com/tools"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="#+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="#+id/nav_view"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="0dp"
android:layout_marginEnd="0dp"
android:background="?android:attr/windowBackground"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:menu="#menu/bottom_nav_menu" >
<androidx.viewpager2.widget.ViewPager2
android:layout_width="match_parent"
android:layout_height="match_parent" />
</com.google.android.material.bottomnavigation.BottomNavigationView>
<androidx.fragment.app.FragmentContainerView
android:id="#+id/nav_host_fragment"
class = "androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:defaultNavHost="true"
app:layout_constraintBottom_toTopOf="#id/nav_view"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:navGraph="#navigation/mobile_navigation" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
fragment_home.xml
<layout xmlns:tools="http://schemas.android.com/tools"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
<variable
name="myViewModel"
type="com.jwanhsulaiman.talktag.ui.home.HomeViewModel" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="8dp"
tools:context=".ui.home.HomeFragment">
<EditText
android:id="#+id/editTextTextMultiLine"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:ems="10"
android:gravity="start|top"
android:hint="Input Sentence(s)\n"
android:inputType="textMultiLine"
android:text="#={myViewModel.inputVocab}"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/spinner" />
<Button
android:id="#+id/tag_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:enabled="#{myViewModel.enabled}"
android:text="#={myViewModel.tagAll}"
android:textSize="14sp"
android:textStyle="bold"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="#+id/editTextTextMultiLine" />
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/vocab_recycler_view"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/progressBar" />
<Button
android:id="#+id/clear"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginLeft="8dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:layout_marginRight="8dp"
android:onClick="#{()->myViewModel.deleteAll()}"
android:text="CLEAR"
app:layout_constraintEnd_toStartOf="#+id/progressBar"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/editTextTextMultiLine" />
<Spinner
android:id="#+id/spinner"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:layout_marginRight="8dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ProgressBar
android:id="#+id/progressBar"
style="?android:attr/progressBarStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:layout_marginRight="8dp"
android:visibility="#{!myViewModel.barProgress}"
app:layout_constraintEnd_toStartOf="#+id/tag_button"
app:layout_constraintTop_toBottomOf="#+id/editTextTextMultiLine" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
HomeViewModel.kt
import android.annotation.SuppressLint
import android.app.Application
import android.view.View
import android.widget.Spinner
import androidx.databinding.Bindable
import androidx.databinding.BindingAdapter
import androidx.databinding.Observable
import androidx.databinding.ObservableField
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.viewModelScope
import com.jwanhsulaiman.talktag.Event
import com.jwanhsulaiman.talktag.R
import com.jwanhsulaiman.talktag.database.Vocab
import com.jwanhsulaiman.talktag.database.VocabRepository
import edu.stanford.nlp.tagger.maxent.MaxentTagger
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import opennlp.tools.sentdetect.SentenceDetectorME
import opennlp.tools.sentdetect.SentenceModel
#BindingAdapter("android:visibility")
fun setVisibility(view: View, visible: Boolean) {
view.visibility = if (visible) View.INVISIBLE else View.VISIBLE
}
#BindingAdapter("android:enabled")
fun setEnabled(view: View, enabled: Boolean) {
view.isEnabled = !enabled
}
#SuppressLint("StaticFieldLeak")
class HomeViewModel(private val repository: VocabRepository, application: Application) : AndroidViewModel(
application
), Observable {
private val context = getApplication<Application>().applicationContext
private val model: SentenceModel = SentenceModel(context.resources.openRawResource(R.raw.en))
private val sDetector = SentenceDetectorME(model)
private var senlist = mutableListOf<String?>()
val vocabs = repository.vocabs
#Bindable
var barProgress = ObservableField<Boolean>()
#Bindable
var enabled = ObservableField<Boolean>()
private fun makeVisible(){
this.barProgress.set(true) }
private fun makeInvisible(){
this.barProgress.set(false) }
private fun makeEnabled(){
this.enabled.set(true) }
private fun makeDisabled(){
this.enabled.set(false) }
#Bindable
val inputVocab = MutableLiveData<String>()
#Bindable
val tagAll = MutableLiveData<String>()
private val statusMessage = MutableLiveData<Event<String>>()
val message : LiveData<Event<String>>
get() = statusMessage
init {
tagAll.postValue("Tag!")
}
suspend fun tagger(spinner: Spinner){
if (inputVocab.value.isNullOrBlank()) {
statusMessage.postValue(Event("Please enter sentence"))
} else {
withContext(Dispatchers.IO) {
//tag words
makeEnabled()
makeVisible()
}
}
}
private suspend fun splitSens(vocab: String): MutableList<String?> {
withContext(Dispatchers.IO) {
//split sentences
}
return senlist
}
private suspend fun tagAll(vocab: String){
withContext(Dispatchers.IO){
insert(Vocab(0, vocab))
inputVocab.postValue(null)
}
makeInvisible()
makeDisabled()
}
fun insert(vocab: Vocab) : Job = viewModelScope.launch {
repository.insert(vocab)
statusMessage.value = Event("Vocab inserted successfuly")
}
fun update(vocab: Vocab) : Job = viewModelScope.launch {
repository.update(vocab)
}
fun delete(vocab: Vocab) : Job = viewModelScope.launch {
repository.delete(vocab)
}
fun deleteAll() = viewModelScope.launch {
repository.deleteAll()
}
override fun addOnPropertyChangedCallback(callback: Observable.OnPropertyChangedCallback?) {
//TODO("Not yet implemented")
}
override fun removeOnPropertyChangedCallback(callback: Observable.OnPropertyChangedCallback?) {
//TODO("Not yet implemented")
}
}
build.gradle
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-kapt'
/**
plugins {
id 'com.android.application'
id 'kotlin-android'
id 'kotlin-kapt'
}
**/
android {
compileSdkVersion 29
buildToolsVersion "30.0.3"
defaultConfig {
applicationId "com.jwanhsulaiman.talktag"
minSdkVersion 16
targetSdkVersion 29
versionCode 1
versionName "1.0"
multiDexEnabled true
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
}
buildFeatures {
dataBinding true
}
}
dependencies {
implementation files('libs/postagger.jar')
implementation files('libs/nlp/opennlp-tools-1.9.3.jar')
def lifecycle_version = "2.2.0"
def room_version = "2.2.3"
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation 'androidx.core:core-ktx:1.3.2'
implementation 'androidx.appcompat:appcompat:1.2.0'
implementation 'com.google.android.material:material:1.3.0'
implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
implementation 'androidx.vectordrawable:vectordrawable:1.1.0'
implementation 'androidx.navigation:navigation-fragment:2.3.3'
implementation 'androidx.navigation:navigation-ui:2.3.3'
implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.3.0'
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.0'
implementation 'androidx.navigation:navigation-fragment-ktx:2.3.3'
implementation 'androidx.navigation:navigation-ui-ktx:2.3.3'
implementation 'androidx.room:room-runtime:2.2.6'
testImplementation 'junit:junit:4.13.2'
kapt "com.android.databinding:compiler:3.5.0"
implementation 'androidx.fragment:fragment-ktx:1.3.0'
// ViewModel
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version"
// LiveData
implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version"
// Annotation processor
//noinspection LifecycleAnnotationProcessorWithJava8
kapt "androidx.lifecycle:lifecycle-compiler:$lifecycle_version"
implementation "androidx.room:room-runtime:$room_version"
kapt "androidx.room:room-compiler:$room_version"
// optional - Kotlin Extensions and Coroutines support for Room
implementation "androidx.room:room-ktx:$room_version"
//coroutines
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.4.1'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.4.1'
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
kapt 'androidx.room:room-compiler:2.2.6'
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.0"
// Kotlin Extensions and Coroutines support for Room
implementation "androidx.room:room-ktx:2.2.6"
implementation 'com.android.support:multidex:1.0.3'
}
Ok, it's normal you have this message because in your code, you' ll do this :
homeViewModel.vocabs.observe(viewLifecycleOwner, Observer {
Log.i("MYTAG", it.toString())
binding.vocabRecyclerView.adapter = MyRecyclerViewAdapter(it, { selectedItem: Vocab -> listItemClicked(selectedItem) })
})
The best solution to not have this message is to set an adapter in createView :
myRecyclerViewAdapter = MyRecyclerViewAdapter({ selectedItem: Vocab -> listItemClicked(selectedItem) })
binding.vocabRecyclerView.adapter = myRecyclerViewAdapter
and :
homeViewModel.vocabs.observe(viewLifecycleOwner, Observer {
myRecyclerViewAdapter.addData(it)
}
and for recyclerView :
class MyRecyclerViewAdapter : .... {
private var values = arrayListOf<....>()
fun addData(values : List<>){
values.addAll(values)
}
}
NB: I put addAll but I don't know what you do, may be you have to do something else.
You have this message because there's no adapter. You have an adpater only when there're data with your observe. It's better if you initialize your adapter and after listening for new datas.
}
Related
It seems I have some problem with kapt. I study Android and try to create app with Room and Coroutines.
I get this kind of mistakes:
enter image description here
and my onclicklistener at XML is underlined with red, and the mistake here is "Cannot find identifier 'onSave' ".
I also tried to set onclick listener at the fragment, but I got the same mistakes.
Neither invalidating caches nor rebuilding project helps.
AddViewModel.kt:
`package com.example.memorizewords.add
import android.app.Application
import androidx.lifecycle.*
import androidx.lifecycle.ViewModelProvider.AndroidViewModelFactory.Companion.APPLICATION_KEY
import androidx.lifecycle.viewmodel.CreationExtras
import com.example.memorizewords.database.Word
import com.example.memorizewords.database.WordDatabase
import com.example.memorizewords.database.WordDatabaseDao
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
class AddViewModel(
val database: WordDatabaseDao?,
application: Application) : AndroidViewModel(application) {
private val _targetWord = MutableLiveData<String>()
private val _nativeWord = MutableLiveData<String>()
private suspend fun insert(word: Word) {
database?.insert(word)
}
private fun onSave() {
runBlocking {
viewModelScope.launch(Dispatchers.IO) {}
// val newWord = Word(0L, _targetWord.value!!, _nativeWord.value!!, true)
val newWord = Word(0L, "String", "String", true)
insert(newWord)
}
}
companion object {
val Factory: ViewModelProvider.Factory = object : ViewModelProvider.Factory {
#Suppress("UNCHECKED_CAST")
override fun <T : ViewModel> create(
modelClass: Class<T>,
extras: CreationExtras
): T {
val application = checkNotNull(extras[APPLICATION_KEY])
val dataSource = WordDatabase.getInstance(application).WordDatabaseDao
AddViewModel(dataSource, application)
return AddViewModel(dataSource, application) as T
}
}
}
}`
AddFragment.kt:
`package com.example.memorizewords.add
import android.os.Bundle
import android.view.LayoutInflater
import android.view.ViewGroup
import android.view.View
import android.widget.Toast
import androidx.databinding.DataBindingUtil
import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels
import com.example.memorizewords.R
import com.example.memorizewords.databinding.FragmentAddBinding
class AddFragment : Fragment() {
private val viewModel: AddViewModel by viewModels { AddViewModel.Factory }
lateinit var targetWord: String
lateinit var nativeWord: String
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
val binding: FragmentAddBinding = DataBindingUtil.inflate(
inflater, R.layout.fragment_add, container, false)
binding.setLifecycleOwner(this)
binding.addViewModel = viewModel
}`
XML:
`<?xml version="1.0" encoding="utf-8"?>
<layout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
<variable
name="addViewModel"
type="com.example.memorizewords.add.AddViewModel" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<EditText
android:id="#+id/targetBox"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="#dimen/button_margin_left_right"
android:layout_marginEnd="#dimen/button_margin_left_right"
android:hint="#string/enterTarget"
android:textSize="#dimen/edit_text_size"
app:layout_constraintBottom_toTopOf="#+id/guideline2"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<androidx.constraintlayout.widget.Guideline
android:id="#+id/guideline2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.15" />
<EditText
android:id="#+id/nativeBox"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="#dimen/button_margin_left_right"
android:layout_marginEnd="#dimen/button_margin_left_right"
android:hint="#string/enterNative"
android:textSize="#dimen/edit_text_size"
app:layout_constraintBottom_toTopOf="#+id/guideline3"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#id/guideline2" />
<androidx.constraintlayout.widget.Guideline
android:id="#+id/guideline3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.3" />
<Button
android:id="#+id/saveButton"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="#dimen/save_button_margin"
android:layout_marginEnd="#dimen/save_button_margin"
android:text="#string/save"
android:textSize="#dimen/button_text_size"
android:onClick="#{() -> addViewModel.onSave()}" //onSave here is underlined with red
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/guideline3"
app:layout_constraintVertical_bias="0.1" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>`
module's build.gradle
`plugins {
id 'com.android.application'
id 'kotlin-android'
id 'kotlin-kapt'
id 'androidx.navigation.safeargs.kotlin'
}
android {
compileSdk 32
defaultConfig {
applicationId "com.example.memorizewords"
minSdk 21
targetSdk 32
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
}
buildFeatures {
dataBinding true
viewBinding true
}
}
dependencies {
// Android KTX
implementation 'androidx.core:core-ktx:1.7.0'
implementation 'androidx.appcompat:appcompat:1.5.1'
implementation 'com.google.android.material:material:1.7.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
// ViewModel and LiveData
implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.5.1'
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.1'
// Navigation
implementation 'androidx.navigation:navigation-fragment-ktx:2.5.3'
implementation 'androidx.navigation:navigation-ui-ktx:2.5.3'
// Room and Lifecycle dependencies
implementation "androidx.room:room-runtime:2.4.3"
kapt "androidx.room:room-compiler:2.4.3"
// Kotlin Extensions and Coroutines support for Room
implementation("androidx.room:room-ktx:2.4.3")
// Coroutines
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.1"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.1"
// Testing
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.4'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.0'
implementation 'com.jakewharton.timber:timber:4.7.1'
}`
app's build.gradle
`plugins {
id 'com.android.application' version '7.2.0' apply false
id 'com.android.library' version '7.2.0' apply false
id 'org.jetbrains.kotlin.android' version '1.7.10' apply false
id 'androidx.navigation.safeargs.kotlin' version '2.4.1' apply false
}
task clean(type: Delete) {
delete rootProject.buildDir
}`
First of all, I'm new into kotlin and I found issues within my learning process. So I found these errors:
"Cannot find identifier 'Current Item"
The errors occured in the xml file. here is code of the xml file:
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<data>
<variable
name="args"
type="com.example.todoapp.fragments.update.UpdateFragment" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="24dp"
tools:context=".fragments.update.UpdateFragment">
<EditText
android:id="#+id/current_title_et"
android:layout_width="0dp"
android:layout_height="60dp"
android:background="#drawable/custom_input"
android:ems="10"
android:hint="#string/title"
android:inputType="textPersonName"
android:paddingStart="24dp"
android:paddingEnd="24dp"
android:text="#{args.currentItem.title}"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Spinner
android:id="#+id/current_priorities_spinner"
android:layout_width="0dp"
android:layout_height="60dp"
android:layout_marginTop="8dp"
android:background="#drawable/custom_input"
android:entries="#array/priorities"
android:paddingStart="20dp"
android:paddingEnd="20dp"
android:parsePriorityToInt="#{args.currentItem.priority}"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/current_title_et" />
<EditText
android:id="#+id/current_description_et"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginTop="8dp"
android:background="#drawable/custom_input"
android:ems="10"
android:gravity="top|start"
android:hint="#string/description"
android:inputType="textMultiLine"
android:paddingStart="24dp"
android:paddingTop="16dp"
android:paddingEnd="24dp"
android:text="#{args.currentItem.description}"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/current_priorities_spinner" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
and this is the kt file
package com.example.todoapp.fragments.update
import android.app.AlertDialog
import android.os.Bundle
import android.view.*
import android.widget.Toast
import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels
import androidx.navigation.fragment.findNavController
import androidx.navigation.fragment.navArgs
import com.example.todoapp.R
import com.example.todoapp.data.models.ToDoData
import com.example.todoapp.data.viewmodel.ToDoViewModel
import com.example.todoapp.databinding.FragmentUpdateBinding
import com.example.todoapp.fragments.SharedViewModel
class UpdateFragment : Fragment() {
private val args by navArgs<UpdateFragmentArgs>()
private val mSharedViewModel: SharedViewModel by viewModels()
private val mToDoViewModel: ToDoViewModel by viewModels()
private var _binding: FragmentUpdateBinding? = null
private val binding get() = _binding!!
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
// Data binding
_binding = FragmentUpdateBinding.inflate(inflater, container, false)
// Set Menu
setHasOptionsMenu(true)
// Spinner Item Selected Listener
binding.currentPrioritiesSpinner.onItemSelectedListener = mSharedViewModel.listener
return binding.root
}
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
inflater.inflate(R.menu.update_fragment_menu, menu)
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
R.id.menu_save -> updateItem()
R.id.menu_delete -> confirmItemRemoval()
}
return super.onOptionsItemSelected(item)
}
private fun updateItem() {
val title = binding.currentTitleEt.text.toString()
val description = binding.currentDescriptionEt.text.toString()
val getPriority = binding.currentPrioritiesSpinner.selectedItem.toString()
val validation = mSharedViewModel.verifyDataFromUser(title, description)
if (validation) {
// Update Current Item
val updatedItem = ToDoData(
args.currentItem.id,
title,
mSharedViewModel.parsePriority(getPriority),
description
)
mToDoViewModel.updateData(updatedItem)
Toast.makeText(requireContext(), "Successfully updated!", Toast.LENGTH_SHORT).show()
// Navigate back
findNavController().navigate(R.id.action_updateFragment_to_listFragment)
} else {
Toast.makeText(requireContext(), "Please fill out all fields.", Toast.LENGTH_SHORT)
.show()
}
}
// Show AlertDialog to Confirm Item Removal
private fun confirmItemRemoval() {
val builder = AlertDialog.Builder(requireContext())
builder.setPositiveButton("Yes") { _, _ ->
mToDoViewModel.deleteItem(args.currentItem)
Toast.makeText(
requireContext(),
"Successfully Removed: ${args.currentItem.title}",
Toast.LENGTH_SHORT
).show()
findNavController().navigate(R.id.action_updateFragment_to_listFragment)
}
builder.setNegativeButton("No") { _, _ -> }
builder.setTitle("Delete '${args.currentItem.title}'?")
builder.setMessage("Are you sure you want to remove '${args.currentItem.title}'?")
builder.create().show()
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
}
this is the plugin and dependency
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: "kotlin-kapt"
apply plugin: "androidx.navigation.safeargs.kotlin"
apply plugin: "kotlin-parcelize"
android {
compileSdkVersion 30
buildToolsVersion "30.0.3"
defaultConfig {
applicationId "com.example.todoapp"
minSdkVersion 26
targetSdkVersion 30
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
buildFeatures{
dataBinding = true
viewBinding = true
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = JavaVersion.VERSION_1_8.toString()
}
}
dependencies {
implementation fileTree(dir: "libs", include: ["*.jar"])
implementation 'androidx.core:core-ktx:1.5.0'
implementation 'androidx.appcompat:appcompat:1.3.0'
implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
// Navigation Component
implementation 'androidx.navigation:navigation-fragment-ktx:2.3.5'
implementation 'androidx.navigation:navigation-ui-ktx:2.3.5'
// Room components
implementation "androidx.room:room-runtime:2.3.0"
kapt "androidx.room:room-compiler:2.3.0"
implementation "androidx.room:room-ktx:2.3.0"
androidTestImplementation "androidx.room:room-testing:2.3.0"
// Lifecycle components
implementation "androidx.lifecycle:lifecycle-extensions:2.2.0"
implementation "androidx.lifecycle:lifecycle-common-java8:2.3.1"
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.1"
// Kotlin components
api "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.0-native-mt"
api "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.0-native-mt"
}
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
google()
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:4.2.1'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.5.10"
classpath "androidx.navigation:navigation-safe-args-gradle-plugin:2.3.5"
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
google()
mavenCentral()
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
Any help or explanation would be appreciated
So I'm building this Carousel project that shows an image and some text on the app. I've gotten the structure down by building a prototype. I was able to use Retrofit to call the information from the RestAPI on my terminal as well. But where I have been really stuck at is trying to get the info to show in the container, where I want it to show. I've tried a slew of ways to approach it, but to no avail. Below is the code I have now, which is showing images and text that I put in it. Along with the Retrofit classes. I've been at it for three days and I'm not sure what to do. If anyone has an idea or can help, I'll be extremely thankful.
The API (Retrofit)
package com.examples.carousel.api
import com.examples.carousel.CarouselItem
import com.examples.carousel.utli.Constants.Companion.BASE_URL
import retrofit2.Call
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import retrofit2.http.GET
interface FlickrApi {
#GET("services/rest/?method=flickr.interestingness.getList" +
"&api_key=(private)" +
"&format=json" +
"&nojsoncallback=1" +
"&extras=url_s")
fun getCarouselItem() : Call<List<CarouselItem>>
companion object {
fun create() : FlickrApi {
val retrofit = Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create())
.baseUrl(BASE_URL)
.build()
return retrofit.create(FlickrApi::class.java)
}
}
}
The Model (The comment out code is for the info I want from the api)
package com.examples.carousel
data class CarouselItem internal constructor(
// var title: String,
// var id: String,
// var url_s: String
var image: Int,
var title2: String
) {
}
The Adapter
package com.examples.carousel
import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import androidx.viewpager2.widget.ViewPager2
import com.bumptech.glide.Glide
import com.makeramen.roundedimageview.RoundedImageView
class ItemAdapter internal constructor(carouselItems: MutableList<CarouselItem>, viewPager2: ViewPager2) : RecyclerView.Adapter<ItemAdapter.ItemPagerViewHolder>() {
private val carouselItems: List<CarouselItem>
private val viewPager2: ViewPager2
init {
this.carouselItems = carouselItems
this.viewPager2 = viewPager2
}
class ItemPagerViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
private val photo: RoundedImageView = itemView.findViewById(R.id.picture)
private val title: TextView = itemView.findViewById(R.id.photo_name)
fun image(carouselItem: CarouselItem) {
photo.setImageResource(carouselItem.image)
}
fun text(carouselItem: CarouselItem) {
title.text = carouselItem.title2
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ItemPagerViewHolder {
return ItemPagerViewHolder(
LayoutInflater.from(parent.context).inflate(
R.layout.carousel_item_container,
parent,
false
)
)
}
override fun onBindViewHolder(holder: ItemPagerViewHolder, position: Int) {
holder.image(carouselItems[position])
holder.text(carouselItems[position])
if (position == carouselItems.size - 2) {
viewPager2.post(runnable)
}
}
override fun getItemCount(): Int {
return carouselItems.size
}
private val runnable = Runnable {
carouselItems.addAll(carouselItems)
notifyDataSetChanged()
}
}
The MainActivity
package com.examples.carousel
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.recyclerview.widget.RecyclerView
import androidx.viewpager2.widget.CompositePageTransformer
import androidx.viewpager2.widget.MarginPageTransformer
import androidx.viewpager2.widget.ViewPager2
import com.examples.carousel.api.FlickrApi
import com.makeramen.roundedimageview.RoundedImageView
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
import kotlin.math.abs
class CarouselActivity : AppCompatActivity() {
lateinit var viewPager: ViewPager2
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_carousel)
viewPager = findViewById(R.id.viewPager_ImageSlider)
supportActionBar?.hide()
val multipleItems: MutableList<CarouselItem> = ArrayList()
multipleItems.add(CarouselItem(R.drawable.bcw_38,"Image 1"))
multipleItems.add(CarouselItem(R.drawable.bcw_39,"Image 2"))
multipleItems.add(CarouselItem(R.drawable.bcw_40,"Image 3"))
multipleItems.add(CarouselItem(R.drawable.bcw_45,"Image 4"))
multipleItems.add(CarouselItem(R.drawable.bcw_50,"Image 5"))
multipleItems.add(CarouselItem(R.drawable.bcw_53,"Image 6"))
viewPager.adapter = ItemAdapter(multipleItems,viewPager)
viewPager.clipToPadding = false
viewPager.clipChildren = false
viewPager.offscreenPageLimit = 3
viewPager.getChildAt(0).overScrollMode = RecyclerView.OVER_SCROLL_NEVER
val compositePageTransformer = CompositePageTransformer()
compositePageTransformer.addTransformer(MarginPageTransformer(30))
compositePageTransformer.addTransformer { page, position ->
val r = 1 - abs(position)
page.scaleY = 0.85f + r * 0.25f
}
viewPager.setPageTransformer(compositePageTransformer)
//
// val apiInterface = FlickrApi.create().getCarouselItem()
//
// apiInterface.enqueue(object: Callback<List<CarouselItem>> {
// override fun onFailure(call: Call<List<CarouselItem>>, t: Throwable) {
//
// }
//
// override fun onResponse(call: Call<List<CarouselItem>>, response: Response<List<CarouselItem>>) {
//
// if (response.body() != null){
// itemAdapter.setItemListItems(response.body()!!)
//
// }
// }
// })
}
}
The XML Files:
The ViewPager2 layout
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent" android:background="#232323"
android:id="#+id/linearLayout">
<androidx.viewpager2.widget.ViewPager2
android:id="#+id/viewPager_ImageSlider"
android:layout_height="0dp"
android:layout_width="0dp"
android:paddingStart="70dp"
android:paddingEnd="70dp"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintBottom_toBottomOf="parent" android:layout_marginTop="80dp"/>
<TextView
android:text="#string/osa_playlist"
android:layout_width="wrap_content"
android:layout_height="wrap_content" android:id="#+id/textView2"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" android:layout_marginTop="40dp"
android:textColor="#color/white" android:textSize="25sp"/>
</androidx.constraintlayout.widget.ConstraintLayout>
The Container
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent" android:id="#+id/container" android:background="#232323">
<com.makeramen.roundedimageview.RoundedImageView
android:layout_width="match_parent"
android:layout_height="550dp" app:layout_constraintTop_toTopOf="parent" android:id="#+id/picture"
android:adjustViewBounds="true"
app:riv_corner_radius="12dp" tools:layout_editor_absoluteX="0dp"/>
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content" android:id="#+id/photo_name"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" android:layout_marginLeft="8dp"
android:layout_marginStart="8dp" android:layout_marginRight="8dp" android:layout_marginEnd="8dp"
android:textStyle="bold"
tools:text="TEXT TEXT" android:textSize="36sp" android:textColor="#color/white" android:gravity="center"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintTop_toBottomOf="#+id/picture" app:layout_constraintBottom_toBottomOf="parent"
android:layout_marginBottom="230dp"/>
</androidx.constraintlayout.widget.ConstraintLayout>
The Dependencies
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation 'androidx.core:core-ktx:1.3.2'
implementation 'androidx.appcompat:appcompat:1.2.0'
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
implementation 'com.google.android.material:material:1.3.0'
implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
//For the Carousel Container
implementation 'androidx.viewpager2:viewpager2:1.0.0'
implementation 'com.makeramen:roundedimageview:2.3.0'
//For Retrofit and Gson
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
// implementation 'com.squareup.retrofit2:converter-scalars:2.5.0'
// implementation 'com.google.code.gson:gson:2.8.6'
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
implementation 'com.squareup.okhttp3:okhttp:4.9.0'
testImplementation 'junit:junit:4.13.2'
// Coroutines
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.4.2'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.4.1'
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.1'
implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.3.1'
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
implementation 'com.github.bumptech.glide:glide:4.12.0'
annotationProcessor 'com.github.bumptech.glide:compiler:4.12.0'
}
*Its not the Internet permission, it's already there.
itemAdapter.setItemListItems(response.body()!!) instead of calling adapters method, write your own method which updates the list:
private val carouselItems: List,
make this list mutable and write method:
public fun updateList(val items: List<CarouselItem>){
carouselItems.clear()
carouselItems.addAll(items)
notifyDataSetChanged()
}
I'm currently developing an application using android-studio with Kotlin.
This app has
a common value I can use through fragments
a fragment class for main content
a fragment class for bottom sheet
I want to show a new value on the main fragment view right after I change the common value at edittext in bottom sheet.
But in the case of my codes, the common value doesn't change when I' back to the main fragment view from the bottom sheet...
How can I solve this situation?
Here are the codes:
build.gradle
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
android {
compileSdkVersion 28
defaultConfig {
applicationId "com.sample.bottomsheetvalue"
minSdkVersion 16
targetSdkVersion 28
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation 'androidx.appcompat:appcompat:1.0.0-beta01'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
implementation 'androidx.legacy:legacy-support-v4:1.0.0-beta01'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test:runner:1.1.0-alpha4'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.0-alpha4'
implementation "androidx.fragment:fragment-ktx:1.3.0-alpha04"
implementation "com.google.android.material:material:1.1.0-alpha06"
}
AppState.kt
package com.sample.bottomsheetvalue
import androidx.lifecycle.ViewModel
class AppState: ViewModel() {
var value:String = "initialValue"
}
MainActivity.kt
package com.sample.bottomsheetvalue
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Button
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<fragment
android:id="#+id/main_fragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:name="com.tomato_love.bottomsheetvalue.MainFragment"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
MainFragment.kt
package com.sample.bottomsheetvalue
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Button
import android.widget.TextView
import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModelProvider
class MainFragment : Fragment() {
lateinit var appState: AppState
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
activity?.run {
appState = ViewModelProvider(this).get(AppState::class.java)
}
val view = inflater.inflate(R.layout.fragment_main, container, false)
val button = view.findViewById<Button>(R.id.button)
val textView = view.findViewById<TextView>(R.id.textView)
textView.text = appState.value
button.setOnClickListener {
val fm = activity!!.supportFragmentManager
val bottomSheet =BottomSheet()
bottomSheet.show(fm, "navigation_bottom_sheet")
}
return view
}
}
fragment_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainFragment"
android:id="#+id/constraintLayoutFragment">
<Button
android:id="#+id/button"
android:text="show bottom sheet"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="32dp"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
/>
<TextView
android:id="#+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="32sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:layout_marginTop="32dp"
app:layout_constraintTop_toBottomOf="#+id/button"/>
</androidx.constraintlayout.widget.ConstraintLayout>
BottomSheet.kt
package com.sample.bottomsheetvalue
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.inputmethod.EditorInfo
import android.widget.EditText
import androidx.lifecycle.ViewModelProvider
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
class BottomSheet : BottomSheetDialogFragment() {
lateinit var appState: AppState
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
activity?.run {
appState = ViewModelProvider(this).get(AppState::class.java)
}
val view = inflater.inflate(R.layout.fragment_bottom_sheet, container, false)
val editText = view.findViewById<EditText>(R.id.editText)
editText.setOnEditorActionListener { v, actionId, event ->
when (actionId) {
EditorInfo.IME_ACTION_DONE -> {
appState.value = editText.text.toString()
println(appState.value)
true
}
else -> false
}
}
return view
}
}
fragment_bottom_sheet.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".BottomSheet">
<EditText
android:id="#+id/editText"
android:layout_width="match_parent"
android:layout_height="500dp"
android:inputType="textPersonName"
android:ems="10"
android:imeOptions="actionDone"
/>
</FrameLayout>
Android Studio : 3.3.2
Add a Livedata to your view model class:
val data: MutableLiveData<String> = MutableLiveData("Initial Value")
And observe that in your fragment:
appState.data.observe(viewLifecycleOwner, Observer {
// Update your ui here
})
And also in your bottom sheet update the data:
data.postValue("newValue")
I am developing football statics app but when I run the code I am getting following exception
cannot find symbol
import yodgorbekkomilov.edgar.footballapp.databinding.FootballItemBindingImpl;
^
symbol: class FootballItemBindingImpl
below XML class
<?xml version="1.0" encoding="utf-8"?>
<layout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
<variable
name="viewModel"
type="yodgorbekkomilov.edgar.footballapp.ui.FootballViewModel" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:mutableText="#{viewModel.clubName}"
/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:mutableText="#{viewModel.countryName}"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:mutableText="#{viewModel.clubValue}"/>
<ImageView
app:imageUrl="#{viewModel.image}"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:id="#+id/clubImage"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:mutableText="#{viewModel.europeanTitle}"/>
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
below my FootballAdapter.kt where I have used databinding
import android.os.Build
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.annotation.RequiresApi
import androidx.databinding.DataBindingUtil
import androidx.recyclerview.widget.RecyclerView
import yodgorbekkomilov.edgar.footballapp.FootballResponse
import yodgorbekkomilov.edgar.footballapp.R
import yodgorbekkomilov.edgar.footballapp.databinding.FootballItemBinding
import yodgorbekkomilov.edgar.footballapp.ui.FootballViewModel
class FootballAdapter :
RecyclerView.Adapter<FootballAdapter.ViewHolder>() {
private lateinit var footballList: List<FootballResponse>
fun updatePostList(footballList: List<FootballResponse>) {
this.footballList = footballList
notifyDataSetChanged()
}
override fun onCreateViewHolder(
parent: ViewGroup,
viewType: Int
): FootballAdapter.ViewHolder {
val binding: FootballItemBinding = DataBindingUtil.inflate(
LayoutInflater.from(parent.context),
R.layout.football_item,
parent,
false
)
return ViewHolder(binding)
}
override fun getItemCount(): Int {
return footballList.size
}
#RequiresApi(Build.VERSION_CODES.O)
override fun onBindViewHolder(holder: FootballAdapter.ViewHolder, position: Int) {
holder.bind(footballList[position])
}
class ViewHolder(private val binding: FootballItemBinding) : RecyclerView.ViewHolder(binding.root) {
private val viewModel = FootballViewModel()
fun bind(model: FootballResponse) {
viewModel.bind(model)
binding.viewModel = viewModel
}
}
}
below FootballViewModel.kt
import androidx.lifecycle.MutableLiveData
import yodgorbekkomilov.edgar.footballapp.FootballResponse
import yodgorbekkomilov.edgar.footballapp.base.BaseViewModel
class FootballViewModel: BaseViewModel() {
private val clubName = MutableLiveData<String>()
private val countryName = MutableLiveData<String>()
private val clubValue = MutableLiveData<String>()
private val clubImage = MutableLiveData<String>()
private val europeanTitle = MutableLiveData<String>()
fun bind(football: FootballResponse){
clubName.value= football[0].name
countryName.value = football[1].country
clubValue.value = football[2].value.toString()
clubImage.value = football[3].image
europeanTitle.value = football[4].europeanTitles.toString()
}
fun getClubName():MutableLiveData<String>{
return clubName
}
fun getCountryName():MutableLiveData<String>{
return countryName
}
fun getClubValue():MutableLiveData<String>{
return clubValue
}
fun getImage():MutableLiveData<String> {
return clubImage
}
fun getEuropeanTitle():MutableLiveData<String> {
return europeanTitle
}
}
below my app.gradle
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
apply plugin: 'kotlin-kapt'
android {
compileSdkVersion 29
buildToolsVersion "30.0.0"
defaultConfig {
applicationId "yodgorbekkomilov.edgar.footballapp"
minSdkVersion 15
targetSdkVersion 29
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
buildFeatures{
dataBinding = true
viewBinding = true
}
kotlinOptions {
jvmTarget = '1.8'
}
}
dependencies {
implementation fileTree(dir: "libs", include: ["*.jar"])
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation 'androidx.core:core-ktx:1.3.0'
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'com.google.android.material:material:1.0.0'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
implementation 'androidx.navigation:navigation-fragment-ktx:2.1.0'
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
def room_version = "2.2.5"
def nav_version = "2.3.0"
//Navigation component
implementation "androidx.navigation:navigation-fragment-ktx:$nav_version"
implementation "androidx.navigation:navigation-ui-ktx:$nav_version"
//RxJava
implementation 'io.reactivex.rxjava3:rxandroid:3.0.0'
implementation 'io.reactivex.rxjava3:rxjava:3.0.0'
implementation "com.squareup.retrofit2:adapter-rxjava2:2.6.1"
implementation 'io.reactivex.rxjava2:rxandroid:2.1.1'
//Room
implementation "androidx.room:room-rxjava2:$room_version"
implementation 'com.google.android.material:material:1.1.0'
implementation 'androidx.cardview:cardview:1.0.0'
implementation 'androidx.recyclerview:recyclerview:1.1.0'
//Glide
implementation 'com.github.bumptech.glide:glide:4.11.0'
//Retrofit
implementation 'com.squareup.retrofit2:retrofit:2.6.2'
implementation 'com.squareup.retrofit2:converter-gson:2.6.2'
implementation 'androidx.navigation:navigation-ui-ktx:2.1.0'
//Dagger2
implementation 'com.google.dagger:dagger:2.27'
kapt 'com.google.dagger:dagger-compiler:2.27'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
}
what I have tried
1.invalidate cache restart
2. I have checked xml carefully it did not solve problem
3. tried following After migration to androidX: Databinding problem (Android Studio 4) and ActivityMainBindingImpl cannot be found in this one as well it did not solve my problem
I want to know where I am making mistake