Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to avoid total view-hierarchy re-layout when using EditText?

Background

I have a rather complex layout being shown to the user in an activity.

One of the views is an EditText.

Since I had to make one of the views stay behind the soft-keyboard, yet the rest above it, I had to listen to view-layout changes (written about it here).

The problem

I've noticed that whenever the EditText has focus and shows its caret, the entire view-hierarchy gets re-layout.

You can see it by either looking at the log of the listener I've created, or by enabling "show surface updates" via the developers settings.

This causes bad performance on some devices, especially if the layout of the activity is complex or have fragments that have complex layouts.

The code

I'm not going to show the original code, but there is a simple way to reproduce the issue:

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.example.user.myapplication.MainActivity">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="just some text"/>

        <EditText
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:inputType="phone"
            android:text="write here"
            android:textSize="18dp"/>


        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="just some text 2"/>
    </LinearLayout>
</FrameLayout>

MainActivity.java

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        findViewById(android.R.id.content).getViewTreeObserver().addOnPreDrawListener(new OnPreDrawListener() {

            @Override
            public boolean onPreDraw() {
                Log.d("AppLog", "onPreDraw");
                return true;
            }
        });
    }
}

What I've tried

When disabling the caret (using "cursorVisible", which for some reason is called a "cursor" instead) , I can see that the problem doesn't exist.

I've tried to find an alternative to the built-in caret behavior, but I can't find. Only thing I've found is this post, but it seems to make it static and I'm not sure as to how well it performs (performance and compatibility vs normal caret).

I've tried to set the size of the EditText forcefully, so that it won't need to cause invalidation of the layout that contains it. It didn't work.

I've also noticed that on the original app, the logs can (for some reason) continue being written even when the app goes to the background.

I've reported about this issue (including sample and video) here, hoping that Google will show what's wrong or a fix for this.

The question

Is there a way to avoid the re-layout of the entire view hierarchy ? A way that will still let the EditText have the same look&feel of normal EditText?

Maybe a way to customize how the EditText behaves with the caret?

like image 735
android developer Avatar asked Feb 01 '16 12:02

android developer


People also ask

What is plain text in Android Studio?

Plaintext is nothing but the Edittext. It has changed the name in Android studio but if you check into Design view you will get to know that it still has name of Edittext only. Usages. Textview : should be used for uneditable text which user wants to read but not to manipulate.

What is TextView and Edittext explain TextView attributes?

Edittext is one of many such widgets which can be used to retrieve text data from user. Edittext refers to the widget that displays an empty textfield in which a user can enter the required text and this text is further used inside our application. Class Syntax: public class EditText extends TextView.

How do you edit a text box on Android?

Step 1: Create a new project in Android Studio and name it EditTextExample. Step 2: Now Open res -> layout -> xml (or) activity_main. xml and add following code. In this code we have added multiple edittext and a button with onclick functionality.


2 Answers

I've noticed that whenever the EditText has focus and shows its caret, the entire view-hierarchy gets re-layout.

This is not true. Size and position of EditText is constant - there is no re-layouting. You can check it by using code below.

findViewById(android.R.id.content).getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
  @Override
  public void onGlobalLayout() {
    Log.d("AppLog", "Layout phase");
  }
});

Because of blinking caret - EditText constatly calls invalidate(). This forces the GPU to draw EditText again.

On my nexus 5 (marshmallow) I see that only EditText beeing redrawn (Show GPU view updates - enabled).

enter image description here

like image 197
Dominik Suszczewicz Avatar answered Oct 05 '22 09:10

Dominik Suszczewicz


How about overriding dispatchOnPreDraw() all the vies you use in activity and having flag to check whether that specific view needs to redraw ?

As you need to disable redraw of all other views only when a text view is on focus. So when a text view is on focus have a flag to disable the redrawing of other views.

if dispatchOnPreDraw() method returns false then refreshing of view will be continues else not. I don't know how complex is your layout and how many views are used, but here a separate class should extent a view used and override that method, and also need a mechanism/variable to distinguish the object in current focus.

Hope this method helps!

like image 40
Charan Pai Avatar answered Oct 05 '22 10:10

Charan Pai