Having analyzed the first step of Glide construction RequesManager lifecycle listening and the second step of RequestBuilder request data encapsulation, it is time to send the third step request

 Glide.with(this)
            .load(uri)
            .skipMemoryCache(true)
            .into(iv_activity)
Copy the code

directory

Imanage (Target); Imanage (Target); Imanage (Target)

Encapsulate Imanage as Target

So normally we’re going to call into ImageView, but we’re going to call into(Target)

RequestBuilder.java

private <Y extends Target<TranscodeType>> Y into(
      @NonNull Y target,
      @NullableRequestListener<TranscodeType> targetListener, BaseRequestOptions<? > options, Executor callbackExecutor)
Copy the code

1.1 How is ImageView encapsulated as Target

RequestBuilder.java

public ViewTarget<ImageView, TranscodeType> into(@NonNull ImageView view) {
	// Check if it is in the main thread
    Util.assertMainThread();
    Preconditions.checkNotNull(view);
	// Get all configuration informationBaseRequestOptions<? > requestOptions =this;
    if(! requestOptions.isTransformationSet() && requestOptions.isTransformationAllowed() && view.getScaleType() ! =null) {
      // Clone in this method so that if we use this RequestBuilder to load into a View and then
      // into a different target, we don't retain the transformation applied based on the previous
      // View's scale type.
      // Request configuration assignment based on scale type
      switch (view.getScaleType()) {
        case CENTER_CROP:
          requestOptions = requestOptions.clone().optionalCenterCrop();
          break;
        case CENTER_INSIDE:
          requestOptions = requestOptions.clone().optionalCenterInside();
          break;
        case FIT_CENTER:
        case FIT_START:
        case FIT_END:
          requestOptions = requestOptions.clone().optionalFitCenter();
          break;
        case FIT_XY:
          requestOptions = requestOptions.clone().optionalCenterInside();
          break;
        case CENTER:
        case MATRIX:
        default:
          // Do nothing.}}return into(
    	// Start creating Tartget
        glideContext.buildImageViewTarget(view, transcodeClass),
        /*targetListener=*/ null.// All requests are configured
        requestOptions,
        // Callback thread
        Executors.mainThreadExecutor());
  }
Copy the code

1.2 Get The Target object is obtained through the factory method

glideContext.buildImageViewTarget(view, transcodeClass),

GlideContext.java

public <X> ViewTarget<ImageView, X> buildImageViewTarget(
     @NonNull ImageView imageView, @NonNull Class<X> transcodeClass) {
   return imageViewTargetFactory.buildTarget(imageView, transcodeClass);
 }
Copy the code

The imageViewTargetFactory is new and assigned when Glide is created

GlideContext.java

public GlideContext(
     @NonNull Context context,
     @NonNull ArrayPool arrayPool,
     @NonNull Registry registry,
     @NonNull ImageViewTargetFactory imageViewTargetFactory,
     @NonNull RequestOptionsFactory defaultRequestOptionsFactory,
     @NonNullMap<Class<? >, TransitionOptions<? ,? >> defaultTransitionOptions,@NonNull List<RequestListener<Object>> defaultRequestListeners,
     @NonNull Engine engine,
     boolean isLoggingRequestOriginsEnabled,
     int logLevel) {
   super(context.getApplicationContext()); ...this.imageViewTargetFactory = imageViewTargetFactory; Glide...}.java
 
 Glide(
     @NonNull Context context,
     @NonNull Engine engine,
     @NonNull MemoryCache memoryCache,
     @NonNull BitmapPool bitmapPool,
     @NonNull ArrayPool arrayPool,
     @NonNull RequestManagerRetriever requestManagerRetriever,
     @NonNull ConnectivityMonitorFactory connectivityMonitorFactory,
     int logLevel,
     @NonNull RequestOptionsFactory defaultRequestOptionsFactory,
     @NonNullMap<Class<? >, TransitionOptions<? ,? >> defaultTransitionOptions,@NonNull List<RequestListener<Object>> defaultRequestListeners,
     boolean isLoggingRequestOriginsEnabled,
     boolean isImageDecoderEnabledForBitmaps) {···· ImageViewTargetFactory ImageViewTargetFactory =new ImageViewTargetFactory();
   glideContext =
       new GlideContext(
           context,
           arrayPool,
           registry,
           imageViewTargetFactory,
           defaultRequestOptionsFactory,
           defaultTransitionOptions,
           defaultRequestListeners,
           engine,
           isLoggingRequestOriginsEnabled,
           logLevel);
 }
Copy the code

ImageViewTargetFactory is a factory class that returns the corresponding Tartget based on the input type, Before we call glideContext. BuildImageViewTarget (view, transcodeClass), incoming ImageView, so the return is BitmapImageViewTarget

ImageViewTargetFactory

public class ImageViewTargetFactory {
 @NonNull
 @SuppressWarnings("unchecked")
 public <Z> ViewTarget<ImageView, Z> buildTarget(
     @NonNull ImageView view, @NonNull Class<Z> clazz) {
   if (Bitmap.class.equals(clazz)) {
     return (ViewTarget<ImageView, Z>) new BitmapImageViewTarget(view);
   } else if (Drawable.class.isAssignableFrom(clazz)) {
     return (ViewTarget<ImageView, Z>) new DrawableImageViewTarget(view);
   } else {
     throw new IllegalArgumentException(
         "Unhandled class: " + clazz + ", try .as*(Class).transcode(ResourceTranscoder)"); }}}Copy the code

1.3 BitmapImageViewTarget

BitmapImageViewTarget.java

public class BitmapImageViewTarget extends ImageViewTarget<Bitmap> {
 // Public API.
 @SuppressWarnings("WeakerAccess")
 public BitmapImageViewTarget(ImageView view) {
   super(view);
 }

 / * *@deprecated Use {@link #waitForLayout()} instead. */
 // Public API.
 @SuppressWarnings({"unused", "deprecation"})
 @Deprecated
 public BitmapImageViewTarget(ImageView view, boolean waitForLayout) {
   super(view, waitForLayout);
 }

 /**
  * Sets the {@link android.graphics.Bitmap} on the view using {@link
  * android.widget.ImageView#setImageBitmap(android.graphics.Bitmap)}.
  *
  * @param resource The bitmap to display.
  */
 @Override
 protected void setResource(Bitmap resource) {
 	// Set the resource to ImageView after the request is returned successfullyview.setImageBitmap(resource); }}Copy the code

BitmapImageViewTarget is a subclass of ImageViewTarget. IamgerViewTarget controls the display of successful content and failed booth map, and controls the animation display.

Assemble Target as Request to start the Request

We know that either into(ImageView) or into(Target) ends up calling the following method

RequestBuilder.java

private <Y extends Target<TranscodeType>> Y into(
      @NonNull Y target,
      @NullableRequestListener<TranscodeType> targetListener, BaseRequestOptions<? > options, Executor callbackExecutor) {
    // Check that target is not null
    Preconditions.checkNotNull(target);
    if(! isModelSet) {throw new IllegalArgumentException("You must call #load() before calling #into()");
    }
	// Encapsulate Request 2.1Request request = buildRequest(target, targetListener, options, callbackExecutor); ...return target;
  }

Copy the code

2.1 packaging Request

Call Request Request = buildRequest(target, targetListener, options, callbackExecutor); To encapsulate the Request

RequestBuilder.java

private Request buildRequest(
      Target<TranscodeType> target,
      @NullableRequestListener<TranscodeType> targetListener, BaseRequestOptions<? > requestOptions, Executor callbackExecutor) {
    return buildRequestRecursive(
        /*requestLock=*/ new Object(),
        target,
        targetListener,
        /*parentCoordinator=*/ null,
        transitionOptions,
        requestOptions.getPriority(),
        requestOptions.getOverrideWidth(),
        requestOptions.getOverrideHeight(),
        requestOptions,
        callbackExecutor);
  }
Copy the code

2.2 Encapsulate the master request and the error graph request

RequestBuilder.java 
  
private Request buildRequestRecursive(
      Object requestLock,
      Target<TranscodeType> target,
      @Nullable RequestListener<TranscodeType> targetListener,
      @Nullable RequestCoordinator parentCoordinator,
      TransitionOptions<?, ? super TranscodeType> transitionOptions,
      Priority priority,
      int overrideWidth,
      intoverrideHeight, BaseRequestOptions<? > requestOptions, Executor callbackExecutor) {··· ErrorRequestCoordinator ErrorRequestCoordinator =null;
    if(errorBuilder ! =null) {
      errorRequestCoordinator = new ErrorRequestCoordinator(requestLock, parentCoordinator);
      parentCoordinator = errorRequestCoordinator;
    }
   
   
   // Create the main image request including the thumbnail request
    Request mainRequest =
        buildThumbnailRequestRecursive(
            requestLock,
            target,
            targetListener,
            parentCoordinator,
            transitionOptions,
            priority,
            overrideWidth,
            overrideHeight,
            requestOptions,
            callbackExecutor);
    if (errorRequestCoordinator == null) {
      returnmainRequest; }...// Create an error request
    Request errorRequest =
        errorBuilder.buildRequestRecursive(
            requestLock,
            target,
            targetListener,
            errorRequestCoordinator,
            errorBuilder.transitionOptions,
            errorBuilder.getPriority(),
            errorOverrideWidth,
            errorOverrideHeight,
            errorBuilder,
            callbackExecutor);
    errorRequestCoordinator.setRequests(mainRequest, errorRequest);
    return errorRequestCoordinator;
  }
Copy the code

2.2.1 Request coordinator encapsulation

Return errorRequestCoordinator; The errorRequestCoordinator is a Request and a RequestCoordinator. The errorRequestCoordinator adopts the responsibility chain mode. This sentence errorRequestCoordinator setRequests (mainRequest errorRequest); The next request that represents a request is errorRequest, so let’s look at the source code

ErrorRequestCoordinator.java

public final class ErrorRequestCoordinator implements RequestCoordinator.Request {

  private final Object requestLock;
  @Nullable private final RequestCoordinator parent;// Last request

  private volatile Request primary;// Current request
  private volatile Request error;// Next request

  @GuardedBy("requestLock")
  private RequestState primaryState = RequestState.CLEARED;

  @GuardedBy("requestLock")
  private RequestState errorState = RequestState.CLEARED;

  public ErrorRequestCoordinator(Object requestLock, @Nullable RequestCoordinator parent) {
    this.requestLock = requestLock;
    // This is null because it is the main request with an error request
    this.parent = parent;
  }

  public void setRequests(Request primary, Request error) {
  	// Here is the main request
    this.primary = primary;
    // Error request
    this.error = error;
  }

  @Override
  public void begin(a) {
    synchronized (requestLock) {
      if(primaryState ! = RequestState.RUNNING) { primaryState = RequestState.RUNNING;// The main request starts the requestprimary.begin(); }}}...@Override
  public void onRequestSuccess(Request request) {
    synchronized (requestLock) {
     // Set the success status if the main request succeeds
      if (request.equals(primary)) {
        primaryState = RequestState.SUCCESS;
      } else if (request.equals(error)) {
      // Set the success status if the error request succeeds
        errorState = RequestState.SUCCESS;
      }
      if(parent ! =null) {
      	//
        parent.onRequestSuccess(this); }}}@Override
  public void onRequestFailed(Request request) {
    synchronized (requestLock) {
    // Master request failed, set status
      if(! request.equals(error)) { primaryState = RequestState.FAILED;if(errorState ! = RequestState.RUNNING) { errorState = RequestState.RUNNING;// Start error request
          error.begin();
        }
        return;
      }

      errorState = RequestState.FAILED;

      if(parent ! =null) {
        parent.onRequestFailed(this); }}}@Override
  public RequestCoordinator getRoot(a) {
    synchronized (requestLock) {
      returnparent ! =null ? parent.getRoot() : this; }}}Copy the code

2.3 Encapsulate master image request and thumbnail image request

RequestBuilder.java 
  
 // Create a thumbnail request
private Request buildThumbnailRequestRecursive(
      Object requestLock,
      Target<TranscodeType> target,
      RequestListener<TranscodeType> targetListener,
      @Nullable RequestCoordinator parentCoordinator,
      TransitionOptions<?, ? super TranscodeType> transitionOptions,
      Priority priority,
      int overrideWidth,
      intoverrideHeight, BaseRequestOptions<? > requestOptions, Executor callbackExecutor) {
      
    // If you set the builder of the thumbnail request
    if(thumbnailBuilder ! =null) {
      // Recursive case: contains a potentially recursive thumbnail request builder.... TransitionOptions <? ,?super TranscodeType> thumbTransitionOptions =
          thumbnailBuilder.transitionOptions;

      // Apply our transition by default to thumbnail requests but avoid overriding custom options
      // that may have been applied on the thumbnail request explicitly.
      if (thumbnailBuilder.isDefaultTransitionOptionsSet) {
        thumbTransitionOptions = transitionOptions;
      }

      Priority thumbPriority =
          thumbnailBuilder.isPrioritySet()
              ? thumbnailBuilder.getPriority()
              : getThumbnailPriority(priority);
	···

      ThumbnailRequestCoordinator coordinator =
          new ThumbnailRequestCoordinator(requestLock, parentCoordinator);
      // Create the main diagram request
      Request fullRequest =
          obtainRequest(
              requestLock,
              target,
              targetListener,
              requestOptions,
              coordinator,
              transitionOptions,
              priority,
              overrideWidth,
              overrideHeight,
              callbackExecutor);
      isThumbnailBuilt = true;
      // Recursively generate thumbnail requests.
      // Create a thumbnail request
      Request thumbRequest =
          thumbnailBuilder.buildRequestRecursive(
              requestLock,
              target,
              targetListener,
              coordinator,
              thumbTransitionOptions,
              thumbPriority,
              thumbOverrideWidth,
              thumbOverrideHeight,
              thumbnailBuilder,
              callbackExecutor);
      isThumbnailBuilt = false;
      coordinator.setRequests(fullRequest, thumbRequest);
      return coordinator;
      // Thumbnail size builder is not empty
    } else if(thumbSizeMultiplier ! =null) {
      // Base case: thumbnail multiplier generates a thumbnail request, but cannot recurse.
      ThumbnailRequestCoordinator coordinator =
          new ThumbnailRequestCoordinator(requestLock, parentCoordinator);
      // Create the main diagram requestRequest fullRequest = obtainRequest( requestLock, target, targetListener, requestOptions, coordinator, transitionOptions, priority, overrideWidth, overrideHeight, callbackExecutor); BaseRequestOptions<? > thumbnailOptions = requestOptions.clone().sizeMultiplier(thumbSizeMultiplier);// Create a thumbnail request
      Request thumbnailRequest =
          obtainRequest(
              requestLock,
              target,
              targetListener,
              thumbnailOptions,
              coordinator,
              transitionOptions,
              getThumbnailPriority(priority),
              overrideWidth,
              overrideHeight,
              callbackExecutor);

      coordinator.setRequests(fullRequest, thumbnailRequest);
      return coordinator;
    } else {
      // Base case: no thumbnail.
      // Create the main image request without setting the thumbnail
      returnobtainRequest( requestLock, target, targetListener, requestOptions, parentCoordinator, transitionOptions, priority, overrideWidth, overrideHeight, callbackExecutor); }}Copy the code

2.4 Creating a Request

RequestBuilder.java 

private Request obtainRequest( Object requestLock, Target<TranscodeType> target, RequestListener<TranscodeType> targetListener, BaseRequestOptions<? > requestOptions, RequestCoordinator requestCoordinator, TransitionOptions<? ,?super TranscodeType> transitionOptions,
      Priority priority,
      int overrideWidth,
      int overrideHeight,
      Executor callbackExecutor) {
    return SingleRequest.obtain(
        context,
        glideContext,
        requestLock,
        model,
        transcodeClass,
        requestOptions,
        overrideWidth,
        overrideHeight,
        priority,
        target,
        targetListener,
        requestListeners,
        requestCoordinator,
        glideContext.getEngine(),
        transitionOptions.getTransitionFactory(),
        callbackExecutor);
  }
  
 SingleRequest.java
 
  public static <R> SingleRequest<R> obtain( Context context, GlideContext glideContext, Object requestLock, Object model, Class<R> transcodeClass, BaseRequestOptions<? > requestOptions,int overrideWidth,
      int overrideHeight,
      Priority priority,
      Target<R> target,
      RequestListener<R> targetListener,
      @Nullable List<RequestListener<R>> requestListeners,
      RequestCoordinator requestCoordinator,
      Engine engine,
      TransitionFactory<? super R> animationFactory,
      Executor callbackExecutor) {
    return new SingleRequest<>(
        context,
        glideContext,
        requestLock,
        model,
        transcodeClass,
        requestOptions,
        overrideWidth,
        overrideHeight,
        priority,
        target,
        targetListener,
        requestListeners,
        requestCoordinator,
        engine,
        animationFactory,
        callbackExecutor);
  }
  
  
private SingleRequest(
      Context context,
      GlideContext glideContext,
      @NonNull Object requestLock,
      @NullableObject model, Class<R> transcodeClass, BaseRequestOptions<? > requestOptions,int overrideWidth,
      int overrideHeight,
      Priority priority,
      Target<R> target,
      @Nullable RequestListener<R> targetListener,
      @Nullable List<RequestListener<R>> requestListeners,
      RequestCoordinator requestCoordinator,
      Engine engine,
      TransitionFactory<? super R> animationFactory,
      Executor callbackExecutor) {
    this.requestLock = requestLock;
    this.context = context;
    this.glideContext = glideContext;
    this.model = model;
    this.transcodeClass = transcodeClass;
    this.requestOptions = requestOptions;
    this.overrideWidth = overrideWidth;
    this.overrideHeight = overrideHeight;
    this.priority = priority;
    this.target = target;
    this.targetListener = targetListener;
    this.requestListeners = requestListeners;
    this.requestCoordinator = requestCoordinator;
    this.engine = engine;
    this.animationFactory = animationFactory;
    this.callbackExecutor = callbackExecutor;
    status = Status.PENDING;

    if (requestOrigin == null && glideContext.isLoggingRequestOriginsEnabled()) {
      requestOrigin = new RuntimeException("Glide request origin trace"); }}Copy the code

Create the real SingleRequest request as a static factory

Handle repeated Target requests

If you have the same image request in Target, you can request it directly to improve performance

RequestBuilder.java

private <Y extends Target<TranscodeType>> Y into(
      @NonNull Y target,
      @NullableRequestListener<TranscodeType> targetListener, BaseRequestOptions<? > options, Executor callbackExecutor) {
    

	// Retrieve the Request saved before target
    Request previous = target.getRequest();
    // If target stores a request equal to the newly created request (including size) and target's request is not cached in memory and loaded
    if(request.isEquivalentTo(previous) && ! isSkipMemoryCacheWithCompletePreviousRequest(options, previous)) {// If the request is completed, beginning again will ensure the result is re-delivered,
      // triggering RequestListeners and Targets. If the request is failed, beginning again will
      // restart the request, giving it another chance to complete. If the request is already
      // running, we can let it continue running without interruption.
      //target Is not in the request
      if(! Preconditions.checkNotNull(previous).isRunning()) {// Use the previous request rather than the new one to allow for optimizations like skipping
        // setting placeholders, tracking and un-tracking Targets, and obtaining View dimensions
        // that are done in the individual Request.
        // Call the request directly
        previous.begin();
      }
      return target;
    }
	
    // Clear the following Target
    requestManager.clear(target);
    // Set target's Request
    target.setRequest(request);
    // Follow Request and trigger the Request
    requestManager.track(target, request);

    return target;
  }
  
 private boolean isSkipMemoryCacheWithCompletePreviousRequest( BaseRequestOptions
        options, Request previous) {
    return! options.isMemoryCacheable() && previous.isComplete(); }Copy the code

Four Sending a Request

RequestBuilder.java

private <Y extends Target<TranscodeType>> Y into(
      @NonNull Y target,
      @NullableRequestListener<TranscodeType> targetListener, BaseRequestOptions<? > options, Executor callbackExecutor) {... requestManager. The clear (target); target.setRequest(request);// Used to trigger a request
    requestManager.track(target, request);

    return target;
    
    
synchronized void track(@NonNullTarget<? > target,@NonNull Request request) {
    targetTracker.track(target);
    requestTracker.runRequest(request);
  }
Copy the code

4.1 Tracking the Tartget life cycle

TargetTracker is a targetTracker used to track the Target lifecycle

TargetTracker.java

public final class TargetTracker implements LifecycleListener {
  private finalSet<Target<? >> targets = Collections.newSetFromMap(newWeakHashMap<Target<? >, Boolean>());public void track(@NonNullTarget<? > target) {
    targets.add(target);
  }

  public void untrack(@NonNullTarget<? > target) {
    targets.remove(target);
  }

  @Override
  public void onStart(a) {
    for (Target<?> target : Util.getSnapshot(targets)) {
      target.onStart();
    }
  }

  @Override
  public void onStop(a) {
    for (Target<?> target : Util.getSnapshot(targets)) {
      target.onStop();
    }
  }

  @Override
  public void onDestroy(a) {
    for (Target<?> target : Util.getSnapshot(targets)) {
      target.onDestroy();
    }
  }

  @NonNull
  publicList<Target<? >> getAll() {return Util.getSnapshot(targets);
  }

  public void clear(a) { targets.clear(); }}Copy the code

4.2 Tracing the Request Lifecycle

RequestTracker is a requestTracker used to follow a Request

RequestTracker.java

public class RequestTracker {
  private static final String TAG = "RequestTracker";
  // Trace all requests
  private final Set<Request> requests =
      Collections.newSetFromMap(newWeakHashMap<Request, Boolean>()); / Prepare the request to send@SuppressWarnings("MismatchedQueryAndUpdateOfCollection")
  private final List<Request> pendingRequests = new ArrayList<>();

  private boolean isPaused;

  /** Starts tracking the given request. */
  public void runRequest(@NonNull Request request) {
  	// Add to the please collection
    requests.add(request);
    if(! isPaused) {// Start executing the request if there is no pause
      request.begin();
    } else {
      // If paused, add to the set of pending requests
      request.clear();
      if (Log.isLoggable(TAG, Log.VERBOSE)) {
        Log.v(TAG, "Paused, delaying request"); } pendingRequests.add(request); }}...Copy the code

4.3 Executing a Request

request.begin(); The begin() method of SingleRequest is executed

SingleRequest.java


@Override
  public void begin(a) {
  	/ / synchronization locks
    synchronized(requestLock) {...// Call onResourceReady directly if loading is complete
      if (status == Status.COMPLETE) {
        onResourceReady(resource, DataSource.MEMORY_CACHE);
        return;
      }

      // Restarts for requests that are neither complete nor running can be treated as new requests
      // and can run again from the beginning.
	  // Set the wait size
      status = Status.WAITING_FOR_SIZE;
      if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
        // Where the actual request and cache are
        onSizeReady(overrideWidth, overrideHeight);
      } else {
        // Get the size
        target.getSize(this);
      }

      if ((status == Status.RUNNING || status == Status.WAITING_FOR_SIZE)
          && canNotifyStatusChanged()) {
        // The first load should go here
        target.onLoadStarted(getPlaceholderDrawable());
      }
      if (IS_VERBOSE_LOGGABLE) {
        logV("finished run method in "+ LogTime.getElapsedMillis(startTime)); }}}Copy the code

GetPlaceholderDrawable () gets a placeholder for the image to display when loading

SingleRequest.java

 private Drawable getPlaceholderDrawable(a) {
    if (placeholderDrawable == null) {
      placeholderDrawable = requestOptions.getPlaceholderDrawable();
      if (placeholderDrawable == null && requestOptions.getPlaceholderId() > 0) { placeholderDrawable = loadDrawable(requestOptions.getPlaceholderId()); }}return placeholderDrawable;
  }
Copy the code

OnLoadStarted (getPlaceholderDrawable()); onLoadStarted(” onLoadStarted “)

ViewTarget.java

public void onLoadStarted(@Nullable Drawable placeholder) {
    super.onLoadStarted(placeholder);
    maybeAddAttachStateListener();
  }
  
private void maybeAddAttachStateListener(a) {
    if (attachStateListener == null || isAttachStateListenerAdded) {
      return;
    }
    view.addOnAttachStateChangeListener(attachStateListener);
    isAttachStateListenerAdded = true;
  }
Copy the code

Added an Attach listener to Target that triggers a callback when the view is attached to the view

ViewTarget.java

attachStateListener =
        new OnAttachStateChangeListener() {
          @Override
          public void onViewAttachedToWindow(View v) {
          // Resume the request
            resumeMyRequest();
          }

          @Override
          public void onViewDetachedFromWindow(View v) {
          // Suspend the requestpauseMyRequest(); }};void resumeMyRequest(a) {
    Request request = getRequest();
    if(request ! =null&& request.isCleared()) { request.begin(); }}void resumeMyRequest(a) {
    Request request = getRequest();
    if(request ! =null&& request.isCleared()) { request.begin(); }}Copy the code