private fun setQuestion() {
val mainImg = findViewById<ImageView>(R.id.movieImgView)
val movieNameText = findViewById<TextView>(R.id.movieName)
val movieYearText = findViewById<TextView>(R.id.movieYear)
val movieRatingText = findViewById<TextView>(R.id.movieRatingText)
val seriesOrNoText = findViewById<TextView>(R.id.seriesOrNoText)
val btnNext = findViewById<Button>(R.id.btnNext)
movieList = Constants.getActionMovies()
val movie: ActionMovies? = movieList!![currentPosition - 1]
val displayMetrics = DisplayMetrics()
windowManager.defaultDisplay.getMetrics(displayMetrics)
val height = displayMetrics.heightPixels.toFloat()
val width = displayMetrics.widthPixels.toFloat()
mainImg.setImageResource(movie!!.moviePic)
movieNameText.text = movie.movieName
movieNameText.scaleX = width
movieNameText.scaleY = height
movieYearText.text = "(${movie.date.toString()})"
movieRatingText.text = movie.rating
if (movie.series) {
seriesOrNoText.text = "Yes"
} else {
seriesOrNoText.text = "No"
}
if (currentPosition == movieList!!.size) {
btnNext.text = "Return to \n Main Menu"
btnNext.setOnClickListener {
finish()
}
}
}
}
I'm trying to set the width and height of my MovieNameText, however it seems to have no effect at all, any help? I've defined the text size in the xml file to 30sp, I've tried setText and scaleX and textSize
To change the size of the text
movieNameText.textSize = 30f // or whatever value you would like to use
Aslong as your Textview is constrained and layout width and height is set to 'wrap content' it should scale with your app.
This doesn't works as expected:
imageView = ImageView(context)
imageView.adjustViewBounds = true
imageView.scaleType = ImageView.ScaleType.FIT_CENTER
imageView.layoutParams = ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.MATCH_PARENT)
imageView.setImageBitmap(myBitmap)
The imageView is added to a TableRow layout (which is added to a Table).
Full function:
fun loadTable(data: List<ListItem>) = lifecycleScope.launch {
val rowParams = TableRow.LayoutParams(TableRow.LayoutParams.MATCH_PARENT, TableRow.LayoutParams.WRAP_CONTENT)
val table = binding.table
val context = table.context
for (i in data.indices) {
val rowIndex = i / TABLE_COLUMNS
val row: TableRow = if (table.childCount <= rowIndex) {
val r = TableRow(context)
r.layoutParams = rowParams
binding.table.addView(r)
table.layoutParams.width = myBitmap.width * TABLE_COLUMNS
r
} else {
table[rowIndex] as TableRow
}
imageView = ImageView(context)
imageView.adjustViewBounds = true
imageView.scaleType = ImageView.ScaleType.FIT_CENTER
imageView.layoutParams = ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.MATCH_PARENT)
imageView.setImageBitmap(myBitmap)
row.addView(imageView)
}
}
Expected result: the imageView display the image and has the same size.
Actual result: the imageView has a zero-size and image is not displayed.
With the layout inspector I can see that the attributes are correct, but the size of the imageView remains 0.0.
If I set the same attribute at design time, the imageView is displayed correctly.
I'm currently using a Table Layout and programatically adding rows and buttons. However, when I add the views a lot of them go off-screen. Is there a way to programatically set the size to the portion of the screen.
I have decent experience with Android, but new to Kotlin.
Here is where I add the views
private fun setupTable () {
for(i in 0 until this.rowSize) {
val row = TableRow(context)
row.layoutParams
row.layoutParams = ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT)
for(j in 0 until this.columnSize) {
val button = Button(context)
button.apply {
layoutParams = TableRow.LayoutParams(TableRow.LayoutParams.WRAP_CONTENT,
TableRow.LayoutParams.WRAP_CONTENT)
text = "R $i C $j"
}
row.addView(button)
}
wordLayout?.addView(row)
}
}
Here is the picture for reference. Here I want a 10x10 table and to fit all the buttons inside the TableLayout.
Try the following code:
package net.androidly.androidlylayouts
class MainActivity : AppCompatActivity() {
val ROWS = 10
val COLUMNS = 5
val tableLayout by lazy { TableLayout(this) }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
textView.text = "ROWS : $ROWS COLUMNS: $COLUMNS"
val lp = TableLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)
tableLayout.apply {
layoutParams = lp
isShrinkAllColumns = true
}
createTable(ROWS, COLUMNS)
}
fun createTable(rows: Int, cols: Int) {
for (i in 0 until rows) {
val row = TableRow(this)
row.layoutParams = ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT)
for (j in 0 until cols) {
val button = Button(this)
button.apply {
layoutParams = TableRow.LayoutParams(TableRow.LayoutParams.WRAP_CONTENT,
TableRow.LayoutParams.WRAP_CONTENT)
text = "R $i C $j"
}
row.addView(button)
}
tableLayout.addView(row)
}
linearLayout.addView(tableLayout)
}
}
Hope this helps.
I'm trying to use the latest version of the FontAwesome typeface for a TextView in a LinearLayout that I created programmatically, but instead a box is shown containing a cross. I tried both FontManager.getTypeface(activity!!.baseContext, FontManager.FONTAWESOME) and FontManager.getTypeface(activity!!.applicationContext, FontManager.FONTAWESOME) but neither of these worked. I'm even using the latest .otf file provided by FontAwesone. I really don't understand what I've done wrong, because I followed all the instructions on the FontAwesome website. Is there a problem because the layout is created dynamically or something else?
FontManager object
object FontManager {
private const val ROOT = "fonts/"
internal const val FONTAWESOME = ROOT + "fontawesome5-free-regular.otf"
internal fun getTypeface(context: Context, font: String): Typeface {
return Typeface.createFromAsset(context.assets, font)
}
}
Fragment class
class MyFragment : androidx.fragment.app.Fragment() {
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
val mainRelativeLayout = RelativeLayout(activity)
// Layout Parameters for relative layout items
val rlpCVPrimary = RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.WRAP_CONTENT)
val rlpTVPrimaryIcon = RelativeLayout.LayoutParams(LinearLayout.LayoutParams
.WRAP_CONTENT,
FrameLayout.LayoutParams.WRAP_CONTENT)
val rlpTVPrimaryText = RelativeLayout.LayoutParams(LinearLayout.LayoutParams
.WRAP_CONTENT,
FrameLayout.LayoutParams.WRAP_CONTENT)
val rlpTVTitle = RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.WRAP_CONTENT)
val rlpCVSecondary = RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.WRAP_CONTENT)
val rlpTVSecondaryIcon = RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT,
FrameLayout.LayoutParams.WRAP_CONTENT)
val rlpTVSecondaryText = RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT,
FrameLayout.LayoutParams.WRAP_CONTENT)
// Accessing FontAwesome font
val iconFont = FontManager.getTypeface(activity!!.applicationContext, FontManager.FONTAWESOME)
//
val r = context!!.resources
val fourDp = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 4f, r.displayMetrics).toInt()
val tenDp = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 10f, r.displayMetrics).toInt()
val thirtyDp = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 30f, r.displayMetrics).toInt()
// Creating RelativeLayouts for root layout
val cvRLPrimary = RelativeLayout(context)
val cvRLSecondary = RelativeLayout(context)
// Creating CardViews
val cvPrimary = context?.let { CardView(it) }
when {
cvPrimary != null -> {
cvPrimary.radius = fourDp.toFloat()
cvPrimary.setContentPadding(tenDp,tenDp,tenDp,tenDp)
cvPrimary.useCompatPadding = true
cvPrimary.cardElevation = fourDp.toFloat()
cvPrimary.layoutParams = rlpCVPrimary
}
}
rlpCVPrimary.setMargins(0, 0, 0, thirtyDp)
val cvSecondary = context?.let { CardView(it) }
when {
cvSecondary != null -> {
cvSecondary.radius = fourDp.toFloat()
cvSecondary.setContentPadding(tenDp,tenDp,tenDp,tenDp)
cvSecondary.useCompatPadding = true
cvSecondary.cardElevation = fourDp.toFloat()
cvSecondary.layoutParams = rlpCVSecondary
}
}
rlpCVSecondary.setMargins(0, 0, 0, thirtyDp)
/*
* Creating Primary CardView items
*/
// 'tvPrimaryIcon' TextView
val tvPrimaryIcon = TextView(context)
tvPrimaryIcon.text = getString(R.string.fa_icon_sign_in)
tvPrimaryIcon.typeface = iconFont
tvPrimaryIcon.layoutParams = rlpCVPrimary
tvPrimaryIcon.setMargins(0, 0, tenDp, 0)
TextViewCompat.setTextAppearance(tvPrimaryIcon, android.R.style.TextAppearance_Medium)
// 'tvPrimaryText' TextView
val tvPrimaryText = TextView(context)
tvPrimaryText.text = getString(R.string
.primary_title)
TextViewCompat.setTextAppearance(tvPrimaryText, android.R.style.TextAppearance_Medium)
// 'tvTitle' TextView
val tvTitle = TextView(context)
tvTitle.text = getString(R.string.hello_world)
tvTitle.gravity = Gravity.CENTER
TextViewCompat.setTextAppearance(tvTitle, android.R.style.TextAppearance_Medium)
rlpTVTitle.setMargins(0, tenDp, 0, tenDp)
/*
* Creating Secondary CardView items
*/
// 'tvSecondaryIcon' TextView
val tvIconExit = TextView(context)
tvIconExit.text = getString(R.string.fa_icon_sign_out)
tvIconExit.typeface = iconFont
TextViewCompat.setTextAppearance(tvIconExit, android.R.style.TextAppearance_Medium)
rlpTVIconExit.setMargins(0, 0, tenDp, 0)
// 'tvSecondaryText' TextView
val tvSecondaryText = TextView(context)
tvSecondaryText.text = getString(R.string.secondary_title)
TextViewCompat.setTextAppearance(tvSecondaryText, android.R.style.TextAppearance_Medium)
// Set IDs for text views
mainRelativeLayout.id = View.generateViewId()
cvPrimary!!.id = View.generateViewId()
tvPrimaryIcon.id = View.generateViewId()
tvPrimaryText.id = View.generateViewId()
tvTitle.id = View.generateViewId()
cvSecondary!!.id = View.generateViewId()
tvSecondaryIcon.id = View.generateViewId()
tvSecondaryText.id = View.generateViewId()
// Set Layout Parameters for text views
tvPrimaryIcon.layoutParams = rlpTVPrimaryIcon
tvPrimaryText.layoutParams = rlpTVPrimaryText
tvTitle.layoutParams = rlpTVTitle
tvSecondaryIcon.layoutParams = rlpTVSecondaryIcon
tvSecondaryText.layoutParams = rlpTVSecondaryText
// Set RelativeLayout rules for views
rlpTVPrimaryText.addRule(RelativeLayout.END_OF, tvPrimaryIcon.id)
rlpTVTitle.addRule(RelativeLayout.BELOW, cvPrimary.id)
rlpCVSecondary.addRule(RelativeLayout.BELOW, tvTitle.id)
rlpTVSecondaryText.addRule(RelativeLayout.END_OF, tvSecondaryIcon.id)
// Adding items to root layout
mainRelativeLayout.addView(cvPrimary)
cvPrimary.addView(cvRLPrimary)
cvRLPrimary.addView(tvPrimaryIcon)
cvRLPrimary.addView(tvPrimaryText)
mainRelativeLayout.addView(tvTitle)
mainRelativeLayout.addView(cvSecondary)
cvSecondary.addView(cvRLSecondary)
cvRLSecondary.addView(tvSecondaryIcon)
cvRLSecondary.addView(tvSecondaryText)
return mainRelativeLayout
}
}
I have RecyclerView, which has another items inside. Each RecyclerView item has list of other items which are shown bellow as subitems if I click item in RecyclerView. To avoid nested RecyclerView thing, I iterate over these items in onBindViewHolder() and I add them to empty LinearLayout inflating subitem layout.
OutOfMemory error occurs as I scroll down, because there can be 1000 items and each item could have 1000 subitems. In my app its list of orders and if I click item from this list, list of ordered parts are shown one by one.
How to fix this issue. Also scrolling became laggy. I'm using Glide API to cache images, but this error still occurs.
recyclerView = view.findViewById<RecyclerView>(R.id.order_recycler_view).apply {
setHasFixedSize(true)
// use a linear layout manager
layoutManager = viewManager
// specify an viewAdapter (see also next example)
adapter = viewAdapter
//set cache for rv
setItemViewCacheSize(50)
isDrawingCacheEnabled = true
drawingCacheQuality = View.DRAWING_CACHE_QUALITY_HIGH
}
inside RVAdapter onBindViewHolder():
for(orderItem in it.itemList){
val contentLayout: View = LayoutInflater.from(holder.itemView.context).inflate(R.layout.ordered_list_item_layout, null, false)
fillItemView(contentLayout, orderItem, res)
holder.orderContentLayout.addView(contentLayout)
}
FillItemView method:
private fun fillItemView(contentLayout: View, orderItem: OrderedItem, res: Resources){
val orderItemImage: ImageView = contentLayout.findViewById(R.id.orderPartImage)
val orderItemName: TextView = contentLayout.findViewById(R.id.orderPartName)
val orderItemWeight: TextView = contentLayout.findViewById(R.id.orderPartWeight)
val orderPartPhoto: String? = orderItem.item.itemPhoto.optString(ctx.getString(R.string.part_photo))
setOrderedPartLogo(orderItemImage, res, orderPartPhoto)
val itemPrice: String = String.format("%.2f", orderItem.item.itemPrice)
val spanText = SpannableString(foodPrice + " €" + " " + "(" + orderItem.quantity.toString() + "x" + ")" + orderItem.item.itemName)
spanText.setSpan(ForegroundColorSpan(res.getColor(R.color.colorRed)), 0, itemPrice.length + 2, 0)
orderItemName.text = spanText
orderItemWeight.text = orderItem.item.itemWeigth
}
private fun setOrderedPartLogo(orderImageView: ImageView, resources: Resources, imageURL: String?) {
val bitmap: Bitmap = BitmapFactory.decodeResource(resources, R.drawable.no_photo)
val roundedBitMapDrawable: RoundedBitmapDrawable = RoundedBitmapDrawableFactory.create(resources, bitmap)
roundedBitMapDrawable.isCircular = true
val requestOptions: RequestOptions = RequestOptions()
.circleCrop()
.placeholder(roundedBitMapDrawable)
.error(roundedBitMapDrawable)
.diskCacheStrategy(DiskCacheStrategy.ALL)
.priority(Priority.HIGH)
Glide.with(orderImageView.context)
.load(imageURL)
.apply(requestOptions)
.into(orderImageView)
}
Whole Adapter:
class OrderListAdapter(private var mActivity: FragmentActivity,
private var orderList: ArrayList<Order>, private var fragment: OrderListFragment):
RecyclerView.Adapter<RecyclerView.ViewHolder>() {
private var expandedPosition = -1
private lateinit var mRecyclerView: RecyclerView
inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
//order item views
val orderName: TextView = itemView.findViewById(R.id.orderName)
val orderWaitTime: TextView = itemView.findViewById(R.id.orderWaitTime)
val orderAddress: TextView = itemView.findViewById(R.id.orderAddress)
val orderDate: TextView = itemView.findViewById(R.id.orderDate)
//details expandable layout
val orderDetailsExpandable: LinearLayout = itemView.findViewById(R.id.orderDetails)
val orderContentLayout: LinearLayout = itemView.findViewById(R.id.contentLayout)
val orderLayout: ConstraintLayout = itemView.findViewById(R.id.mainLayout)
}
override fun onCreateViewHolder(parent: ViewGroup,
viewType: Int): RecyclerView.ViewHolder {
// create a new view
val itemView = LayoutInflater.from(parent.context)
.inflate(R.layout.order_recyclerview_item_layout, parent, false)
return ViewHolder(itemView)
}
override fun onAttachedToRecyclerView(recyclerView: RecyclerView) {
super.onAttachedToRecyclerView(recyclerView)
mRecyclerView = recyclerView
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
if (holder is ViewHolder) {
val res = holder.itemView.context.resources
val ctx = holder.itemView.context
orderList[position].let {
val orderPrice: Int = it.orderJSON.getInt(ctx.getString(R.string.order_total_price))
val orderSupplierName: String? = it.orderSupplier?.json?.getString(ctx.getString(R.string.sup_name))
val orderDate: String = it.orderJSON.getString(ctx.getString(R.string.order_date))
val orderPaymentType: Int = it.orderJSON.getInt(ctx.getString(R.string.order_payment_type))
var orderPaymentTypeString = "unknown"
val orderDeliveryType: Int = it.orderJSON.getInt(ctx.getString(R.string.order_delivery_type))
val orderDeliveryPrice: Int = it.orderJSON.getInt(ctx.getString(R.string.order_delivery_price))
val orderJSONObject: JSONObject = it.orderJSON
val orderItemList: ArrayList<OrderedItem> = it.partsList
//OrderDate -> hours, minutes, day, month, year
val formattedOrderDate: OrderDate = getOrderDate(orderDate)
when(orderPaymentType){
1 -> orderPaymentTypeString = "credit"
2 -> orderPaymentTypeString = "credit"
3 -> orderPaymentTypeString = "money"
4 -> orderPaymentTypeString = "voucher"
}
//set order price, name and type
val orderPriceString: String = convertCentsToFloat(orderPrice)
if (orderSupplierName == null){
val spannableText = SpannableString(orderPriceString + " € " + ctx.getString(R.string.default_sup_name) + " - " + orderPaymentTypeString)
spannableText.setSpan(ForegroundColorSpan(res.getColor(R.color.colorRed)), 0, orderPriceString.length + 3, 0)
holder.orderName.text = spannableText
} else {
val spannableText = SpannableString(orderPriceString + " € " + orderSupplierName + " - " + orderPaymentTypeString)
spannableText.setSpan(ForegroundColorSpan(res.getColor(R.color.colorRed)), 0, orderPriceString.length + 3, 0)
holder.orderName.text = spannableText
}
//set order wait time
holder.orderWaitTime.text = formattedOrderDate.dateHours + ":" + formattedOrderDate.dateMinutes
//set order address
//holder.orderAddress.text = it.orderAddress
//set order date
holder.orderDate.text = formattedOrderDate.dateDay + "." + formattedOrderDate.dateMonth + "." + formattedOrderDate.dateYear
holder.orderContentLayout.removeAllViews()
//create layout for order items
for(orderItem in it.itemList){
val contentLayout: View = LayoutInflater.from(holder.itemView.context).inflate(R.layout.ordered_list_item_layout, null, false)
fillItemView(contentLayout, orderItem, res, ctx)
holder.orderContentLayout.addView(contentLayout)
}
//create footer delivery
val deliveryLayout: View = LayoutInflater.from(holder.itemView.context).inflate(R.layout.order_delivery_footer_layout, null, false)
fillDeliveryFooter(deliveryLayout, orderDeliveryType, orderDeliveryPrice, res, ctx)
holder.orderContentLayout.addView(deliveryLayout)
//create footer orderRepeat Button
val orderRepeatLayout: View = LayoutInflater.from(holder.itemView.context).inflate(R.layout.order_repeat_order_layout, null, false)
holder.orderContentLayout.addView(orderRepeatLayout)
orderRepeatLayout.setOnClickListener {
fragment.switchToOrderCartActivity(orderItemList)
}
//expanding order view on click
val isExpanded = position == expandedPosition
holder.orderDetailsExpandable.visibility = if (isExpanded) View.VISIBLE else View.GONE
holder.itemView.isActivated = isExpanded
holder.orderLayout.setOnClickListener {
createLog("expPos ", position.toString())
orderList[position].let {
if(expandedPosition != position){
if(expandedPosition != -1){
val myLayout: View? = mRecyclerView.layoutManager.findViewByPosition(expandedPosition)
createLog("myLayout", myLayout.toString())
createLog("OrderExp", "Expanding layout")
if(myLayout != null){
myLayout.findViewById<LinearLayout>(R.id.orderDetails).visibility = View.GONE
}
}
createLog("expPosSet ", position.toString())
expandedPosition = position
} else {
expandedPosition = -1
}
notifyItemChanged(position)
scrollToTop(holder.itemView)
}
}
}
}
}
override fun getItemCount() = orderList.size
private fun scrollToTop(v: View) {
val itemToScroll = mRecyclerView.getChildAdapterPosition(v)
val centerOfScreen = mRecyclerView.width / 2 - v.width / 2
fragment.getRecyclerViewManager().scrollToPositionWithOffset(itemToScroll, centerOfScreen)
}
private fun fillItemView(contentLayout: View, orderItem: OrderedItem, res: Resources){
val orderItemImage: ImageView = contentLayout.findViewById(R.id.orderPartImage)
val orderItemName: TextView = contentLayout.findViewById(R.id.orderPartName)
val orderItemWeight: TextView = contentLayout.findViewById(R.id.orderPartWeight)
val orderPartPhoto: String? = orderItem.item.itemPhoto.optString(ctx.getString(R.string.part_photo))
setOrderedPartLogo(orderItemImage, res, orderPartPhoto)
val itemPrice: String = String.format("%.2f", orderItem.item.itemPrice)
val spanText = SpannableString(foodPrice + " €" + " " + "(" + orderItem.quantity.toString() + "x" + ")" + orderItem.item.itemName)
spanText.setSpan(ForegroundColorSpan(res.getColor(R.color.colorRed)), 0, itemPrice.length + 2, 0)
orderItemName.text = spanText
orderItemWeight.text = orderItem.item.itemWeigth
}
private fun fillDeliveryFooter(deliveryLayout: View, deliveryType: Int, deliveryPrice: Int, res: Resources, ctx: Context){
val deliveryImageIcon: ImageView = deliveryLayout.findViewById(R.id.deliveryIconImage)
val deliveryPriceTextView: TextView = deliveryLayout.findViewById(R.id.deliveryLabelText)
//set delivery icon
when(deliveryType){
1 -> deliveryImageIcon.setImageResource(R.drawable.ico_summary_delivery)
2 -> deliveryImageIcon.setImageResource(R.drawable.ico_summary_pickup)
else -> deliveryImageIcon.setImageResource(R.drawable.restauracia_no_photo)
}
//set delivery price, name label
val deliveryPriceString: String = convertCentsToFloat(deliveryPrice)
val deliverySpannable = SpannableString(deliveryPriceString + " € Doprava / Vyzdvihnutie")
deliverySpannable.setSpan(ForegroundColorSpan(res.getColor(R.color.colorPrice)), 0, deliveryPriceString.length + 2, 0)
deliveryPriceTextView.text = deliverySpannable
}
private fun setOrderedPartLogo(orderImageView: ImageView, resources: Resources, imageURL: String?) {
val bitmap: Bitmap = BitmapFactory.decodeResource(resources, R.drawable.no_photo)
val roundedBitMapDrawable: RoundedBitmapDrawable = RoundedBitmapDrawableFactory.create(resources, bitmap)
roundedBitMapDrawable.isCircular = true
val requestOptions: RequestOptions = RequestOptions()
.circleCrop()
.placeholder(roundedBitMapDrawable)
.error(roundedBitMapDrawable)
.diskCacheStrategy(DiskCacheStrategy.ALL)
.priority(Priority.HIGH)
Glide.with(orderImageView.context)
.load(imageURL)
.apply(requestOptions)
.into(orderImageView)
}
private fun convertCentsToFloat(centPrice: Int): String {
val centOnlyPrice: Int = centPrice % 100
val euroPrice: Int = (centPrice - centOnlyPrice) / 100
if (centOnlyPrice < 10) {
val finalPrice: String = euroPrice.toString() + ".0" + centOnlyPrice.toString()
return finalPrice
} else {
val finalPrice: String = euroPrice.toString() + "." + centOnlyPrice.toString()
return finalPrice
}
}
private fun getOrderDate(date: String): OrderDate{
val rawDate: List<String> = date.split("T")
val dateOnly: String = rawDate[0]
val dateFormat: List<String> = dateOnly.split("-")
val timeOnly: String = rawDate[1]
val timeFormat: List<String> = timeOnly.split(":")
val finalDate = OrderDate(timeFormat[0], timeFormat[1], dateFormat[2], dateFormat[1], dateFormat[0])
return finalDate
}
fun createLog(tag: String, msg: String){
Log.i(tag, msg)
}
fun refreshOrder(orderListRefreshed: ArrayList<Order>){
orderList = orderListRefreshed
notifyDataSetChanged()
if(AndroidAssets.getInstance(mActivity).orderList.isEmpty()){
mRecyclerView.visibility = View.GONE
fragment.showFooterLayout()
} else{
mRecyclerView.visibility = View.VISIBLE
fragment.hideFooterLayout()
}
fragment.hideProgressBar()
}
}
Image from AndroidProfiler on Memory Usage(memory usage increased around 25s - this is where I've started scrolling RecyclerView... and after that it dropped).
UPDATE: With better analysis I found out that one SubItem has 2.5MB in memory. If i will have 5 orders containing 20 items each it will allocate 250MB of space in RAM. And this is with Glide caching images.
UPDATE 2: Is there any way how to load only visible views? So as user scrolls it will load new views and top one which will be off the display will be removed from memory. I thought that recyclerview is doing that by default by recycling item layout views.
UPDATE 3: I've implemented new recyclerview and adapter initialization for inner list. This rv and adapter is initialized when view in onBindViewHolder() is marked as expanded and if it's not expanded RV and Adapter is set to null. So I've implemented Nested RecyclerView. Problem is that my inner recyclerview is not scrolling at all. I have to set scrolling and set RV height to fixed size (for example 400dp), because if I leave it match_parent or wrap_content, it will throw OutOfMemoryError if more than 20 items are inside -> it is not recycling views. How to achieve both recyclerviews to scroll vertically?
Layout Visualization:
Your groups (each containing 1000 items) are simply too big.
You should flatten the hierarchy -- that is, expose all the items individually to the RecyclerView. Your adapter will need to override getItemViewType() to return different values for different view types, and you'll need to return different types of view holders depending on the item at each position.
This way, you'll only ever inflate as many views as can fit on the screen (plus a few extra that RecyclerView pre-requests to avoid too much inflation at scroll time).