How to know when the RecyclerView has finished laying down the items?

I have a RecyclerView that is inside a CardView. The CardView has a height of 500dp, but I want to shorten this height if the RecyclerView is smaller.
So I wonder if there is any listener that is called when the RecyclerView has finished laying down its items for the first time, making it possible to set the RecyclerView’s height to the CardView’s height (if smaller than 500dp).

  • Recommended way to load (non-interactive) animations (made using Maya) into OpenGL ES on iOS and Android
  • Android Architecture Design - How to do it right?
  • What's LazyList?
  • dexedLibs folder in android project
  • Custom getFilter in custom ArrayAdapter in android
  • Android: Bulk Insert, when InsertHelper is deprecated
  • How to create map tiles from OpenStreetMap offline, display it on Android?
  • java.lang.ClassCastException: libcore.net.http.HttpURLConnectionImpl cannot be cast to javax.net.ssl.HttpsURLConnection
  • Kiosk mode in Android
  • Could a service bind another service
  • Is it possible to disable scrolling on a ViewPager
  • Android tabhost change text color style
  • 5 Solutions collect form web for “How to know when the RecyclerView has finished laying down the items?”

    I also needed to execute code after my recycler view finished inflating all elements. I tried checking in onBindViewHolder in my Adapter, if the position was the last, and then notified the observer. But at that point, the recycler view still was not fully populated.

    As RecyclerView implements ViewGroup, this anwser was very helpful. You simply need to add an OnGlobalLayoutListener to the recyclerView:

    View recyclerView=findViewById(R.id.myView);
          recyclerView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
                    @Override
                    public void onGlobalLayout() {
                        //At this point the layout is complete and the 
                        //dimensions of recyclerView and any child views are known.
                    }
                });
    

    Working modification of @andrino anwser.

    As @Juancho pointed in comment above. This method is called several times. In this case we want it to be triggered only once.

    Created custom listener with instance e.g

    private RecyclerViewReadyCallback recyclerViewReadyCallback;
    
    public interface RecyclerViewReadyCallback {
        void onLayoutReady();
    }
    

    Then set OnGlobalLayoutListener on your RecyclerView

    recyclerView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
                @Override
                public void onGlobalLayout() {
                    if (recyclerViewReadyCallback != null) {
                        recyclerViewReadyCallback.onLayoutReady();
                    }
                    recyclerViewReadyCallback = null;
                }
            });
    

    after that you only need implement custom listener with your code

    recyclerViewReadyCallback = new RecyclerViewReadyCallback() {
                 @Override
                 public void onLayoutReady() {
                     //
                     //here comes your code that will be executed after all items has are laid down
                     //
                 }
    };
    

    I have been struggling with trying to remove OnGlobalLayoutListener once it gets triggered but that throws an IllegalStateException. Since what I need is to scroll my recyclerView to the second element what I did was to check if it already have children and if it is the first time this is true, only then I do the scroll:

    public class MyActivity extends BaseActivity implements BalanceView {
        ...
        private boolean firstTime = true;
        ...
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            ...
    
            ViewTreeObserver vto = myRecyclerView.getViewTreeObserver();
            vto.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
                @Override
                public void onGlobalLayout() {
                    if (myRecyclerView.getChildCount() > 0 && MyActivity.this.firstTime){
                        MyActivity.this.firstTime = false;
                        scrollToSecondPosition();
                    }
                }
            });
        }
        ...
        private void scrollToSecondPosition() {
            // do the scroll
        }
    }
    

    HTH someone!

    (Of course, this was inspired on @andrino and @Phatee answers)

    My requirement was to trigger dropTheBomb when the RV has completed laying out all the views. So in addition to

    mRecyclerView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                    tryToDropTheBomb();
            }
        }); 
    

    and triggered the bomb this way, so that it gets triggered only when the last layout is complete

    private void tryToTriggerTheBomb() {
        lastRequestIndex ++;
        final int requestIndex = lastRequestIndex;
        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                //if requestIndex = lastRequestIndex even after 200 ms
                if(requestIndex == lastRequestIndex) {
                    dropTheBomb();
                    //todo removeTheListener
                }
            }
        }, 200);
    }
    

    What worked for me was to add the listener after setting the RecyclerView adapter.

    ServerRequest serverRequest = new ServerRequest(this);
    serverRequest.fetchAnswersInBackground(question_id, new AnswersDataCallBack()
    {
         @Override
         public void done(ArrayList<AnswerObject> returnedListOfAnswers)
         {
             mAdapter = new ForumAnswerRecyclerViewAdapter(returnedListOfAnswers, ForumAnswerActivity.this);
             recyclerView.setAdapter(mAdapter);
             recyclerView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener()
             {
                 @Override
                 public void onGlobalLayout()
                 {
                     progressDialog.dismiss();
                 }
             });
         }
     });
    

    This dismisses the “progressDialog” after the global layout state or the visibility of views within the view tree changes.

    Android Babe is a Google Android Fan, All about Android Phones, Android Wear, Android Dev and Android Games Apps and so on.