Android Question Optimizing label redraws

Discussion in 'Android Questions' started by Alessandro71, Mar 19, 2019.

  1. Alessandro71

    Alessandro71 Member Licensed User

    Despite not being a game, my app has several labels that gets updated several times a second:
    text is changed, visible and color attributes are changed, position and size are changed.
    How does Android handles redraws?
    When I set label.Text, it gets redrawn on screen.
    Does it get redrawn even if the new text is the same as the current one?
    Is it worth to check if the new string is different from the previous one, and not set it to avoid a redraw?
    Is it the same for visibility and color attributes, or does the graphic layer already performs these kind of checks?
  2. sorex

    sorex Expert Licensed User

    in android you can enable a special mode where you can see how much time it needs for the current redrawings.

    it's something about vertical lines.

    I read that google was using or planned to use these meassurements to mark 'badly' designed apps.
  3. Erel

    Erel Administrator Staff Member Licensed User

    What is the problem?
  4. Alessandro71

    Alessandro71 Member Licensed User

    Problem is speeding up screen redraws:

    Is it a waste using something like this to update a text label only if it's changed
    Public Sub setText(text As String)
    If (text <> m_textLabel.m_label.Text) Then
            m_textLabel.m_label.Text = text
    End If
    End Sub
    just to avoid unnecessary screen redraw?

    Does the graphic framework already does this, so it's a useless optimization?
  5. Erel

    Erel Administrator Staff Member Licensed User


    I guess that it is currently too slow, right?
  6. emexes

    emexes Well-Known Member Licensed User

    What I do when I have a rapidly changing item on the screen, eg a counter of incoming bytes, is:

    everytime a on-screen variable is updated, set a flag to indicate that it needs to be refreshed on-screen

    For I = 1 to 1000000000
        LoopNumber = I
        RefreshFlag = 
    0or Sleep(1to enable other stuff to happen too

    and then in a timer tick (somewhere between 3 and 20 times per second, to balance CPU load vs user dazzle)

    Sub tmrRefresh_Tick

    If RefreshFlag Then
            RefreshFlag = 
    False    'clear flag first, just in case any updates occur during the next three lines
            lblLoopNumber.Text = LoopNumber
            lblSomethingElse.Text = SomethingElse
            lblButWaitTheresMore.Text = ButWaitTheresMore & 
    " !!!"
    End If

    If RefreshStatusFlag then
            RefreshStatusFlag = 
            lblStatusLine.Text = 
    "S1:" & ThisStatus & " S2:" & ThatStatus & " LS:" & LinkStatus
    End If

    End Sub

    This has the side-benefits of:
    (1) not doing non-string to string conversions if the activity is not on screen (because you disable timers when an activity is paused), and
    (2) automatically loading up all the screen display views on the first timer tick when an activity is resumed (or started)
    (assuming you set all refresh flags = True in the activity resume routine)
    (vs what I often see - and sometimes do myself - is the same code twice: once to initialize the view, and then again to update it)
    Last edited: Mar 21, 2019
  7. Alessandro71

    Alessandro71 Member Licensed User

    this is actually more convoluted than that.
    i actually have a timer for updating some counters, but the most labels (about 150) needs to be updated synchronously with a data capture cycle, which runs several times a second.
    i tested 2 versions of the update cycle:
    1) directly updating the labels
    2) checking previous value before actual update
    and timed the 2 runs:

    here are the results (average value over about 1000 samples)
    1) 11.02 ms
    2) 8.17 ms
    this is against a total cycle time (data capture + refresh) of about 210 ms

    so a small optimization seems to be possible
    i will also check your suggestion about avoiding non-string to string conversions, which can be applied to some of my labels
    thank you
  8. emexes

    emexes Well-Known Member Licensed User

    If you can compare the values before translating them to strings, that'd be good, eg:

    Dim NewValue, OldValue as Double

    NewValue = reading from sensor 
    or whatever
    If NewValue <> OldValue Then
        lblValue.Text = 
    NumberFormat2(NewValue, 133False)
        OldValue = NewValue
    End If
    will (ignoring time taken to read sensor) be significantly faster than

    Dim NewText, OldText As String

    NewText = 
    NumberFormat2(reading from sensor or whatever, 133False)
    If NewText.CompareTo(OldText) <> 0 Then
        lblValue.Text = NewText
        OldText = NewText
    End If
    and that's without taking into account the time taken doing garbage collection of all those discarded temporary strings.

    Not that it matters here, but: the OldText = NewText string assignment is virtually instantaneous (is just a pointer assignment) and might even be (slightly) faster than the 8-byte Double assignment. Both those times get swamped by the String creation and formatting and disposal operations, though.
  9. emexes

    emexes Well-Known Member Licensed User

    I missed that bit about 150 labels. Yikes! How big is your screen?!?! Are we talking 150 different distinct label texts (eg, numbers) or just a few (eg, "Disabled", "Active", "Alarm")?

    Nonetheless, I'd be expecting each non-string comparison to take less than a microsecond, including array indexing, and so to check all 150 should take less than a millisecond. Although it's currently using about 6% of your CPU (11 ms per 210 ms?) so... is there other low-hanging fruit in the remaining 199 ms of that cycle? Like, is that the time taken to transfer 150 x 1-byte readings over a serial link? Can you compress that down to using bits instead of bytes? Or just send changed data (plus unchanged data but at a lower rate, or by request only)?

    Sorry, probably preaching to the converted here. Still, if you'd like a fresh set of eyes on the problem, I'd be interested to look at it.
    Last edited: Mar 22, 2019
  10. emexes

    emexes Well-Known Member Licensed User

    I'm thinking this is either some industrial monitoring system, or a results/scoring system for your kids' athletics carnival. Is either of those guesses close?

    edit: ah, vehicle data logging. I used to program dynamometers, including reading OBD using the (then new) ELM chip. Presumably you're using some more-direct link than OBD though, and don't have any say over what format it gets sent in.

    If you're using a database rather than a plain text or binary file to save the data, and you're storing one reading per record rather than one set of (150?) readings per record, then I could imagine most of that 199 ms is consumed by the database library :-/

    But... no problem.
    Last edited: Mar 22, 2019
  11. Alessandro71

    Alessandro71 Member Licensed User

    real time driving data visualization, through an already highly optimized OBD data reading process
    most of the labels are graphic elements, only some of them are text
    i just tested some of the suggested optimizations, but the results are neglectable in my environment
  12. emexes

    emexes Well-Known Member Licensed User

    Looks good. Certainly not the static industrial indicator panel I'd imagined originally.

    You said that the label updates were taking 11 ms out of 210, and that you'd managed to squeeze that down another 25% already, so I agree with you, you're not going to save much more out of that area. I assume the word "Yaris" and other static stuff isn't being updated constantly.

    Are there 150 elements on that screen? Is that one screen of several? Is there stuff hidden behind the main screen that we can't see but is using pixel-moving time to keep updated anyway?

    Your OBD reading must be pretty highly optimised. My recollection was I could get maybe 20 readings per second if I bent the rules of the ELM protocol by sending the next request before the current request had properly finished. Although most manufacturers were moving to CAN, so that's probably sped things up too.
  13. sorex

    sorex Expert Licensed User

    from what I see I don't think you get more than 5 updates a second.

    why not keep that as reference and update only every 200ms instead of when 1 value changes somewhere in between?

    I also don't see why you need a database to keep track of 10 values? you'll have less overhead when using just a map.
    The graph just moves on so you only need the latest value while you move the rest to the right.
    Erel likes this.
  1. This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
    By continuing to use this site, you are consenting to our use of cookies.
    Dismiss Notice