James Ko
James Ko

Reputation: 34529

Android: How to run a callback right after setText() is rendered

I want to display some text in an EditText and do some work right away after the text is displayed. I have the following code in my onCreate() method:

this.editor.setText(text, TextView.BufferType.EDITABLE);
new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
    @Override
    public void run() {
        // Work that needs to be done right after the text is displayed
    }
}, 1000);

This works OK, but I want to minimize the delay between setText() rendering and the work being done-- a 1s delay is unacceptable. However, if I change the delay to 0ms or 1ms, then the work is done before the text gets rendered.

I could keep typing in numbers to search for the perfect delay time that would execute my code just after the text was rendered, but that seems very tedious/imprecise. Is there a better way to tell Android to run a callback right after that happens? Thanks.

edit: Here are two things I've tried that didn't work. For bonus points, it would be very helpful if you could explain to me why these didn't work.

Using Handler.post

new Handler(Looper.getMainLooper()).post(r) also runs r before the text finishes rendering. I thought setText adds rendering code to the queue, so shouldn't post(r) being called after that add r after the rendering code?

Using View.post

this.editor.post(r) didn't work either, r is still called before the text is rendered.

Upvotes: 2

Views: 1077

Answers (4)

James Ko
James Ko

Reputation: 34529

I initially wanted to delay the work because it was CPU-intensive. I realized the solution was to spin up a new thread for the work, rather than post it to the UI thread.

Upvotes: 0

Kingfisher Phuoc
Kingfisher Phuoc

Reputation: 8190

You can use ViewTreeObserver as below:

yourView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {
            // do your work here. This call back will be called after view is rendered.
            yourView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
            // or below API 16: yourView.getViewTreeObserver().removeGlobalOnLayoutListener(this);

        }
    });

Upvotes: 1

EdmDroid
EdmDroid

Reputation: 1360

You can assign a TextWatcher to your EditText.

A TextWatcher is basically a listener that listens for changes to the text (before, during and after) in the EditText.

It can be implemented as follows:

EditText et;
et.addTextChangedListener(new TextWatcher() {
    public void afterTextChanged(Editable s) {
        // Work that needs to be done right after the text is displayed
    }
    public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
    public void onTextChanged(CharSequence s, int start, int before, int count) {}
}

So when you set the text explicitly, this listener should be called and after the text is changed, the // Work that needs to be done right after the text is displayed code will be run.

Upvotes: 1

Reyansh Mishra
Reyansh Mishra

Reputation: 1915

Use this it would hlp

mSongNameTextView.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {

            }

            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {

            }

            @Override
            public void afterTextChanged(Editable s) {

            }
        });

Upvotes: 1

Related Questions