Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to fix Slow Rendering (Android vitals)

I have an app that is listed as in the bottom 25% in the new Google Play Console - Android vitals section for Slow Rendering. I am concerned of this because of such articles that seem to say Google Play may penalize your app in the Play Store rankings if you fall in the bottom 25%.

However, it seems impossible to improve this metric for my app. It plays music and has a SeekBar and TextView which is updated every 250ms as any music player would. I made the minimum basic program to demonstrate:

public class MainActivity extends AppCompatActivity {

    int count;
    SeekBar seekBar;
    TextView textView;

    Runnable runnable =
            new Runnable() {
                @Override
                public void run() {
                    textView.setText(Integer.toString(count));
                    seekBar.setProgress(count);
                    ++count;
                    seekBar.postDelayed(runnable, 250);
                }
            };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        seekBar = (SeekBar) findViewById(R.id.seek);
        textView = (TextView) findViewById(R.id.text);
        seekBar.post(runnable);
    }
}

Full project here: https://github.com/svenoaks/SlowRendering.git

When I run this program on hardware similar to the Nexus devices, I get these results for a
adb shell dumpsys gfxinfo com.example.xyz.slowrendering command:

Stats since: 19222191084749ns
Total frames rendered: 308
Janky frames: 290 (94.16%)
90th percentile: 32ms
95th percentile: 36ms
99th percentile: 44ms
Number Missed Vsync: 2
Number High input latency: 0
Number Slow UI thread: 139
Number Slow bitmap uploads: 0
Number Slow issue draw commands: 283

This would mean almost all my frames taking >16ms to render, I guess due to the periodic nature of the updating. All other music player apps I have tested also have this Slow Rendering problem as far as I can see. I fear Google's algorithm ruining my app ranking, is there any way I can improve my score?

like image 449
Steve M Avatar asked May 29 '17 02:05

Steve M


People also ask

What are Android vitals?

Android vitals is an initiative by Google to improve the stability and performance of Google Play apps on Android devices. When an opted-in user runs your app, their Android device logs information about aspects of quality including stability metrics, performance metrics, battery usage, and permission denials.

What is slow rendering?

If your app suffers from slow UI rendering, then the system is forced to skip frames and the user will perceive stuttering in your app. We call this jank. To help you improve app quality, Android automatically monitors your app for jank and displays the information in the Android vitals dashboard.

How much time does a UI thread have to render a screen?

Most Android devices refresh the screen 60 times a second (there are undoubtedly exceptions—earlier Android devices were sometimes in the 50 or less fps range). Because the screen is refreshed every 16 ms (1 s/60 fps = 16 ms per frame), it is crucial to ensure that all of your rendering can occur in less than 16 ms.

How do I fix lag on Android studio?

Android Studio needs at least 8 GB RAM to run better. Change your Hard Disk to SSD. Loading/Compiling/Designing/Writing time will be reduced even in 4GB RAM. Use Power Save mode from File Menu that will reduce lots of background work.


1 Answers

The TextView in your layout is causing the problem. Because it has layout width of wrap_content, which said that it's width has to be equals to the width of the content (the text in this example). Therefore, every time you call TextView.setText an expensive measure/layout pass has to occur. Simple setting the layout_width to match_parent will solve the issue.

enter image description here

enter image description here

Here are two images what is taken from systrace, it demonstrate the work run on the UI thread in 1 frame. The top one is done with layout_width=wrap_content and the bottom one is with layout_width=match_parent.

Two following methods that i have tested will improve the frame rate:

  • If you post the runnable in shorter span like 16ms (seekBar.postDelayed(runnable, 16)), you get this smooth 60fps: enter image description here

    P/s: I am not sure why yet.

  • Use some other way to update the count value instead of inside the Runnable. Use View.postOnAnimation(Runnable) to reschedule the Runnable. The result is 60FPS for the sample project.

EDIT: two Runnable that uses postOnAnimation(Runnable)

Runnable runnable =
  new Runnable() {
    @Override
    public void run() {
      textView.setText(Integer.toString(count));
      seekBar.setProgress(count);
      seekBar.postOnAnimation(this);
    }
  };



Runnable updateCount = new Runnable() {
    @Override public void run() {
      ++count;
      seekBar.postDelayed(this, 250);
    }
  };
like image 160
Tin Tran Avatar answered Oct 06 '22 02:10

Tin Tran