Android Binding Adapter attribute not found - android

I am using a binding adapter to have mutable text in one of my views. I believe I have it implemented correctly (and it's working in other places), but for the case of mutableText, it's getting the error AAPT: error: attribute mutableText not found
I've looked through some other answers on here, but none of them have been able to solve the issue.
Here is my layout file:
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
<variable
name="viewModel"
type="com.example.nhlstats.ui.game.GameViewModel" />
</data>
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:id="#+id/awayTeam"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginTop="12dp">
<ImageView
android:id="#+id/awayTeamLogo"
android:layout_height="48dp"
android:layout_width="0dp"
android:layout_weight="1"
tools:src="#drawable/ic_launcher_background"/>
<TextView
android:id="#+id/awayTeamName"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="3"
android:layout_gravity="center_vertical"
app:mutableText="#{viewModel.getAwayTeamName()}"
tools:text="CHI Blackhawks"/>
<TextView
android:id="#+id/awayScore"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_gravity="center_vertical"
app:mutableText="#{viewModel.getAwayTeamScore().toString()}"
tools:text="0"/>
<TextView
android:id="#+id/gameTime"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_gravity="center_vertical"
app:mutableText="#{viewModel.getTimeRemaining()"
tools:text="14:26 3rd"/>
</LinearLayout>
<LinearLayout
android:id="#+id/homeTeam"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="12dp">
<ImageView
android:id="#+id/homeTeamLogo"
android:layout_height="48dp"
android:layout_width="0dp"
android:layout_weight="1"
tools:src="#drawable/ic_launcher_background"/>
<TextView
android:id="#+id/homeTeamName"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="3"
android:layout_gravity="center_vertical"
app:mutableText="#{viewModel.getHomeTeamName()}"
tools:text="CAR Hurricanes"/>
<TextView
android:id="#+id/homeScore"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_weight="2"
app:mutableText="#{viewModel.getHomeTeamScore().toString()}"
tools:text="4"/>
</LinearLayout>
</LinearLayout>
</layout>
and my BindingAdpater function:
#BindingAdapter("mutableText")
fun setMutableText(view: TextView, text: MutableLiveData<String>?) {
val parentActivity:AppCompatActivity? = view.getParentActivity()
if (parentActivity != null && text != null) {
text.observe(parentActivity, Observer { value ->
view.text = value?:""
})
}
}
GameViewModel:
class GameViewModel:BaseViewModel() {
private val awayTeamName = MutableLiveData<String>()
private val homeTeamName = MutableLiveData<String>()
private val awayTeamScore = MutableLiveData<Int>()
private val homeTeamScore = MutableLiveData<Int>()
private val timeRemaining = MutableLiveData<String>()
fun bind(response: Game) {
awayTeamName.value = response.gameData.teams.get(0).name
homeTeamName.value = response.gameData.teams.get(1).name
awayTeamScore.value = response.liveData.linescore.teams.get(1).goals
homeTeamScore.value = response.liveData.linescore.teams.get(0).goals
timeRemaining.value = response.liveData.linescore.currentPeriodOrdinal + " " + response.liveData.linescore.currentPeriodTimeRemaining
}
fun getAwayTeamName(): MutableLiveData<String> {
return awayTeamName
}
fun getHomeTeamName(): MutableLiveData<String> {
return homeTeamName
}
fun getAwayTeamScore(): MutableLiveData<Int> {
return awayTeamScore
}
fun getHomeTeamScore(): MutableLiveData<Int> {
return homeTeamScore
}
fun getTimeRemaining(): MutableLiveData<String> {
return timeRemaining
}
}
MainActivity:
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
private lateinit var viewModel: GameListViewModel
private var errorSnackbar: Snackbar? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
binding.gameList.layoutManager = LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)
viewModel = ViewModelProviders.of(this).get(GameListViewModel::class.java)
viewModel.errorMessage.observe(this, Observer { errorMessage ->
if (errorMessage != null)
showError(errorMessage)
else
hideError()
})
binding.viewModel = viewModel
}
private fun showError(#StringRes errorMessage:Int) {
errorSnackbar = Snackbar.make(binding.root, errorMessage, Snackbar.LENGTH_INDEFINITE)
errorSnackbar?.setAction(R.string.retry, viewModel.errorClickListener)
errorSnackbar?.show()
}
private fun hideError() {
errorSnackbar?.dismiss()
}
}
Thanks in advance.

As per your GameViewModel, I don't think you need any custom binding adapter.
Please check the edited code.
GameViewModel
class GameViewModel:BaseViewModel() {
// Make the variables public and access directly instead of exposing them via get() method.
val awayTeamName = MutableLiveData<String>()
val homeTeamName = MutableLiveData<String>()
val awayTeamScore = MutableLiveData<String>() // Change to String
val homeTeamScore = MutableLiveData<String>() // Change to String
val timeRemaining = MutableLiveData<String>()
fun bind(response: Game) {
awayTeamName.value = response.gameData.teams.get(0).name
homeTeamName.value = response.gameData.teams.get(1).name
awayTeamScore.value = response.liveData.linescore.teams.get(1).goals.toString() // Convert to String from here only instead of writing it in XML!
homeTeamScore.value = response.liveData.linescore.teams.get(0).goals.toString()
timeRemaining.value = response.liveData.linescore.currentPeriodOrdinal + " " + response.liveData.linescore.currentPeriodTimeRemaining
}
}
Your layout file(Notice I accessed the variables directly and removed the toString() as we are now only exposing MutableLiveData with String and yes, we are not using your custom binding adapter.
<data>
<variable
name="viewModel"
type="com.example.nhlstats.ui.game.GameViewModel" />
</data>
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:id="#+id/awayTeam"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginTop="12dp">
<ImageView
android:id="#+id/awayTeamLogo"
android:layout_height="48dp"
android:layout_width="0dp"
android:layout_weight="1"
tools:src="#drawable/ic_launcher_background"/>
<TextView
android:id="#+id/awayTeamName"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="3"
android:layout_gravity="center_vertical"
android:text="#{viewModel.awayTeamName}"
tools:text="CHI Blackhawks"/>
<TextView
android:id="#+id/awayScore"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_gravity="center_vertical"
android:text="#{viewModel.awayTeamScore}"
tools:text="0"/>
<TextView
android:id="#+id/gameTime"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_gravity="center_vertical"
android:text="#{viewModel.timeRemaining}"
tools:text="14:26 3rd"/>
</LinearLayout>
<LinearLayout
android:id="#+id/homeTeam"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="12dp">
<ImageView
android:id="#+id/homeTeamLogo"
android:layout_height="48dp"
android:layout_width="0dp"
android:layout_weight="1"
tools:src="#drawable/ic_launcher_background"/>
<TextView
android:id="#+id/homeTeamName"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="3"
android:layout_gravity="center_vertical"
android:text="#{viewModel.homeTeamName}"
tools:text="CAR Hurricanes"/>
<TextView
android:id="#+id/homeScore"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_weight="2"
android:text="#{viewModel.homeTeamScore}"
tools:text="4"/>
</LinearLayout>
</LinearLayout>
I haven't tested this so let me know how this goes for you.

Your binding adapter receives a nullable value, while the viewModel returns a non-null value. Change the text parameter to be non-null, just like the function in the viewModel returns it.
You can also do shorter encapsulation, for example:
private val _data = MutableLiveData<String>()
val data: LiveData<String>
get() = _data
This way you don't have to write long and boring getters like in Java.

Related

RecyclerView doesn't show any items even though getItemCount() returns the correct count in the adapter

everyone. I have a RecyclerView in which I want to display items. For this I implemented an adapter class and the required functions. I have 3 identical example data sets which I pass to the adapter and which are also correctly displayed as 3 in getItemCount(). However, my problem is that I can't see anything. The RecyclerView remains empty. I also don't get any errors in the terminal/debugger, everything is correct. Have I made a mistake and perhaps forgot something?
Here is my OverviewActivity containing the RecyclerView:
class OverviewActivity : AppCompatActivity() {
private lateinit var resultsAdapter: ResultsAdapter
private lateinit var listResults : ArrayList<HouseModel>
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_overview)
listResults = ArrayList()
var resultRv: RecyclerView = findViewById(R.id.result_rv)
resultRv.layoutManager = LinearLayoutManager(this)
resultsAdapter = ResultsAdapter(this, listResults)
resultRv.adapter = resultsAdapter
//TEST DATA
listResults.add(HouseModel("Abador",R.drawable.house,R.drawable.alle,"Bella Vista, PY","650","Schönes, neu renoviertes Haus. Mit neuestem Standard. Kann besichtigt werden"))
listResults.add(HouseModel("Abador",R.drawable.house,R.drawable.alle,"Bella Vista, PY","650","Schönes, neu renoviertes Haus. Mit neuestem Standard. Kann besichtigt werden"))
listResults.add(HouseModel("Abador",R.drawable.house,R.drawable.alle,"Bella Vista, PY","650","Schönes, neu renoviertes Haus. Mit neuestem Standard. Kann besichtigt werden"))
resultsAdapter.notifyDataSetChanged()
... } }
Model class:
data class HouseModel(
var senderName: String,
var mainImg : Int,
var senderImg: Int,
var place: String,
var price: String,
var desc: String,
)
ResultsAdapter:
class ResultsAdapter(private val context: Context, private val resultsList: ArrayList<HouseModel>): RecyclerView.Adapter<ResultsAdapter.ViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ResultsAdapter.ViewHolder {
val inflateView = LayoutInflater.from(context).inflate(R.layout.result_list_rv,parent,false)
return ViewHolder(inflateView)
}
class ViewHolder(view: View): RecyclerView.ViewHolder(view) {
val mainImg: ImageView = view.findViewById(R.id.rv_list_main_img)
val senderImg: ImageView = view.findViewById(R.id.main_list_rv_sender_img)
val senderName: TextView = view.findViewById(R.id.main_list_rv_sender_name)
val place: TextView = view.findViewById(R.id.main_list_rv_place)
val desc: TextView = view.findViewById(R.id.main_list_rv_desc)
val price: TextView = view.findViewById(R.id.main_list_rv_price)
}
override fun onBindViewHolder(holder: ResultsAdapter.ViewHolder, position: Int) {
holder.mainImg.setImageResource(resultsList[position].mainImg)
holder.senderImg.setImageResource(resultsList[position].senderImg)
holder.senderName.text = resultsList[position].senderName
holder.place.text = resultsList[position].place
holder.desc.text = resultsList[position].desc
holder.price.text = resultsList[position].price
}
override fun getItemCount(): Int {
println("ITEMS: ${resultsList.size}")
// SHOWS I/System.out: ITEMS: 3
return resultsList.size
}
}
UPDATE
RecyclerView Code:
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/result_rv"
android:layout_marginEnd="20dp"
android:layout_marginStart="20dp"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="16dp">
</androidx.recyclerview.widget.RecyclerView>
And my code for result_list_rv.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<androidx.cardview.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:elevation="6dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ImageView
android:id="#+id/rv_list_main_img"
android:src="#drawable/longtime"
android:layout_width="match_parent"
android:layout_height="wrap_content"></ImageView>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginStart="20dp">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical">
<ImageView
android:id="#+id/main_list_rv_sender_img"
android:background="#drawable/imageborder"
android:padding="10dp"
android:src="#drawable/shorttime"
android:layout_width="100dp"
android:layout_height="100dp"></ImageView>
<TextView
android:id="#+id/main_list_rv_sender_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Abador"
android:layout_marginTop="16dp"
android:fontFamily="#font/baumans"
android:textSize="23sp"
android:textStyle="bold"></TextView>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="70dp"
android:orientation="vertical"
android:layout_gravity="bottom"
android:layout_marginEnd="20dp"
android:gravity="right">
<TextView
android:id="#+id/main_list_rv_place"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Bella Vista, PY"
android:textSize="16sp">
</TextView>
<TextView
android:id="#+id/main_list_rv_price"
android:layout_marginTop="20dp"
android:gravity="bottom"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="600 USD/mtl"
android:textSize="23sp"
android:textStyle="bold"></TextView>
</LinearLayout>
</LinearLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginEnd="20dp"
android:layout_marginStart="20dp"
android:layout_marginTop="20dp"
android:gravity="center"
android:layout_gravity="center">
<TextView
android:id="#+id/main_list_rv_desc"
android:layout_width="260dp"
android:layout_height="60dp"
android:layout_alignParentLeft="true"
android:gravity="left"
android:maxLength="200"
android:maxLines="2"
android:text="Beschreibung Haus sdf sdfe Beschreibung Haus sdf sdfe"
android:textSize="17sp"
android:textStyle="bold"></TextView>
<ImageButton
android:id="#+id/main_list_rv_message_btn"
android:layout_width="60dp"
android:layout_height="60dp"
android:layout_alignParentRight="true"
android:backgroundTint="#color/white"
android:scaleType="centerCrop"
android:src="#drawable/send"></ImageButton>
</RelativeLayout>
</LinearLayout>
</androidx.cardview.widget.CardView>
I've reviewed your code and I think the problem is in the result_list_rv.xml file,
try to set the main linear layout width = match_parent and last RelativeLayout height = wrap_content

How to display Fullscreen image from RecyclerView in Kotlin?

i am getting data from API and display it in RecyclerView and everything is working fine
but now i'm a bit confused on how can i display the images that i'm getting from the API in full screen if the user clicked on it
this is the activity:
LlmNoteDetailsActivity:
class LlmNoteDetailsActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.fragment_ilm_note_detail)
val EventName = intent.getStringExtra("EventName")
val EventLink = intent.getStringExtra("EventLink")
val isFavourite = intent.getBooleanExtra("isFavourite" , false)
val eventId = intent.getIntExtra("eventId",0)
val eventDate = intent.getStringExtra("eventDate")
val eventDescription = intent.getStringExtra("eventDescription")
val eventLocation = intent.getStringExtra("eventLocation")
val eventLink = intent.getStringExtra("eventLink")
val EventImage = intent.getStringExtra("EventImage")
val ImageViewTop: ImageView = findViewById(R.id.ImageViewTop)
val LinkText: TextView = findViewById(R.id.LocationTx)
val EventNameText: TextView = findViewById(R.id.EventNameText)
val eventDateTxt: TextView = findViewById(R.id.eventDateTxt)
val eventDescriptionText: TextView = findViewById(R.id.eventDescriptionText)
val butttoRegiiste: Button = findViewById(R.id.butttoRegiiste)
val detailback_btn: ImageButton = findViewById(R.id.detailback_btn)
LinkText.text = EventLink
EventNameText.text = EventName
eventDateTxt.text = eventDate
eventDescriptionText.text = eventDescription
butttoRegiiste.setOnClickListener {
openLinkInBrowser(eventLink!!)
}
detailback_btn.setOnClickListener {
onBackPressed()
}
ImageViewTop.setOnClickListener {
//display image in fullscreen
}
Picasso.get()
.load(EventImage)
.error(R.drawable.qiblacompass)
.memoryPolicy(MemoryPolicy.NO_CACHE, MemoryPolicy.NO_STORE)
.networkPolicy(NetworkPolicy.NO_CACHE, NetworkPolicy.NO_STORE)
.into(ImageViewTop)
}
fun openLinkInBrowser(url: String) {
try {
val url = if (Uri.parse(url).scheme == null || !url.startsWith("https://") && !url.startsWith(
"http://"
)) {
"https://$url"
} else url
val webPage: Uri = Uri.parse(url)
val intent = Intent(Intent.ACTION_VIEW, webPage)
this.startActivity(intent)
} catch (e: Exception) {
e.printStackTrace()
}
}
}
this its layout(fragment_ilm_note_detail):
<?xml version="1.0" encoding="utf-8"?>
<ScrollView
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="wrap_content"
android:layout_height="wrap_content">
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageView
android:layout_marginTop="-100dp"
android:id="#+id/ImageViewTop"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:contentDescription="login background"
android:src="#drawable/sampledetail" />
<com.google.android.flexbox.FlexboxLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="350dp"
android:layout_alignParentBottom="true"
android:orientation="vertical"
app:flexDirection="column">
<LinearLayout
android:background="#drawable/rounded_background"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingTop="#dimen/dimen_16"
android:paddingLeft="#dimen/dimen_16"
android:paddingRight="#dimen/dimen_16"
android:elevation="5dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
android:orientation="vertical"
android:padding="20dp">
<com.google.android.flexbox.FlexboxLayout
android:layout_width="match_parent"
app:justifyContent="space_between"
android:layout_height="wrap_content">
<com.google.android.flexbox.FlexboxLayout
app:alignItems="center"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageView
android:layout_marginRight="10dp"
android:src="#drawable/pin"
android:layout_width="18dp"
android:layout_height="25dp"/>
<TextView
android:id="#+id/LocationTx"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="#font/poppins"
android:text="Ara Damansara"
android:textColor="#color/black"
android:textSize="15sp" />
</com.google.android.flexbox.FlexboxLayout>
<ImageView
android:layout_marginRight="10dp"
android:src="#drawable/star"
android:layout_width="25dp"
android:layout_height="25dp"/>
</com.google.android.flexbox.FlexboxLayout>
<TextView
android:id="#+id/EventNameText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:fontFamily="#font/poppins"
android:text="Perfecting My Solah"
android:textColor="#color/teal_600"
android:textSize="20sp"
android:textStyle="bold" />
<TextView
android:id="#+id/eventDateTxt"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="3dp"
android:fontFamily="#font/poppins_semibold"
android:text="Sabtu 15 Ogos 2021"
android:textColor="#color/black"
android:textSize="15sp"
android:textStyle="bold" />
<TextView
android:id="#+id/eventDescriptionText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="15dp"
android:fontFamily="#font/poppins"
android:text=""
android:textColor="#color/black"
android:textSize="10sp" />
<Button
android:id="#+id/butttoRegiiste"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginVertical="#dimen/dimen_32"
android:backgroundTint="#FFB248"
android:textAllCaps="false"
android:text="Link to Register"
app:rippleColor="#FFB248" />
</LinearLayout>
</LinearLayout>
</com.google.android.flexbox.FlexboxLayout>
<ImageButton
android:id="#+id/detailback_btn"
android:layout_width="18dp"
android:layout_marginLeft="#dimen/_20sdp"
android:layout_marginTop="#dimen/_50sdp"
android:layout_height="20dp"
android:background="#drawable/chevron_left" />
</RelativeLayout>
</ScrollView>
this is the adapter:
IimfinderAdapter:
class IimfinderAdapter(var countryList: List<ilmFinders>, private val iimfinderAdapterCallback: MainActivity): RecyclerView.Adapter<IimfinderAdapter.ViewHolder>(){
lateinit var context: Context
val CategoryID: Int = AppPreferences.heightInCentimeters ?: 170
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): IimfinderAdapter.ViewHolder {
context = parent.context!!
val view = LayoutInflater.from(context).inflate(R.layout.list_item2, parent, false)
return ViewHolder(view)
}
override fun getItemCount(): Int {
return countryList[CategoryID].ilmFinders.size
}
override fun onBindViewHolder(holder: IimfinderAdapter.ViewHolder, position: Int) {
var categoryIDis = countryList[CategoryID].categoryID
Log.e("CategoryID",categoryIDis.toString())
Log.e("Categorycount ",countryList[CategoryID].ilmFinders.size.toString())
holder.eventName.text = countryList[CategoryID].ilmFinders[position].eventName
holder.eventLink.text = countryList[CategoryID].ilmFinders[position].eventLink
Log.d("ggggggggggggggg", countryList[CategoryID].ilmFinders[position].eventName)
var ilmfinderimage = countryList[CategoryID].ilmFinders[position].eventPhoto.toString()
var newatri = ilmfinderimage.replace("[", "").replace("" +
"]", "")
Log.d("ffffffffff", newatri)
Picasso.get()
.load(newatri)
.error(R.drawable.qiblacompass)
.memoryPolicy(MemoryPolicy.NO_CACHE, MemoryPolicy.NO_STORE)
.networkPolicy(NetworkPolicy.NO_CACHE, NetworkPolicy.NO_STORE)
.into(holder.eventPhoto)
holder.list_card.setOnClickListener {
countryList[CategoryID].ilmFinders[position].eventName
countryList[CategoryID].ilmFinders[position].eventLink
newatri
//context.startActivity(Intent(context, LlmNoteDetailsActivity::class.java))
var intent = Intent(context, LlmNoteDetailsActivity::class.java)
intent.putExtra("EventName",countryList[CategoryID].ilmFinders[position].eventName)
intent.putExtra("EventLink",countryList[CategoryID].ilmFinders[position].eventLink)
intent.putExtra("isFavourite",countryList[CategoryID].ilmFinders[position].isFavourite)
intent.putExtra("eventId",countryList[CategoryID].ilmFinders[position].eventId)
intent.putExtra("eventDate",countryList[CategoryID].ilmFinders[position].eventDate)
intent.putExtra("eventDescription",countryList[CategoryID].ilmFinders[position].eventDescription)
intent.putExtra("eventLocation",countryList[CategoryID].ilmFinders[position].eventLocation)
intent.putExtra("eventLink",countryList[CategoryID].ilmFinders[position].eventLink)
intent.putExtra("EventImage",newatri)
context.startActivity(intent)
}
}
class ViewHolder(itemView: View): RecyclerView.ViewHolder(itemView){
val eventName: TextView = itemView.findViewById(R.id.title_tv2)
val eventLink: TextView = itemView.findViewById(R.id.tv_url2)
val eventPhoto: ImageView = itemView.findViewById(R.id.thumbnail_tv2)
val list_card: ConstraintLayout = itemView.findViewById(R.id.list_constraint)
}
}
and this is its layout(list_item2):
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout 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:id="#+id/frame_layout"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<com.bigman.wmzx.customcardview.library.CardView
android:id="#+id/list_card"
android:layout_width="wrap_content"
android:layout_height="250dp"
app:cardCornerRadius="4dp"
app:contentPadding="8dp">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="#+id/list_constraint"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageView
android:id="#+id/thumbnail_tv2"
android:layout_width="150dp"
android:layout_height="150dp"
android:src="#drawable/insta"
app:layout_constraintTop_toTopOf="parent"
tools:ignore="MissingConstraints"
/>
<TextView
android:id="#+id/title_tv2"
android:layout_width="150dp"
android:textColor="#4B4B4B"
android:fontFamily="#font/poppins"
android:textStyle="bold"
android:textSize="12dp"
android:maxLength="20"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/thumbnail_tv2" />
<TextView
android:id="#+id/tv_url2"
android:maxLength="20"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:drawablePadding="10dp"
android:drawableLeft="#drawable/linkiimfinder"
android:layout_marginTop="8dp"
android:fontFamily="#font/poppins"
android:text="TextView"
android:textSize="12sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/title_tv2"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
</com.bigman.wmzx.customcardview.library.CardView>
</FrameLayout>
so in (fragment_ilm_note_detail) layout there is an ImageView (id:ImageViewTop) i'm trying to display this image in full screen if the user click on it
i tried to create new activity and layout to show only the image and i added setOnClickListener if the user click the image but i faced few errors
what is the easiest way to achieve this?
"please be patient with me becasue i'm new to Kotlin"
i have been searching online for almost 3 days for this problem and i couldn't find the right solution for my case that's why i'm asking here, please relate to my code if you have a solution
You don't create a new activity inside holder.list_card.setOnClickListener. Instead, create a new fragment, with it's own xml layout with fullScreen imageView. For example, the kotlin code for fragment:
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import androidx.fragment.app.Fragment
class FullScreenImageFragment: Fragment() {
companion object {
val TAG: String = "FullScreenImageFragment"
val INPUT_IMAGE: String = "INPUT_IMAGE"
fun getInstance(inputImageUrl: String): FullScreenImageFragment {
val fullScreenImageFragment = FullScreenImageFragment()
val args = Bundle()
args.putString(INPUT_IMAGE, inputImageUrl)
fullScreenImageFragment.arguments = args
return fullScreenImageFragment
}
}
private var inputImageUrl: String = ""
private lateinit var fragmentRootView: View
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
// return super.onCreateView(inflater, container, savedInstanceState)
this.fragmentRootView = inflater.inflate(R.layout.full_screen_image, container, false)
this.fragmentRootView.setOnClickListener { /* empty listener to prevent click propagation */ }
return fragmentRootView
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
initArgument()
val imagePreview: ImageView = fragmentRootView.findViewById(R.id.imagePreview)
Picasso.get()
.load(inputImageUrl)
.error(R.drawable.qiblacompass)
.memoryPolicy(MemoryPolicy.NO_CACHE, MemoryPolicy.NO_STORE)
.networkPolicy(NetworkPolicy.NO_CACHE, NetworkPolicy.NO_STORE)
.into(imagePreview)
}
private fun initArgument() {
if(arguments!=null) {
this.inputImageUrl = requireArguments().getString(INPUT_IMAGE, "")
}
}
}
The xml layout:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="#+id/imagePreview"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
And finally, inside your adapter:
holder.list_card.setOnClickListener{
val activity: Activity = holder.context as Activity
activity.supportFragmentManager.beginTransaction()
.replace(android.R.id.content, FullScreenImageFragment.getInstance(newatri)) // "www.some_image_url.com"
.commit()
}
This should do the work. Consider studying some more on fragments to further modify the code.
SOLUTION:
so what i did here:
i created new Activity with its layout:
Activity:
val detailback_btn: ImageButton = findViewById(R.id.detailback_btn2)
val EventImage = intent.getStringExtra("EventImage")
val thumbnail_tv22: ImageView = findViewById(R.id.thumbnail_tv22)
Picasso.get()
.load(EventImage)
.error(R.drawable.qiblacompass)
.memoryPolicy(MemoryPolicy.NO_CACHE, MemoryPolicy.NO_STORE)
.networkPolicy(NetworkPolicy.NO_CACHE, NetworkPolicy.NO_STORE)
.into(thumbnail_tv22)
detailback_btn.setOnClickListener {
onBackPressed()
}
}
i passed the image "val EventImage = intent.getStringExtra("EventImage")"
and from "LlmNoteDetailsActivity" i added setOnClickListener to open new Activity and passed the image:
LlmNoteDetailsActivity:
ImageViewTop.setOnClickListener {
val intent = Intent(this, LoginActivityV2::class.java)
intent.putExtra("EventImage",EventImage)
startActivity(intent)
}

Facebook Shimmer library with Paging 3 library

In my app I load data from API which is using paginating so I have to use paging 3 library
and I use facebook shimmer library to show shimmer effect when items are being loaded
but the problem is always shimmer effect is shown even when items are completely loaded
ArticlePagingAdapter.kt
class ArticlePagingAdapter(private val listener: OnItemClickListener) :
PagingDataAdapter<Article, ArticlePagingAdapter.ViewHolder>(ArticleDiffUtil()) {
private val TAG = ArticlePagingAdapter::class.simpleName
private lateinit var context: Context
var showShimmer: Boolean = true
inner class ViewHolder(itemView: View) :
RecyclerView.ViewHolder(itemView), View.OnClickListener {
lateinit var item: Article
val shimmerLayout: ShimmerFrameLayout = itemView.shimmer_layout
val articleImageView: ShapeableImageView = itemView.findViewById(R.id.article_image_view)
val articleTitleTextView: TextView = itemView.findViewById(R.id.article_title_text_view)
val articleEstimatedTextView: TextView =
itemView.findViewById(R.id.article_estimated_read_time_text_view)
val clockImageView: ImageView = itemView.findViewById(R.id.clock_icon)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
if (showShimmer) {
holder.shimmerLayout.startShimmer()
} else {
holder.shimmerLayout.stopShimmer()
holder.shimmerLayout.setShimmer(null)
holder.articleImageView.background = null
holder.clockImageView.background = null
holder.articleEstimatedTextView.background = null
holder.articleTitleTextView.background = null
val item = getItem(position)
if (item != null) {
Log.d(TAG, "position $position, isNull != null ")
holder.item = item
holder.articleTitleTextView.text = item.title
holder.articleEstimatedTextView.text = (item.estimatedReadingTime.toString()
val requestOptions = RequestOptions().transform(
CenterCrop(), RoundedCorners(
context.resources.getDimension(R.dimen.item_article_image_view_radius)
.toInt()
)
)
Glide.with(context).load(item.imageUrl!!.toUri())
.placeholder(R.drawable.ic_article_placeholder).apply(requestOptions)
.into(holder.articleImageView)
holder.clockImageView.setImageResource(R.drawable.ic_clock)
} else {
Log.d(TAG, "position $position, isNull= null ")
}
}
}
}
ArticleFragmnet.kt
class LatestArticlesFragment : Fragment(), ArticlePagingAdapter.OnItemClickListener {
val TAG = LatestArticlesFragment::class.simpleName
lateinit var binding: FragmentLatestArticlesBinding
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
// some unrelated code
val adapter = ArticlePagingAdapter(this)
binding.recyclerView.adapter = adapter
viewModel.getArticles().observe(viewLifecycleOwner) { data ->
lifecycleScope.launch {
adapter.submitData(data)
Log.d(TAG,"data ${data.toString()}")
adapter.showShimmer = false
}
}
}
}
ArticleFragmentViewModel.kt
class LatestArticlesFragmentViewModel #AssistedInject constructor(
private val repository: ArticleRepository, ...) : ViewModel() {
fun getArticles(): LiveData<PagingData<Article>> {
currentArticles = repository.getArticlesStream().cachedIn(viewModelScope)
return currentArticles?.asLiveData()!!
}
}
item_article.xml
<?xml version="1.0" encoding="utf-8"?>
<com.google.android.material.card.MaterialCardView 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"
style="#style/card_view_style"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="#dimen/small_margin"
android:clipToPadding="false"
android:paddingBottom="#dimen/_2sdp">
<com.facebook.shimmer.ShimmerFrameLayout
android:id="#+id/shimmer_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="#dimen/very_small_padding">
<com.google.android.material.imageview.ShapeableImageView
android:id="#+id/article_image_view"
android:layout_width="0dp"
android:layout_height="#dimen/_70sdp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintDimensionRatio="3:2"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="#id/article_title_text_view"
app:layout_constraintTop_toTopOf="parent"
tools:src="#drawable/ic_icon" />
<TextView
android:id="#+id/article_title_text_view"
style="#style/Widget.MyWidget.TextView.VerySmall.Bold"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="#dimen/very_small_margin"
android:layout_marginEnd="#dimen/very_small_margin"
android:ellipsize="end"
android:gravity="start"
android:maxLines="2"
android:minLines="2"
android:textAlignment="textStart"
android:textColor="?attr/textColor"
app:layout_constraintBottom_toTopOf="#id/clock_icon"
app:layout_constraintEnd_toStartOf="#id/article_image_view"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="#id/article_image_view"
tools:text="This is a dummy title" />
<TextView
android:id="#+id/article_estimated_read_time_text_view"
style="#style/Widget.MyWidget.TextView.VerySmall"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="#dimen/very_small_margin"
android:background="#color/shimmer_background"
android:textColor="?attr/textColor"
app:layout_constraintBottom_toBottomOf="#id/article_image_view"
app:layout_constraintEnd_toEndOf="#id/article_title_text_view"
app:layout_constraintStart_toEndOf="#id/clock_icon"
app:layout_constraintTop_toBottomOf="#id/article_title_text_view"
tools:text="5 min" />
<ImageView
android:id="#+id/clock_icon"
android:layout_width="#dimen/_10sdp"
android:layout_height="#dimen/_10sdp"
android:background="#color/shimmer_background"
app:layout_constraintBottom_toBottomOf="#id/article_estimated_read_time_text_view"
app:layout_constraintEnd_toStartOf="#id/article_estimated_read_time_text_view"
app:layout_constraintStart_toStartOf="#id/article_title_text_view"
app:layout_constraintTop_toTopOf="#id/article_estimated_read_time_text_view"
tools:src="#drawable/ic_clock" />
</androidx.constraintlayout.widget.ConstraintLayout>
</com.facebook.shimmer.ShimmerFrameLayout>
</com.google.android.material.card.MaterialCardView>
fragment_article_layout.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"
xmlns:tools="http://schemas.android.com/tools">
<data>
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="#+id/root_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?attr/articleBackground">
<TextView
android:id="#+id/article_text_view"
style="#style/Widget.MyWidget.TextView.Large.Bold"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="#dimen/medium_margin"
android:text="#string/articles"
android:textColor="?attr/textColor"
app:layout_constraintStart_toStartOf="#id/left_guideline"
app:layout_constraintTop_toTopOf="parent" />
<View
android:id="#+id/line_separator"
style="#style/Divider"
android:layout_marginStart="#dimen/_10sdp"
app:layout_constraintBottom_toBottomOf="#id/article_text_view"
app:layout_constraintEnd_toEndOf="#id/right_guideline"
app:layout_constraintStart_toEndOf="#id/article_text_view"
app:layout_constraintTop_toTopOf="#id/article_text_view"
app:layout_constraintVertical_chainStyle="packed" />
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="0dp"
android:background="#android:color/transparent"
android:clipToPadding="false"
android:orientation="vertical"
android:paddingHorizontal="#dimen/small_padding"
android:paddingTop="#dimen/small_padding"
android:paddingBottom="#dimen/small_padding"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="#id/article_text_view"
tools:itemCount="8"
tools:listitem="#layout/item_article" />
<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scaleType="fitXY"
android:src="?attr/listFadeBackground"
app:layout_constraintTop_toTopOf="#id/recycler_view" />
<androidx.constraintlayout.widget.Guideline
android:id="#+id/left_guideline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.03" />
<androidx.constraintlayout.widget.Guideline
android:id="#+id/right_guideline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.97" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>

RecyclerView not adding item loaded from Cloud Firestore Kotlin

I am loading in Data from Cloud Firestore. That data is then being added as an Item to a RecyclerView and should be displayed on the screen. However, the RecyclerView remains empty.
The data is loaded in correctly from Cloud Firestore (I can tell because of the logs I added which are shown below).
So I cannot find out why the data is not being added to the RecyclerView correctly and displayed?
ActiveOrderActivity.kt
class ActiveOrderActivity : AppCompatActivity() {
private val aorderList = ArrayList<ActiveOrderModel>()
private val adapter = AOrdersAdapter(aorderList)
/* Access a Cloud Firestore instance from the Activity. */
val db = Firebase.firestore
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_active_order)
recyclerview.adapter = adapter
recyclerview.layoutManager = LinearLayoutManager(this)
recyclerview.setHasFixedSize(true)
db.collection("Orders - 18.3.2021")
.get()
.addOnSuccessListener { result ->
for (document in result) {
Log.i("", "IN LOOP FOR DOCUMENT: ActiveOrderActivity.\n")
val customerName = document.getField<String>("customer Name")
Log.i("", "$customerName: ActiveOrderActivity.\n")
val customerNumber = document.getField<String>("customer Number")
val customerPostal = document.getField<String>("eircode")
val customerAddress = document.getField<String>("address")
val paymentAmount = document.getField<String>("payment Amount")
val paymentType = document.getField<String>("payment Total")
val newItem = ActiveOrderModel(customerName = customerName,customerNumber = customerNumber,customerPostal = customerPostal,customerAddress = customerAddress,paymentAmount = paymentAmount,paymentType = paymentType)
aorderList.add(INDEX,newItem)
adapter.notifyItemInserted(INDEX)
}
}
}
}
AOrdersAdapter.kt
class AOrdersAdapter(private val aorderList: List<ActiveOrderModel> ) : RecyclerView.Adapter<AOrdersAdapter.AOrderViewHolder>() {
class AOrderViewHolder(view: View) : RecyclerView.ViewHolder(view) {
val nameView = view.nameView
val addressView = view.address1View
val mobileView = view.mobileView
val eircodeView = view.eircodeView
val paymentView = view.paymentView
val paymentAmountView = view.paymentAmountView
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): AOrderViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.active_order_item, parent, false)
return AOrderViewHolder(view)
}
override fun getItemCount(): Int {
return aorderList.size
}
override fun onBindViewHolder(holder: AOrderViewHolder, position: Int) {
val currentItem = aorderList[position]
holder.nameView.text = currentItem.customerName
holder.addressView.text = currentItem.customerNumber
holder.mobileView.text = currentItem.customerPostal
holder.eircodeView.text = currentItem.customerAddress
holder.paymentAmountView.text = currentItem.paymentAmount
holder.paymentView.text = currentItem.paymentType
}
}
activity_active_order.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=".MainBody.dashboard.ordersActivites.ActiveOrderActivity">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/recyclerview"
android:layout_width="wrap_content"
android:layout_height="699dp"
android:layout_marginStart="16dp"
android:layout_marginTop="32dp"
android:layout_marginEnd="16dp"
android:clipToPadding="false"
android:padding="8dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.501"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/floatingActionButton"
app:layout_constraintVertical_bias="0.0"
tools:listitem="#layout/active_order_item" />
<androidx.appcompat.widget.AppCompatButton
android:id="#+id/floatingActionButton"
android:layout_width="307dp"
android:layout_height="68dp"
android:layout_marginTop="88dp"
android:background="#drawable/pizaa_button2"
android:text="Main Menu"
android:textColor="#color/white"
android:textSize="16sp"
android:textStyle="bold"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
active_order_item.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:id="#+id/rowConstraintLayout"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<androidx.cardview.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:padding="16dp"
android:layout_margin="4dp"
app:cardElevation="10dp"
app:cardCornerRadius="8dp"
app:cardPreventCornerOverlap="false">
<RelativeLayout
android:layout_width="800dp"
android:layout_height="match_parent"
android:padding="12dp">
<TextView
android:id="#+id/nameView"
android:layout_width="223dp"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_marginStart="6dp"
android:layout_marginEnd="0dp"
android:text="George Matthews"
android:textColor="#color/shopColour"
android:textSize="20sp"
android:textStyle="bold" />
<TextView
android:id="#+id/address1View"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#+id/nameView"
android:layout_alignParentStart="true"
android:layout_marginStart="6dp"
android:layout_marginLeft="2dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="6dp"
android:text="123 Fakelands,\nHigher up Road,\nDublin"
android:textColor="#color/logoYellow"
android:textSize="20sp"
android:textStyle="bold" />
<TextView
android:id="#+id/mobileView"
android:layout_width="144dp"
android:layout_height="wrap_content"
android:layout_alignTop="#+id/productPriceView"
android:layout_marginStart="20dp"
android:layout_marginLeft="2dp"
android:layout_marginTop="1dp"
android:layout_marginEnd="100dp"
android:layout_toEndOf="#+id/nameView"
android:text="089 215 2121"
android:textColor="#color/shopColour"
android:textSize="20sp"
android:textStyle="bold" />
<TextView
android:id="#+id/eircodeView"
android:layout_width="87dp"
android:layout_height="wrap_content"
android:layout_below="#+id/mobileView"
android:layout_alignEnd="#+id/mobileView"
android:layout_marginStart="43dp"
android:layout_marginLeft="0dp"
android:layout_marginTop="11dp"
android:layout_marginEnd="16dp"
android:layout_marginBottom="1dp"
android:layout_toEndOf="#+id/nameView"
android:text="A96 K4D8"
android:textColor="#color/logoYellow"
android:textSize="20sp"
android:textStyle="bold" />
<TextView
android:id="#+id/paymentView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignTop="#+id/productPriceView"
android:layout_marginStart="20dp"
android:layout_marginLeft="2dp"
android:layout_marginTop="1dp"
android:layout_marginEnd="100dp"
android:layout_toEndOf="#+id/mobileView"
android:gravity="center"
android:text="Frank's Website"
android:textColor="#color/shopColour"
android:textSize="20sp"
android:textStyle="bold" />
<TextView
android:id="#+id/paymentAmountView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#+id/paymentView"
android:layout_alignEnd="#+id/paymentView"
android:layout_marginStart="144dp"
android:layout_marginLeft="0dp"
android:layout_marginTop="12dp"
android:layout_marginEnd="-5dp"
android:layout_marginBottom="1dp"
android:layout_toEndOf="#+id/eircodeView"
android:gravity="center"
android:text="47.00"
android:textColor="#color/logoYellow"
android:textSize="20sp"
android:textStyle="bold" />
</RelativeLayout>
</androidx.cardview.widget.CardView>
</androidx.constraintlayout.widget.ConstraintLayout>
ActiveOrderModel.kt
data class ActiveOrderModel(
val customerName: String? = null,
val customerNumber: String? = null,
val customerPostal: String? = null,
val customerAddress: String? = null,
val paymentAmount: String? = null,
val paymentType: String? = null )
Here the running terminal shows that the data has been loaded correctly from the Cloud Firestore and the loop is working to iterate through all the entries in the Collection. Now each document should be added to the RecyclerView but the Recycler View is empty as shown below.
You need to update list in adapter to get desired result. Create a method in adapter as below -
fun updateList(list: List<ActiveOrderModel> ) {
this.aorderList = list
notifyDataSetChanged()
}
Update below lines in your activity
aorderList.add(INDEX,newItem)
adapter.updateList(aorderList)
adapter.notifyItemInserted(INDEX)
try this
fun initRecyclerView() {
mainRecycler.setLayoutManager(LinearLayoutManager(context))
var linearLayoutManager: LinearLayoutManager? = LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false)
mainRecycler?.layoutManager = linearLayoutManager
val itemDecorator = VerticalSpacingItemDecorator(20)
mainRecycler.addItemDecoration(itemDecorator)
adapter = AOrdersAdapter(aorderList)
mainRecycler.setAdapter(adapter)
}
and this
for (document in result) {
Log.i("", "IN LOOP FOR DOCUMENT: ActiveOrderActivity.\n")
val customerName = document.getField<String>("customer Name")
Log.i("", "$customerName: ActiveOrderActivity.\n")
val customerNumber = document.getField<String>("customer Number")
val customerPostal = document.getField<String>("eircode")
val customerAddress = document.getField<String>("address")
val paymentAmount = document.getField<String>("payment Amount")
val paymentType = document.getField<String>("payment Total")
val newItem = ActiveOrderModel(customerName = customerName,customerNumber = customerNumber,customerPostal = customerPostal,customerAddress = customerAddress,paymentAmount = paymentAmount,paymentType = paymentType)
aorderList.add(INDEX,newItem)
adapter.notifyItemInserted(INDEX)
}
adapter?.notifyDataSetChanged()
use adapter?.notifyDataSetChanged()
and must check your arraylist not be empty.

Populate UI from a ViewModel in Kotlin

This is the first time I am using Android Architecture. I have decided to go with MVVM structure but I am stuck at the point where I have no idea how to set the textViews in my XML with the data I pull from the database.
Checking the logs, I have seen that the function calls to my database (Firestore) does retrieve the correct data documents. Do I set the UI elements from the Activity,ViewModel or the Fragment? (Please note that I'm using a Navigation bar and controller)
Please assist me, my code is as follows:
My Single Activity:
class HomeActivity : AppCompatActivity() {
// Create the three objects for the fragments
lateinit var homeFragment: HomeFragment
lateinit var visitsFragment: VisitsFragment
lateinit var profileFragment: ProfileFragment
// ViewModels
lateinit var customerViewModel: CustomerViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_home)
// Initialize the bottom nav bar and navigation controller and then merge them
val bottomNavigationView = findViewById<BottomNavigationView>(R.id.btm_nav)
val navigationController = findNavController(R.id.fragmentHost)
bottomNavigationView.setupWithNavController(navigationController)
// Create app bar config object so that you can rename the bar ontop with the tab name
val appBarConfiguration = AppBarConfiguration(setOf(R.id.homeFragment,R.id.visitsFragment,R.id.profileFragment))
setupActionBarWithNavController(navigationController,appBarConfiguration)
// View Model
customerViewModel = ViewModelProvider(this).get(CustomerViewModel::class.java)
customerViewModel.retrieveCustomer().observe(this, Observer { it })
}
// This function creates the menu object by inflating it with the resource we gave it (menu resource).
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
menuInflater.inflate(R.menu.menu_main,menu);
return true
}
// This function checks which menu item was selected and performs the task associated with the item selected.
override fun onOptionsItemSelected(item: MenuItem): Boolean {
val id = item.itemId;
// If Log Out menu item was selected
if (id == R.id.menuLogOut){
// Sign the user out
FirebaseAuth.getInstance().signOut()
// Finish this activity
finish()
// Start the initial activity
val intent = Intent(this, MainActivity::class.java)
startActivity(intent)
// Display the message to the user
Toast.makeText(this, "Successfully Signed Out", Toast.LENGTH_SHORT).show()
return true
}
return super.onOptionsItemSelected(item)
}
}
My View Model:
class CustomerViewModel: ViewModel() {
val TAG = "CustomerViewModel"
var db = Firebase.firestore
var user = FirebaseAuth.getInstance().currentUser
var liveData = MutableLiveData<List<Customer>>()
var cusArray = arrayListOf<Customer>()
var docRef = user?.uid
fun retrieveCustomer(): MutableLiveData<List<Customer>>
{
db.collection("users").document(docRef.toString())
.get()
.addOnSuccessListener { document ->
if (document != null)
{
val data = document
// Set the data
val name = data.get("name") as String
val surname = data.get("surname") as String
val email = data.get("email") as String
val contactNo = data.get("contact no") as String
val customer = Customer(name, surname, email, contactNo)
cusArray.add(customer)
liveData.value = cusArray
Log.d(TAG, "DocumentSnapshot data: ${document.data}")
}
else
{
Log.d(TAG, "No such document")
}
}
.addOnFailureListener { exception ->
Log.d(TAG, "get failed with " + exception.message, exception)
}
return liveData
}
}
My Object Class
package com.CleanWheels.cleanwheels.DataClasses
data class Customer(
val name: String?,
val surname: String?,
val email: String?,
val contactNo: String?
)
My XML file (profile_fragment):
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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=".Fragments.ProfileFragment">
<TextView
android:id="#+id/banner"
android:layout_width="499dp"
android:layout_height="290dp"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:layout_alignParentEnd="true"
android:layout_marginStart="-6dp"
android:layout_marginTop="0dp"
android:layout_marginEnd="0dp"
android:background="#color/colorPrimary"
android:layout_marginLeft="-6dp"
android:layout_alignParentRight="true"
android:layout_alignParentLeft="true"
android:layout_marginRight="0dp" />
<ImageView
android:id="#+id/image"
android:layout_width="154dp"
android:layout_height="159dp"
android:layout_alignParentTop="true"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:layout_centerHorizontal="true"
android:layout_marginTop="53dp"
android:layout_marginEnd="132dp"
android:layout_marginRight="132dp"
android:layout_marginBottom="78dp"
android:src="#drawable/ic_action_profile" />
<LinearLayout
android:id="#+id/layout_1"
android:layout_width="280dp"
android:layout_height="40dp"
android:layout_below="#id/banner"
android:layout_marginLeft="80dp"
android:layout_marginTop="100dp"
android:layout_marginRight="20dp"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Name:"
android:textSize="18sp"/>
<TextView
android:id="#+id/profileNameUI"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:textSize="18sp"/>
</LinearLayout>
<LinearLayout
android:id="#+id/layout_2"
android:layout_width="280dp"
android:layout_height="40dp"
android:layout_below="#id/layout_1"
android:layout_marginLeft="80dp"
android:layout_marginTop="20dp"
android:layout_marginRight="20dp"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Surname:"
android:textSize="18sp"/>
<TextView
android:id="#+id/profileSurnameUI"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:textSize="18sp"/>
</LinearLayout>
<LinearLayout
android:id="#+id/layout_3"
android:layout_width="280dp"
android:layout_height="40dp"
android:layout_below="#id/layout_2"
android:layout_marginLeft="80dp"
android:layout_marginTop="20dp"
android:layout_marginRight="20dp"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Email Address:"
android:textSize="18sp"/>
<TextView
android:id="#+id/profileEmailUI"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:textSize="18sp"/>
</LinearLayout>
<LinearLayout
android:id="#+id/layout_4"
android:layout_width="280dp"
android:layout_height="40dp"
android:layout_below="#id/layout_3"
android:layout_marginLeft="80dp"
android:layout_marginBottom="50dp"
android:layout_marginTop="20dp"
android:layout_marginRight="20dp"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Contact No:"
android:textSize="18sp" />
<TextView
android:id="#+id/profileContactUI"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:textSize="18sp" />
</LinearLayout>
<LinearLayout
android:id="#+id/layout_5"
android:layout_width="65dp"
android:layout_height="220dp"
android:layout_below="#id/banner"
android:layout_alignParentStart="true"
android:layout_alignParentLeft="true"
android:layout_marginStart="0dp"
android:layout_marginLeft="0dp"
android:layout_marginTop="90dp"
android:orientation="vertical">
<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="0dp"
android:layout_marginBottom="5dp"
android:layout_weight="1"
android:src="#drawable/ic_action_profile_name_ui"/>
<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:layout_marginBottom="5dp"
android:layout_weight="1"
android:src="#drawable/ic_action_profile_surname_ui"/>
<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:layout_marginBottom="5dp"
android:layout_weight="1"
android:src="#drawable/ic_action_profile_email_ui"/>
<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:layout_marginBottom="0dp"
android:layout_weight="1"
android:src="#drawable/ic_action_profile_contact_ui"/>
</LinearLayout>
The profile_fragment class file:
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
// TODO: Rename parameter arguments, choose names that match
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
private const val ARG_PARAM1 = "param1"
private const val ARG_PARAM2 = "param2"
/**
* A simple [Fragment] subclass.
* Use the [ProfileFragment.newInstance] factory method to
* create an instance of this fragment.
*/
class ProfileFragment : Fragment() {
// TODO: Rename and change types of parameters
private var param1: String? = null
private var param2: String? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
arguments?.let {
param1 = it.getString(ARG_PARAM1)
param2 = it.getString(ARG_PARAM2)
}
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_profile, container, false)
}
companion object {
/**
* Use this factory method to create a new instance of
* this fragment using the provided parameters.
*
* #param param1 Parameter 1.
* #param param2 Parameter 2.
* #return A new instance of fragment ProfileFragment.
*/
// TODO: Rename and change types and number of parameters
#JvmStatic
fun newInstance(param1: String, param2: String) =
ProfileFragment().apply {
arguments = Bundle().apply {
putString(ARG_PARAM1, param1)
putString(ARG_PARAM2, param2)
}
}
}
}
Then finally, the View I am trying to populate
You need to move all the logic to ProfileFragment once you navigate to ProfileFragment data will be set.
Example:
ProfileFragment
class ProfileFragment : Fragment() {
private val customerViewModel: CustomerViewModel by viewModels()
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
val view = inflater.inflate(R.layout.fragment_profile, container, false)
val name = view.findViewById<TextView>(R.id.name)
val surname = view.findViewById<TextView>(R.id.surname)
val email = view.findViewById<TextView>(R.id.email)
val contact = view.findViewById<TextView>(R.id.contact)
//calling initially here
customerViewModel.retrieveCustomer()
customerViewModel.liveData.observe(viewLifecycleOwner, Observer {
//customer index at 0
val customer = it[0]
name.text = customer.name
surname.text = customer.surname
email.text = customer.email
contact.text = customer.contactNo
})
return view
}
CustomerViewModel.kt
class CustomerViewModel(application: Application) : AndroidViewModel(application) {
var liveData = MutableLiveData<List<Customer>>()
fun retrieveCustomer(){
//Your logic to get data from Firebase or any remote or db
val listOfCustomer = mutableListOf<Customer>()
val customer = Customer("name", "surname","email", "contqct")
listOfCustomer.add(customer)
liveData.postValue(listOfCustomer)
}
}
fragment_profile.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="#+id/name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Name"
android:padding="8dp"
android:textSize="24dp"
/>
<TextView
android:id="#+id/surname"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Surname"
android:padding="8dp"
android:textSize="24dp"
/>
<TextView
android:id="#+id/email"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Name"
android:padding="8dp"
android:textSize="24dp"
/>
<TextView
android:id="#+id/contact"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Name"
android:padding="8dp"
android:textSize="24dp"
/>
</LinearLayout>

Categories

Resources