How to display 40+ buttons programmatically

49 views Asked by At

I'm building a small Point Of Sale app for a friend. She needs an app on a tablet that has 40 add button (and 40 remove buttons). Each button represents a Product and has a different label. The left side of the screen should have 20 stacked vertical buttons, and the right side should also have 20 stacked vertical buttons. All buttons should fit on one screen.

I have tried to use two recyclerviews next to each other - fixed to screen size - with the same adapter and custom views inside each recyclerview but this caused a lot of lag and I got warnings in my emulator that frames were skipped. I think this is because the large amount of views inside the recyclerview (80+ buttons).

I then tried 1 recyclerview with two products on 1 horizontal line, but this didn't seem to improve performance and complicates my app (because I need to set two products per line). I've also tried using ListView because I thought it had less overhead, but kept getting lag and "I/Choreographer: Skipped 44 frames! The application may be doing too much work on its main thread."

The only way that no frames seem to be skipped is when I hardcode the 80 buttons, but this is not an optimal solution because the amount of products will change over time. When the products change (saved in a csv) the amount of buttons should also update without having to change code.

Is there a way I can create a View with the 80 buttons that is less demanding on the system? Ideally I would input 1 list of Product in 1 View.

Example of 1 Product:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal"
    android:paddingHorizontal="10dip"
    android:paddingTop="1dp"
    android:paddingBottom="4dp">

    <Button
        android:id="@+id/add_button"
        android:layout_width="200dp"
        android:layout_height="44dp"
        android:minHeight="1dip"
        android:text="BUT L"
        android:textSize="22sp" />

    <TextView
        android:id="@+id/amount"
        android:layout_width="80dp"
        android:layout_height="44dp"
        android:paddingHorizontal="20dip"
        android:layout_gravity="center"
        android:textAlignment="center"
        android:text="0"
        android:textSize="22sp" />

    <Button
        android:id="@+id/delete_button"
        android:layout_width="60dp"
        android:layout_height="44dp"
        android:minWidth="1dip"
        android:minHeight="1dip"
        android:text="-"
        android:textSize="22sp" />

</LinearLayout>
1

There are 1 answers

0
cactustictacs On

I wouldn't worry about skipped frames messages in the log personally - that's more to do with how your emulator is running on your machine, if there's a Garbage Collection happening, what else is going on with the system and other apps...

RecyclerViews are the correct way to do this - they're designed to be efficient! The old ListView approach would create your 40 entries with their own Button views - RecyclerViews only create a few (enough to fill the screen and a couple either side so they can peek in when you scroll).

Then they recycle them by taking a ViewHolder that's scrolled off the screen, and filling it with the data for an item that's about to scroll into view (this is what the onBindViewHolder method is about, filling in that data). So you only have a handful of ViewHolders with their view layouts, and it doesn't matter if your list represents 40 items or 40,000!


Really you should profile the performance on a real device, but you shouldn't be having any problems with a basic RecyclerView layout, that's hardly anything in UI terms. If you like you could post your Adapter and ViewHolder code and people can tell you if you're doing anything super slow or memory-intensive in the actual handling logic.

Also make sure you're looking up the UI elements once for each ViewHolder you create, and store them as properties you can set in onBindViewHolder. If you're running findViewById in onBindViewHolder (which remember, runs every time an item is getting ready to be scrolled into view) that's a lot of duplicated work. Probably won't be glitchy in this case, but still best to avoid it if you can!