Personal blog portal

preface

Request(real) does not start loading until the size of the image component is ready

// GenericRequest
	public void begin(a) {
        startTime = LogTime.getLogTime();
        if (model == null) {
            onException(null);
            return;
        }

        status = Status.WAITING_FOR_SIZE;
        if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
        	// Specify a specific size
            onSizeReady(overrideWidth, overrideHeight);
        } else {
        	OnSizeReady () = onSizeReady();
            target.getSize(this);
        }

        if(! isComplete() && ! isFailed() && canNotifyStatusChanged()) { target.onLoadStarted(getPlaceholderDrawable()); }if (Log.isLoggable(TAG, Log.VERBOSE)) {
            logV("finished run method in "+ LogTime.getElapsedMillis(startTime)); }}Copy the code

We refer to the Android Glide 3.7.0 source code parsing, (2) from an image loading process to see the source code The article introduces the process, can get the target is a GlideDrawableImageViewTarget type, So how do YOU get size

How to get size

// GlideDrawableImageViewTarget

	private final SizeDeterminer sizeDeterminer;
	@Override
    public void getSize(SizeReadyCallback cb) {
        sizeDeterminer.getSize(cb);
    }

// SizeDeterminer
	public void getSize(SizeReadyCallback cb) {
			// Calculate the current View width and height code
            int currentWidth = getViewWidthOrParam();
            int currentHeight = getViewHeightOrParam();
            // Start counting the width and height of the View directly. If it is >0 or WRAP_CONTENT(-2), it is valid
            if (isSizeValid(currentWidth) && isSizeValid(currentHeight)) {
            	// The View is loaded and the width and height are calculated
                cb.onSizeReady(currentWidth, currentHeight);
            } else {
                if(! cbs.contains(cb)) { cbs.add(cb); }if (layoutListener == null) {
                	/ / listen to refresh the View to register, hope the View finish loading, SizeDeterminerLayoutListener to receive notification events
                    final ViewTreeObserver observer = view.getViewTreeObserver();
                    layoutListener = new SizeDeterminerLayoutListener(this); observer.addOnPreDrawListener(layoutListener); }}}private boolean isSizeValid(int size) {
            return size > 0 || size == LayoutParams.WRAP_CONTENT;
        }
Copy the code

IsSizeValid >0 is valid. Size == layoutparams.wrap_content is valid. In fact, after the analysis, it seems that this judgment condition is not used

Two questions need to be clarified:

  1. How do the getViewWidthOrParam() and getViewHeightOrParam() methods calculate the width and height
  2. SizeDeterminerLayoutListener after monitoring the change of the View, and did some what

The basic function that calculates Size

Let’s see how to calculate the width and height of the View in its current state (which may not be fully loaded)

// SizeDeterminer
	private static final int PENDING_SIZE = 0;
	private int getViewHeightOrParam(a) {
            final LayoutParams layoutParams = view.getLayoutParams();
            if (isSizeValid(view.getHeight())) {
            	// getHeight if >0
                return view.getHeight();
            } else if(layoutParams ! =null) {
            	// Other circumstances
                return getSizeForParam(layoutParams.height, true /*isHeight*/);
            } else {
            	// Failure 0 is returned by default
                returnPENDING_SIZE; }}private int getViewWidthOrParam(a) {
            final LayoutParams layoutParams = view.getLayoutParams();
            if (isSizeValid(view.getWidth())) {
            	// Directly getWidth if >0
                return view.getWidth();
            } else if(layoutParams ! =null) {
            	// Other circumstances
                return getSizeForParam(layoutParams.width, false /*isHeight*/);
            } else {
            	// Failure 0 is returned by default
                returnPENDING_SIZE; }}// WRAP_CONTETNT case calculation
        private int getSizeForParam(int param, boolean isHeight) {
            if (param == LayoutParams.WRAP_CONTENT) {
            	// Calculate the core code of WRAP_CONTETNT
                Point displayDimens = getDisplayDimens();
                return isHeight ? displayDimens.y : displayDimens.x;
            } else {
                returnparam; }}private Point getDisplayDimens(a) {
            if(displayDimens ! =null) {
                return displayDimens;
            }
            WindowManager windowManager = (WindowManager) view.getContext().getSystemService(Context.WINDOW_SERVICE);
            // Get the display area of the View
            Display display = windowManager.getDefaultDisplay();
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2) {
                displayDimens = new Point();
                display.getSize(displayDimens);
            } else {
                displayDimens = new Point(display.getWidth(), display.getHeight());
            }
            return displayDimens;
        }
Copy the code

So far, we have looked at the functions that calculate the size of the View (getViewWidthOrParam()/getViewHeightOrParam()). The principle is simple

  1. GetHeight/getWidth can calculate a value greater than 0, which prevails
  2. LayoutParams. WRAP_CONTENT or LayoutParams. MATCH_PARENT, windowManager. GetDefaultDisplay () to get a View of the display area

Simply draw a flow chart3. One is to return 0 or MATCH_PARENT, which means I didn’t calculate it. One is returned getHeight/getWidth or windowManager getDefaultDisplay (), said I calculated

Analysis of the basic calculation of wide high function, we take a look at, SizeDeterminerLayoutListener to monitor the View refresh after all did what

Listen to View refresh

// SizeDeterminerLayoutListener
	private static class SizeDeterminerLayoutListener implements ViewTreeObserver.OnPreDrawListener {
            private final WeakReference<SizeDeterminer> sizeDeterminerRef;

            public SizeDeterminerLayoutListener(SizeDeterminer sizeDeterminer) {
                sizeDeterminerRef = new WeakReference<SizeDeterminer>(sizeDeterminer);
            }

            @Override
            public boolean onPreDraw(a) {
                // View refresh callback
                SizeDeterminer sizeDeterminer = sizeDeterminerRef.get();
                if(sizeDeterminer ! =null) {
                	// SizeDeterminer to check whether the current View's width and height are valid
                    sizeDeterminer.checkCurrentDimens();
                }
                return true; }}// SizeDeterminer
	private void checkCurrentDimens(a) {
            if (cbs.isEmpty()) {
                return;
            }

			// Recalculate the width
            int currentWidth = getViewWidthOrParam();
            int currentHeight = getViewHeightOrParam();
            if(! isSizeValid(currentWidth) || ! isSizeValid(currentHeight)) {return;
            }
			
			GenericRequest is notified that the width and height are valid
            notifyCbs(currentWidth, currentHeight);
            
            // Remove listening for View refresh
            ViewTreeObserver observer = view.getViewTreeObserver();
            if (observer.isAlive()) {
                observer.removeOnPreDrawListener(layoutListener);
            }
            layoutListener = null;
        }
	
	private void notifyCbs(int width, int height) {
            for (SizeReadyCallback cb : cbs) {
            	// GenericRequest instance
                cb.onSizeReady(width, height);
            }
            cbs.clear();
        }
Copy the code

The logic is simple

  1. The View refresh the
  2. Calculate wide high again, effective – > GenericRequest. OnSizeReady

() Start loading images; Remove refresh listener 3. Calculate width and height again, invalid -> do nothing, continue to wait

summary

So with that said, let’s summarize the process