Fragment - removeGlobalOnLayoutListener IllegalStateException

前端 未结 3 1937
一向
一向 2020-12-09 03:35

I\'m trying to get the height and width of an ImageView in a Fragment with the following ViewTreeObserver:

import andr         


        
3条回答
  •  鱼传尺愫
    2020-12-09 04:17

    Better try to check if a getViewTreeObserver is alive. I think the following code will work. Based on https://stackoverflow.com/a/15301092/2914140, https://stackoverflow.com/a/26193736/2914140 and some others.

    ** Update **

    After reading Remove listener from ViewTreeObserver, https://stackoverflow.com/a/40013262/2914140 I rewrote a bit.

    public static void captureGlobalLayout(@NonNull final View view,
                                           @NonNull final ViewTreeObserver.OnGlobalLayoutListener listener) {
        ViewTreeObserver vto = view.getViewTreeObserver();
        if (vto.isAlive()) {
            vto.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
                        @Override
                        public void onGlobalLayout() {
                            ViewTreeObserver vto = view.getViewTreeObserver();
                            if (vto.isAlive()) {
                                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
                                    vto.removeOnGlobalLayoutListener(this);
                                } else {
                                    //noinspection deprecation
                                    vto.removeGlobalOnLayoutListener(this);
                                }
                                listener.onGlobalLayout();
                            }
                        }
                    });
        } else {
            view.post(new Runnable() {
                @Override
                public void run() {
                    listener.onGlobalLayout();
                }
            });
    
        }
    }
    

    ** Old answer **

    Strange but even if view.getViewTreeObserver().isAlive() is true, then next call to view.getViewTreeObserver() may again produce the same exception. So, I surrounded a code with try-catch. Possibly you may skip all this and retain only view.post(...) block.

    if (view.getViewTreeObserver().isAlive()) {
        try {
            view.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
                @Override
                public void onGlobalLayout() {
                    if (view.getViewTreeObserver().isAlive()) {
                        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
                            view.getViewTreeObserver().removeOnGlobalLayoutListener(this);
                        } else {
                            view.getViewTreeObserver().removeGlobalOnLayoutListener(this);
                        }
                    }
                    yourCode();
                }
            });
        } catch (IllegalStateException e) {
            e.printStackTrace();
            // The same as below branch.
            getActivity().runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    view.post(new Runnable() {
                        @Override
                        public void run() {
                            yourCode();
                        }
                    });
                }
            });
        }
    } else {
        getActivity().runOnUiThread(new Runnable() {
            @Override
            public void run() {
                // Try to wait until the view is ready.
                view.post(new Runnable() {
                    @Override
                    public void run() {
                        yourCode();
                    }
                });
            }
        });
    }
    

    Probably view.post(...) is enough, but I called it from background thread, so if you do the same, better should invoke it from runOnUiThread(new Runnable() ....

提交回复
热议问题