Glide图片框架源码解析

news2025/8/2 17:41:15

一、Glide几个基本概念

  • Model
    表示数据的来源;加载图片的时候需要告诉Glide从哪获取这个图片,可以是url类型、本地文件类型、资源ID类型。不管什么类型,Glide都将其称为Model。

  • Data
    从数据源中获取到model之后,把它加工成原始数据,一般就是InputStream输入流,Glide把 它们称之为Data。负责从数据源中获取原始数据的功能角色称之为ModelLoader。

  • Resource
    负责将得到的原始数据进行解码,比如将InputStream解码成bitmap,而解码之后的资源称之为Resource。而负责解码的功能角色称之为Decoder。

  • TransformedResource
    把Resouce进行变换,比如图片要进行裁剪,调用fitcenter、centerCrop等等方法转换,在Glide方法中采用Resource Transform功能来进行转换,而转换后的资源就称之为TransformedResource。

  • TranscodedResource
    转码,Glide不仅能加载静态图之外,还能加载Gif动态图,但是解码之后的bitmap和gif drawable其实类型都是统一的,为了逻辑方便处理,Glide会把bitmap转换成GlideBitmapDrawable,这样类型就统一了,负责转码的角色称为Transcode,而转码之后的角色称为TranscodedResource

  • Target
    最终将图片显示到目标上,比如ImageView上,这时候Glide就会将要显示的目标封装成Target。

在这里插入图片描述

二、Glide基本使用和参数说明:

Glide.with(getApplicationContext())  //指定Context
                    .load(url) //指定图片的URL
                    .placeholder(R.mipmap.ic_launcher)  //指定图片未成功加载前显示的图片
                    .error(R.mipmap.ic_launcher)  //指定图片加载失败显示的图片
                    .override(300, 300)  //指定图片的尺寸
                    .fitCenter()  //指定图片缩放类型
                    .centerCrop() //指定图片缩放类型
                    .skipMemoryCache(true) //跳过内存缓存,默认为false
                    .crossFade(1000)  //设置渐变式显示的时间
                    .diskCacheStrategy(DiskCacheStrategy.NONE)  //表示不缓存任何内容,跳过磁盘缓存
                    .diskCacheStrategy(DiskCacheStrategy.DATA)  //表示只缓存原始图片,即只缓存原来的全分辨率的图片
                    .diskCacheStrategy(DiskCacheStrategy.RESOURCE) //表示只缓存转换后的图片
                    .diskCacheStrategy(DiskCacheStrategy.ALL) //表示即缓存原始图片,也缓存转换过后的图片
                    .diskCacheStrategy(DiskCacheStrategy.AUTOMATIC) //表示让Glide根据图片资源智能地选择使用哪一种缓存策略(默认选项)
                    .priority(Priority.HIGH)  //指定优先级,Glide将会用他们作为一个准则,并尽可能的处理这些请求,但是它不一定能百分之百保证所有的图片都按照你优先级来加载
                    .into(imageView);  //指定显示图片的ImageView

1. with流程解析

  /**
   * Begin a load with Glide by passing in a context.
   *
   * <p> Any requests started using a context will only have the application level options applied
   * and will not be started or stopped based on lifecycle events. In general, loads should be
   * started at the level the result will be used in. If the resource will be used in a view in a
   * child fragment, the load should be started with {@link #with(android.app.Fragment)}} using that
   * child fragment. Similarly, if the resource will be used in a view in the parent fragment, the
   * load should be started with {@link #with(android.app.Fragment)} using the parent fragment. In
   * the same vein, if the resource will be used in a view in an activity, the load should be
   * started with {@link #with(android.app.Activity)}}. </p>
   *
   * <p> This method is appropriate for resources that will be used outside of the normal fragment
   * or activity lifecycle (For example in services, or for notification thumbnails). </p>
   *
   * @param context Any context, will not be retained.
   * @return A RequestManager for the top level application that can be used to start a load.
   * @see #with(android.app.Activity)
   * @see #with(android.app.Fragment)
   * @see #with(android.support.v4.app.Fragment)
   * @see #with(android.support.v4.app.FragmentActivity)
   */
  @NonNull
  public static RequestManager with(@NonNull Context context) {
    return getRetriever(context).get(context);
  }

  /**
   * Begin a load with Glide that will be tied to the given {@link android.app.Activity}'s lifecycle
   * and that uses the given {@link Activity}'s default options.
   *
   * @param activity The activity to use.
   * @return A RequestManager for the given activity that can be used to start a load.
   */
  @NonNull
  public static RequestManager with(@NonNull Activity activity) {
    return getRetriever(activity).get(activity);
  }

  /**
   * Begin a load with Glide that will tied to the give
   * {@link android.support.v4.app.FragmentActivity}'s lifecycle and that uses the given
   * {@link android.support.v4.app.FragmentActivity}'s default options.
   *
   * @param activity The activity to use.
   * @return A RequestManager for the given FragmentActivity that can be used to start a load.
   */
  @NonNull
  public static RequestManager with(@NonNull FragmentActivity activity) {
    return getRetriever(activity).get(activity);
  }

  /**
   * Begin a load with Glide that will be tied to the given
   * {@link android.support.v4.app.Fragment}'s lifecycle and that uses the given
   * {@link android.support.v4.app.Fragment}'s default options.
   *
   * @param fragment The fragment to use.
   * @return A RequestManager for the given Fragment that can be used to start a load.
   */
  @NonNull
  public static RequestManager with(@NonNull Fragment fragment) {
    return getRetriever(fragment.getActivity()).get(fragment);
  }

  /**
   * Begin a load with Glide that will be tied to the given {@link android.app.Fragment}'s lifecycle
   * and that uses the given {@link android.app.Fragment}'s default options.
   *
   * @param fragment The fragment to use.
   * @return A RequestManager for the given Fragment that can be used to start a load.
   * @deprecated Prefer support Fragments and {@link #with(Fragment)} instead,
   * {@link android.app.Fragment} will be deprecated. See
   * https://github.com/android/android-ktx/pull/161#issuecomment-363270555.
   */
  @SuppressWarnings("deprecation")
  @Deprecated
  @NonNull
  public static RequestManager with(@NonNull android.app.Fragment fragment) {
    return getRetriever(fragment.getActivity()).get(fragment);
  }

  /**
   * Begin a load with Glide that will be tied to the lifecycle of the {@link Fragment},
   * {@link android.app.Fragment}, or {@link Activity} that contains the View.
   *
   * <p>A {@link Fragment} or {@link android.app.Fragment} is assumed to contain a View if the View
   * is a child of the View returned by the {@link Fragment#getView()}} method.
   *
   * <p>This method will not work if the View is not attached. Prefer the Activity and Fragment
   * variants unless you're loading in a View subclass.
   *
   * <p>This method may be inefficient aways and is definitely inefficient for large hierarchies.
   * Consider memoizing the result after the View is attached or again, prefer the Activity and
   * Fragment variants whenever possible.
   *
   * <p>When used in Applications that use the non-support {@link android.app.Fragment} classes,
   * calling this method will produce noisy logs from {@link android.app.FragmentManager}. Consider
   * avoiding entirely or using the {@link Fragment}s from the support library instead.
   *
   * <p>If the support {@link FragmentActivity} class is used, this method will only attempt to
   * discover support {@link Fragment}s. Any non-support {@link android.app.Fragment}s attached
   * to the {@link FragmentActivity} will be ignored.
   *
   * @param view The view to search for a containing Fragment or Activity from.
   * @return A RequestManager that can be used to start a load.
   */
  @NonNull
  public static RequestManager with(@NonNull View view) {
    return getRetriever(view.getContext()).get(view);
  }

with()方法参数可以为Context、Activity、FragmentActivity、Fragment、View。with设计了这么多重装方法就是为了可以灵活根据当前的上下文和组件进行不同图片的操作选择。将图片加载的过程与组件的生命周期进行挂钩。

下面以参数为Activity进行流程阐述:


  /**
   * Begin a load with Glide that will be tied to the given {@link android.app.Activity}'s lifecycle
   * and that uses the given {@link Activity}'s default options.
   *
   * @param activity The activity to use.
   * @return A RequestManager for the given activity that can be used to start a load.
   */
  @NonNull
  public static RequestManager with(@NonNull Activity activity) {
    return getRetriever(activity).get(activity);
  }

getRetriever(activity)是获取RequestManagerRetriever对象

  @NonNull
  public RequestManager get(@NonNull Activity activity) {
    if (Util.isOnBackgroundThread()) { // ①
      return get(activity.getApplicationContext());  
    } else {   // ②
      assertNotDestroyed(activity);
      android.app.FragmentManager fm = activity.getFragmentManager();
      return fragmentGet(
          activity, fm, /*parentHint=*/ null, isActivityVisible(activity));
    }
  }

如果当前是后台线程(即子线程)就走流程①,否则走流程②。

  • 流程①最后是通过getApplicationManager(context)语句DCL单例模式来获取RequestManager对象。
  • 流程②
    RequestManagerFragment 是一种没有UI界面的fragment
    glide添加一种没有界面的fragment到Activity或fragment上,通过这种没有界面RequestManagerFragment 的这个fragment来监听activity或fragment的生命周期,因为glide是无法监听activity的生命周期,从而来完成绑定activity的生命周期,来去选择完成图片加载操作的过程。

通过RequestManager就可以控制整个界面生命周期的监听,用于监听整个组件的生命周期,根据这个生命周期来做图片的相应操作。
RequestManagerFragment 与 RequestManager是一 一对应的

 private RequestManager fragmentGet(@NonNull Context context,
      @NonNull android.app.FragmentManager fm,
      @Nullable android.app.Fragment parentHint,
      boolean isParentVisible) {
    RequestManagerFragment current = getRequestManagerFragment(fm, parentHint, isParentVisible);
    RequestManager requestManager = current.getRequestManager();
    if (requestManager == null) {
      // TODO(b/27524013): Factor out this Glide.get() call.
      Glide glide = Glide.get(context);
      requestManager =
          factory.build(
              glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), context);
      current.setRequestManager(requestManager); // 将RequestManagerFragment这个空界面的fragment与RequestManager图片加载进行绑定,目的就是为了将监听activity生命周期的来管理整个图片加载
    }
    return requestManager;
  }

with方流程总结: 主要是为了获取RequestManager对象,该对象是用于管理请求;通过RequestManagerRetriever生产RequestManager这个类来处理的;
由于glide绑定了组件的生命周期,这样可以根据不同的生命周期来进行相应的处理

2. load流程解析

glide支持多种图片的来源,包含url、本地文件、资源ID等等,从而会重写不同参数类型的load()方法。

interface ModelTypes<T> {
  @NonNull
  @CheckResult
  T load(@Nullable Bitmap bitmap);

  @NonNull
  @CheckResult
  T load(@Nullable Drawable drawable);

  @NonNull
  @CheckResult
  T load(@Nullable String string);

  @NonNull
  @CheckResult
  T load(@Nullable Uri uri);

  @NonNull
  @CheckResult
  T load(@Nullable File file);

  @NonNull
  @CheckResult
  T load(@RawRes @DrawableRes @Nullable Integer resourceId);

  @Deprecated
  @CheckResult
  T load(@Nullable URL url);

  @NonNull
  @CheckResult
  T load(@Nullable byte[] model);

  @NonNull
  @CheckResult
  @SuppressWarnings("unchecked")
  T load(@Nullable Object model);
}

 @Override
  public RequestBuilder<Drawable> load(@Nullable String string) {
    return asDrawable().load(string);
  }
 @NonNull
  @Override
  @CheckResult
  public RequestBuilder<TranscodeType> load(@Nullable String string) {
    return loadGeneric(string);
  }
  @NonNull
  private RequestBuilder<TranscodeType> loadGeneric(@Nullable Object model) {
    this.model = model;
    isModelSet = true;
    return this;
  }

**load总结:**其实也就是一些初始化的创建工作

3. init流程解析

  /**
   * Sets the {@link ImageView} the resource will be loaded into, cancels any existing loads into
   * the view, and frees any resources Glide may have previously loaded into the view so they may be
   * reused.
   *
   * @see RequestManager#clear(Target)
   *
   * @param view The view to cancel previous loads for and load the new resource into.
   * @return The
   * {@link com.bumptech.glide.request.target.Target} used to wrap the given {@link ImageView}.
   */
  @NonNull
  public ViewTarget<ImageView, TranscodeType> into(@NonNull ImageView view) {
    Util.assertMainThread();
    Preconditions.checkNotNull(view);

    BaseRequestOptions<?> 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.
      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(
        glideContext.buildImageViewTarget(view, transcodeClass),
        /*targetListener=*/ null,
        requestOptions,
        Executors.mainThreadExecutor());
  }

Util.assertMainThread(); 这个语句就可以确定into方法必须要在主线程中进行操作,

glideContext.buildImageViewTarget(view, transcodeClass)就是为了构建一个target对象

  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)");
    }
  }

into操作主要就是图片加载,

  1. 首先会对操作是否在主线程中进行判断,
  2. 之后创建所需要的target
private <Y extends Target<TranscodeType>> Y into(
      @NonNull Y target,
      @Nullable RequestListener<TranscodeType> targetListener,
      BaseRequestOptions<?> options,
      Executor callbackExecutor) {
    Preconditions.checkNotNull(target);
    if (!isModelSet) {
      throw new IllegalArgumentException("You must call #load() before calling #into()");
    }

    Request request = buildRequest(target, targetListener, options, callbackExecutor);

    Request previous = target.getRequest();
    if (request.isEquivalentTo(previous)
        && !isSkipMemoryCacheWithCompletePreviousRequest(options, previous)) {
      request.recycle();
      // 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.
      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.
        previous.begin();
      }
      return target;
    }

    requestManager.clear(target);
    target.setRequest(request);  //设置tag,将tag与图片request进行绑定,防止图片错位
    requestManager.track(target, request);

    return target;
  }

RequestManager.java

  synchronized void track(@NonNull Target<?> target, @NonNull Request request) {
    targetTracker.track(target);
    requestTracker.runRequest(request);
  }

RequestTracker.java

  /**
   * Starts tracking the given request.
   */
  public void runRequest(@NonNull Request request) {
    requests.add(request);
    if (!isPaused) {
      request.begin();
    } else {
      request.clear();
      if (Log.isLoggable(TAG, Log.VERBOSE)) {
        Log.v(TAG, "Paused, delaying request");
      }
      pendingRequests.add(request);
    }
  }

SingleRequest.java

 @Override
  public synchronized void begin() {
    assertNotCallingCallbacks();
    stateVerifier.throwIfRecycled();
    startTime = LogTime.getLogTime();
    if (model == null) {
      if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
        width = overrideWidth;
        height = overrideHeight;
      }
      // Only log at more verbose log levels if the user has set a fallback drawable, because
      // fallback Drawables indicate the user expects null models occasionally.
      int logLevel = getFallbackDrawable() == null ? Log.WARN : Log.DEBUG;
      onLoadFailed(new GlideException("Received null model"), logLevel);
      return;
    }

    if (status == Status.RUNNING) {
      throw new IllegalArgumentException("Cannot restart a running request");
    }

    // If we're restarted after we're complete (usually via something like a notifyDataSetChanged
    // that starts an identical request into the same Target or View), we can simply use the
    // resource and size we retrieved the last time around and skip obtaining a new size, starting a
    // new load etc. This does mean that users who want to restart a load because they expect that
    // the view size has changed will need to explicitly clear the View or Target before starting
    // the new load.
    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.

    status = Status.WAITING_FOR_SIZE;
    if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
      onSizeReady(overrideWidth, overrideHeight);
    } else {
      target.getSize(this);
    }

    if ((status == Status.RUNNING || status == Status.WAITING_FOR_SIZE)
        && canNotifyStatusChanged()) {
      target.onLoadStarted(getPlaceholderDrawable());
    }
    if (IS_VERBOSE_LOGGABLE) {
      logV("finished run method in " + LogTime.getElapsedMillis(startTime));
    }
  }

SingleRequest.java

  /**
   * A callback method that should never be invoked directly.
   */
  @Override
  public synchronized void onSizeReady(int width, int height) {
    stateVerifier.throwIfRecycled();
    if (IS_VERBOSE_LOGGABLE) {
      logV("Got onSizeReady in " + LogTime.getElapsedMillis(startTime));
    }
    if (status != Status.WAITING_FOR_SIZE) {
      return;
    }
    status = Status.RUNNING;

    float sizeMultiplier = requestOptions.getSizeMultiplier();
    this.width = maybeApplySizeMultiplier(width, sizeMultiplier);
    this.height = maybeApplySizeMultiplier(height, sizeMultiplier);

    if (IS_VERBOSE_LOGGABLE) {
      logV("finished setup for calling load in " + LogTime.getElapsedMillis(startTime));
    }
    loadStatus =
        engine.load(
            glideContext,
            model,
            requestOptions.getSignature(),
            this.width,
            this.height,
            requestOptions.getResourceClass(),
            transcodeClass,
            priority,
            requestOptions.getDiskCacheStrategy(),
            requestOptions.getTransformations(),
            requestOptions.isTransformationRequired(),
            requestOptions.isScaleOnlyOrNoTransform(),
            requestOptions.getOptions(),
            requestOptions.isMemoryCacheable(),
            requestOptions.getUseUnlimitedSourceGeneratorsPool(),
            requestOptions.getUseAnimationPool(),
            requestOptions.getOnlyRetrieveFromCache(),
            this,
            callbackExecutor);

    // This is a hack that's only useful for testing right now where loads complete synchronously
    // even though under any executor running on any thread but the main thread, the load would
    // have completed asynchronously.
    if (status != Status.RUNNING) {
      loadStatus = null;
    }
    if (IS_VERBOSE_LOGGABLE) {
      logV("finished onSizeReady in " + LogTime.getElapsedMillis(startTime));
    }
  }

Engine.java


  /**
   * Starts a load for the given arguments.
   *
   * <p>Must be called on the main thread.
   *
   * <p>The flow for any request is as follows:
   *
   * <ul>
   *   <li>Check the current set of actively used resources, return the active resource if present,
   *       and move any newly inactive resources into the memory cache.
   *   <li>Check the memory cache and provide the cached resource if present.
   *   <li>Check the current set of in progress loads and add the cb to the in progress load if one
   *       is present.
   *   <li>Start a new load.
   * </ul>
   *
   * <p>Active resources are those that have been provided to at least one request and have not yet
   * been released. Once all consumers of a resource have released that resource, the resource then
   * goes to cache. If the resource is ever returned to a new consumer from cache, it is re-added to
   * the active resources. If the resource is evicted from the cache, its resources are recycled and
   * re-used if possible and the resource is discarded. There is no strict requirement that
   * consumers release their resources so active resources are held weakly.
   *
   * @param width The target width in pixels of the desired resource.
   * @param height The target height in pixels of the desired resource.
   * @param cb The callback that will be called when the load completes.
   */
  public synchronized <R> LoadStatus load(
      GlideContext glideContext,
      Object model,
      Key signature,
      int width,
      int height,
      Class<?> resourceClass,
      Class<R> transcodeClass,
      Priority priority,
      DiskCacheStrategy diskCacheStrategy,
      Map<Class<?>, Transformation<?>> transformations,
      boolean isTransformationRequired,
      boolean isScaleOnlyOrNoTransform,
      Options options,
      boolean isMemoryCacheable,
      boolean useUnlimitedSourceExecutorPool,
      boolean useAnimationPool,
      boolean onlyRetrieveFromCache,
      ResourceCallback cb,
      Executor callbackExecutor) {
    long startTime = VERBOSE_IS_LOGGABLE ? LogTime.getLogTime() : 0;

    EngineKey key = keyFactory.buildKey(model, signature, width, height, transformations,
        resourceClass, transcodeClass, options);

    EngineResource<?> active = loadFromActiveResources(key, isMemoryCacheable);  //活动缓存
    if (active != null) {
      cb.onResourceReady(active, DataSource.MEMORY_CACHE);
      if (VERBOSE_IS_LOGGABLE) {
        logWithTimeAndKey("Loaded resource from active resources", startTime, key);
      }
      return null;
    }

    EngineResource<?> cached = loadFromCache(key, isMemoryCacheable);  //内存缓存
    if (cached != null) {
      cb.onResourceReady(cached, DataSource.MEMORY_CACHE);
      if (VERBOSE_IS_LOGGABLE) {
        logWithTimeAndKey("Loaded resource from cache", startTime, key);
      }
      return null;
    }

    EngineJob<?> current = jobs.get(key, onlyRetrieveFromCache);
    if (current != null) {
      current.addCallback(cb, callbackExecutor);
      if (VERBOSE_IS_LOGGABLE) {
        logWithTimeAndKey("Added to existing load", startTime, key);
      }
      return new LoadStatus(cb, current);
    }

    EngineJob<R> engineJob =
        engineJobFactory.build(
            key,
            isMemoryCacheable,
            useUnlimitedSourceExecutorPool,
            useAnimationPool,
            onlyRetrieveFromCache);

    DecodeJob<R> decodeJob =
        decodeJobFactory.build(
            glideContext,
            model,
            key,
            signature,
            width,
            height,
            resourceClass,
            transcodeClass,
            priority,
            diskCacheStrategy,
            transformations,
            isTransformationRequired,
            isScaleOnlyOrNoTransform,
            onlyRetrieveFromCache,
            options,
            engineJob);

    jobs.put(key, engineJob);

    engineJob.addCallback(cb, callbackExecutor);
    engineJob.start(decodeJob);

    if (VERBOSE_IS_LOGGABLE) {
      logWithTimeAndKey("Started new load", startTime, key);
    }
    return new LoadStatus(cb, engineJob);
  }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/16082.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

java.swing 飞机大战小游戏

上午没事刷到网上最近炒热了一些简单的小游戏和爱心代码&#xff0c;单身8个月了&#xff0c;对爱心代码不是很感冒&#xff0c;所以想蹭个热度&#xff0c;写一个飞机大站来玩玩。 首先&#xff0c;分析小游戏需要那些技术与怎么设计&#xff1a; 窗体&#xff0c;因为是jav…

Python如何使用PyMySQL连接数据库

1&#xff1a;为什么要连接数据库呢&#xff1f; 做接口自动化测试的时候&#xff0c;我们需要校验数据是否正常入库&#xff0c;数据是否正确&#xff0c;来做断言处理&#xff1b;有的时候需要修改数据&#xff0c;去执行其他场景的测试用例&#xff1b;有的时候需要删除数据…

DOX-HSA/HGB/FITC/Glu人血清蛋白/血红蛋白/荧光素/葡萄糖修饰阿霉素

小编今天分享给大家的科研知识是DOX-HSA/HGB/FITC/Glu人血清蛋白/血红蛋白/荧光素/葡萄糖修饰阿霉素&#xff0c;来看&#xff01; DOX-HSA人血清蛋白偶联阿霉素相关&#xff1a; 采用阿霉素(Doxorubicin,DOX)与人血清白蛋白(HSA)经化学交联获得的偶联物。本品经过滤,溶于PBS…

Chapter4 利用机器学习解决分类和回归问题

目录 4.1 机器学习和神经网络基本概念 4.1.1 感知器 4.1.2 前向传播 4.1.3 反向传播 4.1.4 过拟合和欠拟合 4.2 利用神经网络解决回归问题 4.2.1 问题介绍 4.2.2 利用pytorch解析数据 4.2.2 利用pytorch定义网络结构 4.2.3 开始训练 4.2.4 将模型进行保存 4.3 利用p…

云中马在A股上市:总市值约为40亿元,叶福忠为实际控制人

11月18日&#xff0c;浙江云中马股份有限公司&#xff08;下称“云中马”&#xff0c;SH:603130&#xff09;在上海证券交易所主板上市。本次上市&#xff0c;云中马的发行价为19.72元/股&#xff0c;发行数量为3500万股&#xff0c;募资总额约为6.90亿元&#xff0c;募资金额约…

码农必备?清华大学开源了一款写代码神器。。。

程序员宝藏库&#xff1a;https://gitee.com/sharetech_lee/CS-Books-Store 提升程序员编码效率&#xff0c;是一个经久不衰的话题&#xff0c;从最初用纯文本编辑器到后来代码自动补全&#xff0c;再到后来基于AI智能补全代码&#xff0c;开发者效率的确在不断提升。 关于新工…

这就是程序员眼中的函数吗?(一)

小叮当的任意门1. 函数是什么&#xff1f;2. C语言中的函数分类1. 库函数2. 自定义函数3. 函数的参数1. 实际参数&#xff08;实参&#xff09;2. 形式参数&#xff08;形参&#xff09;4. 函数的调用1. 传值调用2. 传址调用练习1. 写一个函数可以判断一个数是不是素数三级标题…

5分钟实现「视频检索」:基于内容理解,无需任何标签

Notebook 教程&#xff1a;text-video retrieval 「视频检索」任务就是输入一段文本&#xff0c;检索出最符合文本描述的视频。随着各类视频平台的兴起和火爆&#xff0c;网络上视频的数量呈现井喷式增长&#xff0c;「视频检索」成为人们高效查找视频的一项新需求。传统的视频…

Matlab点云处理及可视化第1期—基于KD树的邻域点搜索(柱状邻域、球状邻域及KNN)

目录 1 概述 2 代码实现 3 可视化验证 数据及完整代码获取方式&#xff1a; 观前提示&#xff1a;本文文字内容请勿直接用于论文写作&#xff0c;否则后果自负。 特别提示&#xff1a;《Matlab点云处理及可视化》系列文章旨在为初入点云处理领域的朋友提供一份较为权威、可…

MR直播(混合现实直播)做一场高品质企业培训

阿酷TONY / 2022-11-18 / 长沙 MR&#xff0c;是英文Mixed Reality两个单词的缩写&#xff0c;中文翻译为混合现实。 MR混合现实直播技术是通过在现实环境中引入虚拟场景信息&#xff0c;增强用户体验的真实感&#xff0c;具有真实性、实时互动性等特点。 MR直播解决方案是深…

基于springboot农产品交易平台的设计与实现

摘 要 随着科学技术的飞速发展&#xff0c;各行各业都在努力与现代先进技术接轨&#xff0c;通过科技手段提高自身的优势&#xff1b;对于特色农产品电商平台 当然也不能排除在外&#xff0c;随着网络技术的不断成熟&#xff0c;带动了特色农产品电商平台&#xff0c;它彻底…

软件需求分析——需求的理论基础

如果有兴趣了解更多相关内容&#xff0c;可以来我的个人网站看看&#xff1a;瞳孔空间 一&#xff1a;需求的涵义 研究对象&#xff1a;软件加强型系统中的软件 软件加强型系统&#xff1a;泛指由计算机技术支持的互相联系着的一组人类活动组成的系统。与物理设备和人类社会…

linux网络协议栈源码分析 - 传输层(TCP的输出)

1、TCP write系统调用(tcp_sendmsg) 1.1、write系统调用 socket的write系统调用栈: write最终调用tcp_sendmsg发送消息。 1.2、tcp_sendmsg报文分段 tcp_sendmsg主要是对用户的消息按MSS进行分段、添加到发送队列并将用户数据拷贝到分段里面&#xff0c;根据相关判断设置PSH标…

[附源码]SSM计算机毕业设计超市收银系统论文JAVA

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

学生台灯是灯管的好还是led的好?分享学生专用台灯第一品牌

给学生使用的话肯定是led灯更好的&#xff0c;主要是对眼睛有保护作用的&#xff0c;灯管一般当做主要照明灯具是可以的&#xff0c;在家中客厅里&#xff0c;卧室就是灯管&#xff0c;使用led灯是想要补足亮度的&#xff0c;全光谱的国AA级台灯&#xff0c;更健康、更适应人类…

计算机网络---ARP、DHCP与ICMP

&#xff08;一&#xff09;IP 地址与硬件地址 IP地址是网络层使用的地址&#xff0c;它是分层次等级的。硬件地址是数据链路层使用的地址&#xff08;MAC地址&#xff09;&#xff0c;它是平面式的。在网络层及网络层之上使用IP地址&#xff0c;IP地址放在IP数据报的首部&…

并肩刘德华,对战周杰伦,腾格尔老师线上演唱会即将拉开帷幕

在刚刚结束的第三十五届金鸡奖上面&#xff0c;著名爱国艺人刘德华&#xff0c;又一次出现在大众的视野当中。来自香港的天王刘德华&#xff0c;是一个著名的音乐人和演员&#xff0c;他拳拳的爱国之情&#xff0c;也感动了无数的粉丝。 刘德华作为中国华语乐坛的中坚力量&…

22071班(11月18日)

1.在串口工具进行输入&#xff1a; echo 1 > /dev/myled0 ---->led1灯点亮 echo 0 > /dev/myled0 ---->led1灯熄灭 echo 1 > /dev/myled1 ---->led1灯点亮 echo 0 > /dev/myled1 ---->led1灯熄灭 echo 1 > /dev/myled2 ----…

【附源码】计算机毕业设计JAVA校园跑腿平台

【附源码】计算机毕业设计JAVA校园跑腿平台 目运行 环境项配置&#xff1a; Jdk1.8 Tomcat8.5 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; JAVA mybati…

什么是PaaS平台

PaaS平台概述 PaaS平台通常是基于IaaS平台构建的&#xff0c;PaaS平台和IaaS平台最大的差别是需求即服务。所有的管理都是以服务为粒度的&#xff0c;在IaaS以资源管理为中心的平台上提供了更高层次的抽象。 PaaS的本质 &#xff08;1&#xff09;运维自动化&#xff0c;故障…