I am using Firebase recyclerview, while it works great, but I am observing a lag in rendering photos everytime user scroll so in order to fix(Recyclerview painfully slow to load cached images form Picasso) I am trying to setHasFixedSize(true) and setItemViewCacheSize(true) but problem is when I set then my recycler view shows nothing when started( completely blank), Please let me know what wrong I am doing.
HomeActivity:
package com.apnabazzar
import android.content.Intent
import android.os.Bundle
import android.view.LayoutInflater
import android.view.Menu
import android.view.View
import android.view.ViewGroup
import android.widget.Button
import android.widget.EditText
import android.widget.TextView
import androidx.appcompat.app.ActionBarDrawerToggle
import com.google.android.material.floatingactionbutton.FloatingActionButton
import com.google.android.material.snackbar.Snackbar
import com.google.android.material.navigation.NavigationView
import androidx.navigation.ui.AppBarConfiguration
import androidx.drawerlayout.widget.DrawerLayout
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.Toolbar
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.apnabazzar.constant.PNAME_PROPERTY
import com.apnabazzar.constant.PRODUCTS_DB_NAME
import com.apnabazzar.constant.PRODUCT_STATE
import com.apnabazzar.constant.PRODUCT_STATE_ACTIVE
import com.apnabazzar.model.Orders
import com.apnabazzar.model.Products
import com.apnabazzar.prevalent.Prevalent
import com.apnabazzar.viewholder.ProductViewHolder
import com.firebase.ui.database.FirebaseRecyclerAdapter
import com.firebase.ui.database.FirebaseRecyclerOptions
import com.firebase.ui.database.SnapshotParser
import com.google.firebase.database.DatabaseReference
import com.google.firebase.database.FirebaseDatabase
import com.squareup.picasso.Picasso
import de.hdodenhof.circleimageview.CircleImageView
import io.paperdb.Paper
class HomeActivity : AppCompatActivity() {
private var searchInputText:String = ""
private lateinit var appBarConfiguration: AppBarConfiguration
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_home)
Paper.init(this)
val toolbar: Toolbar = findViewById(R.id.toolbar)
toolbar.title = "Home"
setSupportActionBar(toolbar)
val fab: FloatingActionButton = findViewById(R.id.fab)
fab.setOnClickListener { view ->
val intent = Intent(this@HomeActivity, CartActivity::class.java)
startActivity(intent)
}
val drawerLayout: DrawerLayout = findViewById(R.id.drawer_layout)
val navView: NavigationView = findViewById(R.id.nav_view)
val toggle = ActionBarDrawerToggle(
this, drawerLayout, toolbar, 0, 0
)
drawerLayout.addDrawerListener(toggle)
toggle.syncState()
// Passing each menu ID as a set of Ids because each
// menu should be considered as top level destinations.
appBarConfiguration = AppBarConfiguration(
setOf(
R.id.nav_home, R.id.nav_gallery, R.id.nav_slideshow
), drawerLayout
)
navView.setNavigationItemSelectedListener {
when (it.itemId) {
R.id.nav_cart -> {
val intent = Intent(this@HomeActivity, CartActivity::class.java)
startActivity(intent)
true
}
R.id.nav_logout -> {
// handle click
Paper.book().destroy()
val intent = Intent(this@HomeActivity, MainActivity::class.java)
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK)
startActivity(intent)
true
}
else -> false
}
}
val headerView:View = navView.getHeaderView(0)
val userNameTextView:TextView = headerView.findViewById(R.id.user_profile_name)
userNameTextView.text = Prevalent.currentOnlineUser?.name
val profileImageView:CircleImageView = headerView.findViewById(R.id.user_profile_image)
if(!Prevalent.currentOnlineUser?.image.isNullOrBlank()){
Picasso.get().load(Prevalent.currentOnlineUser?.image).placeholder(R.drawable.profile).into(profileImageView)
}
val recyclerView:RecyclerView = findViewById(R.id.recycler_menu)
//recyclerView.setHasFixedSize(true) ----Not working
//recyclerView.setItemViewCacheSize(10) -- not working
val layoutManager:RecyclerView.LayoutManager = LinearLayoutManager(this)
recyclerView.layoutManager = layoutManager
val searchText: EditText = findViewById(R.id.home_search_product_name)
val searchProductsBtn: Button = findViewById(R.id.home_search_products_btn)
searchProductsBtn.setOnClickListener {
searchInputText = searchText.text.toString()
onStart()
}
}
override fun onStart() {
super.onStart()
var productRef: DatabaseReference = FirebaseDatabase.getInstance().reference.child(PRODUCTS_DB_NAME).child(
PRODUCT_STATE_ACTIVE)
var options:FirebaseRecyclerOptions<Products>? = null
if(searchInputText.isNullOrBlank()){
options = FirebaseRecyclerOptions.Builder<Products>().setQuery(productRef, Products::class.java).
setLifecycleOwner(this).build()
} else {
options = FirebaseRecyclerOptions.Builder<Products>().setQuery(productRef.orderByChild(PNAME_PROPERTY).
startAt(searchInputText), Products::class.java).
setLifecycleOwner(this).build()
}
val adapter = object : FirebaseRecyclerAdapter<Products, ProductViewHolder>(options) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ProductViewHolder {
return ProductViewHolder(LayoutInflater.from(parent.context)
.inflate(R.layout.product_items_layout, parent, false))
}
protected override fun onBindViewHolder(holder: ProductViewHolder, position: Int, model: Products) {
holder.txtProductName.text = model.pname
holder.txtProductDescription.text = model.description
holder.txtProductPrice.text = "Price = ₹ " + model.price.toString()
Picasso.get().load(model.image).into(holder.imageView)
holder.itemView.setOnClickListener {
val intent:Intent = Intent(this@HomeActivity, ProductDetailsActivity::class.java)
intent.putExtra("pid", model.pid)
startActivity(intent)
}
}
}
val recyclerView:RecyclerView = findViewById(R.id.recycler_menu)
recyclerView.setAdapter(adapter)
adapter.startListening()
}
override fun onCreateOptionsMenu(menu: Menu): Boolean {
// Inflate the menu; this adds items to the action bar if it is present.
menuInflater.inflate(R.menu.home, menu)
return true
}
}
View Holder:
class ProductViewHolder(itemView: View): RecyclerView.ViewHolder(itemView), View.OnClickListener{
val txtProductName: TextView = itemView.findViewById(R.id.product_name)
val txtProductDescription: TextView = itemView.findViewById(R.id.product_description)
val imageView: ImageView = itemView.findViewById(R.id.product_image)
val txtProductPrice: TextView = itemView.findViewById(R.id.product_price)
override fun onClick(v: View?) {
}
}
content_home
<?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"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
tools:showIn="@layout/app_bar_home">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler_menu"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scrollbars="vertical">
</androidx.recyclerview.widget.RecyclerView>
</RelativeLayout>
build.gradle
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
android {
compileSdkVersion 29
buildToolsVersion "29.0.3"
defaultConfig {
applicationId "com.apnabazzar"
minSdkVersion 23
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'
}
}
// To inline the bytecode built with JVM target 1.8 into
// bytecode that is being built with JVM target 1.6. (e.g. navArgs)
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = "1.8"
}
}
repositories {
maven { url 'https://jitpack.io' }
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'androidx.core:core-ktx:1.2.0'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
implementation 'com.google.firebase:firebase-analytics:17.2.2'
implementation 'com.google.firebase:firebase-database:19.3.0'
implementation 'com.google.firebase:firebase-storage:19.1.1'
implementation 'com.firebaseui:firebase-ui-database:6.2.1'
implementation 'com.squareup.picasso:picasso:2.71828'
implementation 'com.github.rey5137:material:1.3.0'
implementation 'io.paperdb:paperdb:2.7.1'
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
implementation 'com.google.android.material:material:1.1.0'
implementation 'androidx.navigation:navigation-fragment:2.2.2'
implementation 'androidx.navigation:navigation-ui:2.2.2'
implementation 'androidx.lifecycle:lifecycle-extensions:2.0.0'
implementation 'androidx.navigation:navigation-fragment-ktx:2.2.2'
implementation 'androidx.navigation:navigation-ui-ktx:2.2.2'
implementation 'de.hdodenhof:circleimageview:3.1.0'
implementation 'com.theartofdev.edmodo:android-image-cropper:2.8.+'
implementation 'com.cepheuen.elegant-number-button:lib:1.0.2'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
}
apply plugin: 'com.google.gms.google-services'