glide源码解析之GlideModule

Glide源码解析(2)—Glide实例创建过程 Glide的使用很简单,就在这简单的三步中就实现了很多复杂的流程,其中就包括Glide的创建,Glide的创建涉及的内容很多,下面就开始分析Glide的创建过程。 ... 阅读详情
GlideModule是对glide全局配置相关的类,这里介绍相关配置的源码解析
一般的用法是这样
public class GlideConfiguration implements GlideModule {

    @Override
    public void applyOptions(Context context, GlideBuilder builder) {
        builder.setDecodeFormat(DecodeFormat.PREFER_ARGB_8888);
        MemorySizeCalculator calculator = new MemorySizeCalculator(context);
        int defaultMemoryCacheSize = calculator.getMemoryCacheSize();
        int defaultBitmapPoolSize = calculator.getBitmapPoolSize();
        int customMemoryCacheSize = (int) (1.2 * defaultMemoryCacheSize);
        int customBitmapPoolSize = (int) (1.2 * defaultBitmapPoolSize);
        builder.setMemoryCache(new LruResourceCache(customMemoryCacheSize)); //设置图片缓存策略
        builder.setBitmapPool(new LruBitmapPool(customBitmapPoolSize));
        int cacheSize100MegaBytes = 104857600;  //100M
        String downloadDirectoryPath = Environment.getExternalStorageDirectory().getPath();
        builder.setDiskCache(new DiskLruCacheFactory(downloadDirectoryPath, "cache/", cacheSize100MegaBytes));
    }

    @Override
    public void registerComponents(Context context, Glide glide) {
        glide.register(GlideUrl.class, InputStream.class, new HttpUrlGlideUrlLoader.Factory());
    }
}
然后再manifest文件中加入这个配置
        <meta-data
            android:name=".GlideConfiguration"
            android:value="GlideModule"/>

先看看GlideMoudle接口源码
package com.bumptech.glide.module;

import android.content.Context;

import com.bumptech.glide.Glide;
import com.bumptech.glide.GlideBuilder;

/**
 * An interface allowing lazy configuration of Glide including setting options using
 * {@link com.bumptech.glide.GlideBuilder} and registering
 * {@link com.bumptech.glide.load.model.ModelLoader ModelLoaders}.
 *
 * <p>
 *     To use this interface:
 *     <ol>
 *         <li>
 *             Implement the GlideModule interface in a class with public visibility, calling
 *             {@link com.bumptech.glide.Glide#register(Class, Class, com.bumptech.glide.load.model.ModelLoaderFactory)}
 *             for each {@link com.bumptech.glide.load.model.ModelLoader} you'd like to register:
 *             <pre>
 *                  <code>
 *                      public class FlickrGlideModule implements GlideModule {
 *                          {@literal @}Override
 *                          public void applyOptions(Context context, GlideBuilder builder) {
 *                              buidler.setDecodeFormat(DecodeFormat.ALWAYS_ARGB_8888);
 *                          }
 *
 *                          {@literal @}Override
 *                          public void registerComponents(Context context, Glide glide) {
 *                              glide.register(Model.class, Data.class, new MyModelLoader());
 *                          }
 *                      }
 *                  </code>
 *             </pre>
 *         </li>
 *         <li>
 *              Add your implementation to your list of keeps in your proguard.cfg file:
 *              <pre>
 *                  {@code
 *                      -keepnames class * com.bumptech.glide.samples.flickr.FlickrGlideModule
 *                  }
 *              </pre>
 *         </li>
 *         <li>
 *             Add a metadata tag to your AndroidManifest.xml with your GlideModule implementation's fully qualified
 *             classname as the key, and {@code GlideModule} as the value:
 *             <pre>
 *                 {@code
 *                      <meta-data
 *                          android:name="com.bumptech.glide.samples.flickr.FlickrGlideModule"
 *                          android:value="GlideModule" />
 *                 }
 *             </pre>
 *         </li>
 *     </ol>
 * </p>
 *
 * <p>
 *     All implementations must be publicly visible and contain only an empty constructor so they can be instantiated
 *     via reflection when Glide is lazily initialized.
 * </p>
 *
 * <p>
 *     There is no defined order in which modules are called, so projects should be careful to avoid applying
 *     conflicting settings in different modules. If an application depends on libraries that have conflicting
 *     modules, the application should consider avoiding the library modules and instead providing their required
 *     dependencies in a single application module.
 * </p>
 */
public interface GlideModule {

    /**
     * Lazily apply options to a {@link com.bumptech.glide.GlideBuilder} immediately before the Glide singleton is
     * created.
     *
     * <p>
     *     This method will be called once and only once per implementation.
     * </p>
     *
     * @param context An Application {@link android.content.Context}.
     * @param builder The {@link com.bumptech.glide.GlideBuilder} that will be used to create Glide.
     */
    void applyOptions(Context context, GlideBuilder builder);

    /**
     * Lazily register components immediately after the Glide singleton is created but before any requests can be
     * started.
     *
     * <p>
     *     This method will be called once and only once per implementation.
     * </p>
     *
     * @param context An Application {@link android.content.Context}.
     * @param glide The newly created Glide singleton.
     */
    void registerComponents(Context context, Glide glide);
}

上面一堆注释介绍是怎么用的,最终就是两个方法需要实现。
一个是设置属性,一个是注册组件。
看设置属性的,先看参数GlideBuilder
/**
 * A builder class for setting default structural classes for Glide to use.
 */
public class GlideBuilder {

里边含有一些方法
/**
 * Sets the {@link com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool} implementation to use to store and
 * retrieve reused {@link android.graphics.Bitmap}s.
 *
 * @param bitmapPool The pool to use.
 * @return This builder.
 */
public GlideBuilder setBitmapPool(BitmapPool bitmapPool) {
    this.bitmapPool = bitmapPool;
    return this;
}

这个是设置bitmap池的,是在内存中存储以bitmap形式,大家应该都知道这个是占用内存比较大的,但是速度是最快的。

/**
 * Sets the {@link com.bumptech.glide.load.engine.cache.MemoryCache} implementation to store
 * {@link com.bumptech.glide.load.engine.Resource}s that are not currently in use.
 *
 * @param memoryCache  The cache to use.
 * @return This builder.
 */
public GlideBuilder setMemoryCache(MemoryCache memoryCache) {
    this.memoryCache = memoryCache;
    return this;
}

这个是内存缓存的是以文件或者流的方式存在内存中的,没有上面那个处理速度快,但是比在磁盘读写和加载网络要快很多的。
上面两种都是在内存中存储的,在默认实现中,他们两种总共占内存的0.33-0.4的空间,如果在低内存下还有其他的处理,他们俩各占这部分内存的一半。

/**
 * Sets the {@link com.bumptech.glide.load.engine.cache.DiskCache.Factory} implementation to use to construct
 * the {@link com.bumptech.glide.load.engine.cache.DiskCache} to use to store
 * {@link com.bumptech.glide.load.engine.Resource} data on disk.
 *
 * @param diskCacheFactory The disk cche factory to use.
 * @return This builder.
 */
public GlideBuilder setDiskCache(DiskCache.Factory diskCacheFactory) {
    this.diskCacheFactory = diskCacheFactory;
    return this;
}
讲网络中下载的数据存储到磁盘中。不用重复下载,这个也可以自己去实现,如何存储以及存储的方式算法。

Glide是支持扩展性比较高的,基于接口去配置,可以实现对其灵活的扩展,上面是有一些默认实现的,如果需要更高级的用法,可以自己实现缓存策略,和硬盘存储策略。


/**
 * Sets the {@link com.bumptech.glide.load.DecodeFormat} that will be the default format for all the default
 * decoders that can change the {@link android.graphics.Bitmap.Config} of the {@link android.graphics.Bitmap}s they
 * decode.
 *
 * <p>
 *     Decode format is always a suggestion, not a requirement. See {@link com.bumptech.glide.load.DecodeFormat} for
 *     more details.
 * </p>
 *
 * <p>
 *     If you instantiate and use a custom decoder, it will use
 *     {@link com.bumptech.glide.load.DecodeFormat#DEFAULT} as its default.
 * </p>
 *
 * <p>
 *     Calls to this method are ignored on KitKat and Lollipop. See #301.
 * </p>
 *
 * @param decodeFormat The format to use.
 * @return This builder.
 */
public GlideBuilder setDecodeFormat(DecodeFormat decodeFormat) {
    this.decodeFormat = decodeFormat;
    return this;
}

设置全局的bitmap解码格式
解码格式源码在这里
package com.bumptech.glide.load;

/**
 * Options for setting the value of {@link android.graphics.Bitmap#getConfig()} for {@link android.graphics.Bitmap}s
 * returned by a {@link com.bumptech.glide.load.resource.bitmap.BitmapDecoder}.
 *
 * <p>
 *     Note - In some cases it may not be possible to obey the requested setting, not all
 *     {@link com.bumptech.glide.load.resource.bitmap.BitmapDecoder}s support setting formats and certain images may
 *     not be able to be loaded as certain configurations. Therefore this class represents a preference rather than a
 *     requirement.
 * </p>
 */
public enum DecodeFormat {
    /**
     * All bitmaps returned by the {@link com.bumptech.glide.load.resource.bitmap.BitmapDecoder} should return
     * {@link android.graphics.Bitmap.Config#ARGB_8888} for {@link android.graphics.Bitmap#getConfig()}.
     *
     * @deprecated Use the equivalent but less misleadingly named {@link #PREFER_ARGB_8888}. Scheduled to be removed
     * in Glide 4.0
     */
    @Deprecated
    ALWAYS_ARGB_8888,

    /**
     * Bitmaps decoded from most image formats (other than GIFs with hidden configs), will be decoded with the
     * ARGB_8888 config.
     *
     * <p>
     *     {@link android.graphics.BitmapFactory} does not allow us to guarantee that all returned Bitmaps will
     *     be of a requested config without resorting to expensive copying. As a result, this is a preference only.
     *     Most GIFs, for example, will still produce {@link android.graphics.Bitmap}s with null
     *     {@link android.graphics.Bitmap.Config}s.
     * </p>
     */
    PREFER_ARGB_8888,

    /**
     * Bitmaps decoded from image formats that support and/or use alpha (some types of PNGs, GIFs etc) should
     * return {@link android.graphics.Bitmap.Config#ARGB_8888} for {@link android.graphics.Bitmap#getConfig()}. Bitmaps
     * decoded from formats that don't support or use alpha should return
     * {@link android.graphics.Bitmap.Config#RGB_565} for {@link android.graphics.Bitmap#getConfig()}.
     *
     */
    PREFER_RGB_565;

    /** The default value for DecodeFormat. */
    public static final DecodeFormat DEFAULT = PREFER_RGB_565;
}
这里默认是用Bitmap.option中国的565格式,我们也可以设置成888的格式,如下这样:
builder.setDecodeFormat(DecodeFormat.PREFER_ARGB_8888);

在GlideBuilder中的默认设置在此:
Glide createGlide() {
    if (sourceService == null) {
        final int cores = Math.max(1, Runtime.getRuntime().availableProcessors());
        sourceService = new FifoPriorityThreadPoolExecutor(cores);
    }
    if (diskCacheService == null) {
        diskCacheService = new FifoPriorityThreadPoolExecutor(1);
    }

    MemorySizeCalculator calculator = new MemorySizeCalculator(context);
    if (bitmapPool == null) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
            int size = calculator.getBitmapPoolSize();
            bitmapPool = new LruBitmapPool(size);
        } else {
            bitmapPool = new BitmapPoolAdapter();
        }
    }

    if (memoryCache == null) {
        memoryCache = new LruResourceCache(calculator.getMemoryCacheSize());
    }

    if (diskCacheFactory == null) {
        diskCacheFactory = new InternalCacheDiskCacheFactory(context);
    }

    if (engine == null) {
        engine = new Engine(memoryCache, diskCacheFactory, diskCacheService, sourceService);
    }

    if (decodeFormat == null) {
        decodeFormat = DecodeFormat.DEFAULT;
    }

    return new Glide(engine, memoryCache, bitmapPool, context, decodeFormat);
}

下面是类的成员变量
private final Context context;

private Engine engine;
private BitmapPool bitmapPool;
private MemoryCache memoryCache;
private ExecutorService sourceService;
private ExecutorService diskCacheService;
private DecodeFormat decodeFormat;
private DiskCache.Factory diskCacheFactory;

也就是除了context以外都是可以设置的
sourceService是从服务器来去图片资源的时候的处理策略
diskCacheService是从磁盘缓存是的策略
这两个默认的都是带有优先级的先进先出方式
用的是这个
public class FifoPriorityThreadPoolExecutor extends ThreadPoolExecutor {

下面是bitmapPool处理方式
MemorySizeCalculator calculator = new MemorySizeCalculator(context);
if (bitmapPool == null) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
        int size = calculator.getBitmapPoolSize();
        bitmapPool = new LruBitmapPool(size);
    } else {
        bitmapPool = new BitmapPoolAdapter();
    }
}

默认是根据SDK的版本处理不同的方式 Build.VERSION_CODES.HONEYCOMB = 11
MemorySizeCalculator 这个类是池大小计算的类,有感兴趣的可以读下,看看怎么计算的。
实现大概就是图片缓存占用整个APP内存的0.33-0.4的,其中的一半是给BitmapPool用的,另一半是给cache用的
这个bitmapPool要是自己实现要实现BitmapPool接口就可以了。
/**
 * An interface for a pool that allows users to reuse {@link android.graphics.Bitmap} objects.
 */
public interface BitmapPool {

那个小于sdk11版本的默认是实现,就是什么都没有实现,下面是源码
/**
 * An {@link com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool BitmapPool} implementation that rejects all
 * {@link android.graphics.Bitmap Bitmap}s added to it and always returns {@code null} from get.
 */
public class BitmapPoolAdapter implements BitmapPool {
    @Override
    public int getMaxSize() {
        return 0;
    }

    @Override
    public void setSizeMultiplier(float sizeMultiplier) {
        // Do nothing.
    }

    @Override
    public boolean put(Bitmap bitmap) {
        return false;
    }

    @Override
    public Bitmap get(int width, int height, Bitmap.Config config) {
        return null;
    }

    @Override
    public Bitmap getDirty(int width, int height, Bitmap.Config config) {
        return null;
    }

    @Override
    public void clearMemory() {
        // Do nothing.
    }

    @Override
    public void trimMemory(int level) {
        // Do nothing.
    }

然后看下LRU算法实现的bitmapPool。
/**
 * Constructor for LruBitmapPool.
 *
 * @param maxSize The initial maximum size of the pool in bytes.
 */
public LruBitmapPool(int maxSize) {
    this(maxSize, getDefaultStrategy(), getDefaultAllowedConfigs());
}

第一个是缓存池大小单位bytes
第二个是默认的缓存策略,
第三个是允许的配置,如ARGB565、ARGB888等
然后第二个缓存策略
private static LruPoolStrategy getDefaultStrategy() {
    final LruPoolStrategy strategy;
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
        strategy = new SizeConfigStrategy();
    } else {
        strategy = new AttributeStrategy();
    }
    return strategy;
}

也是根据sdk版本不同的实现

@TargetApi(Build.VERSION_CODES.KITKAT)
public class SizeConfigStrategy implements LruPoolStrategy {

class AttributeStrategy implements LruPoolStrategy {

他们两个都实现了LruPoolStrategy接口
看下这个接口
interface LruPoolStrategy {
    void put(Bitmap bitmap);
    Bitmap get(int width, int height, Bitmap.Config config);
    Bitmap removeLast();
    String logBitmap(Bitmap bitmap);
    String logBitmap(int width, int height, Bitmap.Config config);
    int getSize(Bitmap bitmap);
}

看第get方法,是获得key的方式,width,height config
下面是AttributeStrategy 的实现
下面是key的代码
static class Key implements Poolable {
    private final KeyPool pool;
    private int width;
    private int height;
    // Config can be null :(
    private Bitmap.Config config;

    public Key(KeyPool pool) {
        this.pool = pool;
    }

    public void init(int width, int height, Bitmap.Config config) {
        this.width = width;
        this.height = height;
        this.config = config;
    }

    @Override
    public boolean equals(Object o) {
        if (o instanceof Key) {
            Key other = (Key) o;
            return width == other.width
                    && height == other.height
                    && config == other.config;
        }
        return false;
    }

    @Override
    public int hashCode() {
        int result = width;
        result = 31 * result + height;
        result = 31 * result + (config != null ? config.hashCode() : 0);
        return result;
    }

    @Override
    public String toString() {
        return getBitmapString(width, height, config);
    }

    @Override
    public void offer() {
        pool.offer(this);
    }
}

AttributeStrategy实现的get和put实现方法

private final KeyPool keyPool = new KeyPool();
private final GroupedLinkedMap<Key, Bitmap> groupedMap = new GroupedLinkedMap<Key, Bitmap>();

public void put(Bitmap bitmap) {
    final Key key = keyPool.get(bitmap.getWidth(), bitmap.getHeight(), bitmap.getConfig());

    groupedMap.put(key, bitmap);
}

@Override
public Bitmap get(int width, int height, Bitmap.Config config) {
    final Key key = keyPool.get(width, height, config);

    return groupedMap.get(key);
}

这个是用了一个 GroupedLinkedMap
来存储的,里边的实现是和LinkedHashMap相似的方式,LinkedHashMap本身是有对LRU算法相应的实现的,读一下他的构造方法就明白了。

然后再看下cache
if (memoryCache == null) {
    memoryCache = new LruResourceCache(calculator.getMemoryCacheSize());
}

默认是LruResourceCache
/**
 * An LRU in memory cache for {@link com.bumptech.glide.load.engine.Resource}s.
 */
public class LruResourceCache extends LruCache<Key, Resource<?>> implements MemoryCache {

咱们自己实现的cache要实现MemoryCache接口,把源码贴出来下
/**
 * An interface for adding and removing resources from an in memory cache.
 */
public interface MemoryCache {
    /**
     * An interface that will be called whenever a bitmap is removed from the cache.
     */
    interface ResourceRemovedListener {
        void onResourceRemoved(Resource<?> removed);
    }

    /**
     * Returns the sum of the sizes of all the contents of the cache in bytes.
     */
    int getCurrentSize();

    /**
     * Returns the current maximum size in bytes of the cache.
     */
    int getMaxSize();

    /**
     * Adjust the maximum size of the cache by multiplying the original size of the cache by the given multiplier.
     *
     * <p>
     *     If the size multiplier causes the size of the cache to be decreased, items will be evicted until the cache
     *     is smaller than the new size.
     * </p>
     *
     * @param multiplier A size multiplier >= 0.
     */
    void setSizeMultiplier(float multiplier);

    /**
     * Removes the value for the given key and returns it if present or null otherwise.
     *
     * @param key The key.
     */
    Resource<?> remove(Key key);

    /**
     * Add bitmap to the cache with the given key.
     *
     * @param key The key to retrieve the bitmap.
     * @param resource The {@link com.bumptech.glide.load.engine.EngineResource} to store.
     * @return The old value of key (null if key is not in map).
     */
    Resource<?> put(Key key, Resource<?> resource);

    /**
     * Set the listener to be called when a bitmap is removed from the cache.
     *
     * @param listener The listener.
     */
    void setResourceRemovedListener(ResourceRemovedListener listener);

    /**
     * Evict all items from the memory cache.
     */
    void clearMemory();

    /**
     * Trim the memory cache to the appropriate level. Typically called on the callback onTrimMemory.
     *
     * @param level This integer represents a trim level as specified in {@link android.content.ComponentCallbacks2}.
     */
    void trimMemory(int level);
}

默认实现的LruCache就是用的
private final LinkedHashMap<T, Y> cache = new LinkedHashMap<T, Y>(100, 0.75f, true);
/**
 * Constructs a new {@code LinkedHashMap} instance with the specified
 * capacity, load factor and a flag specifying the ordering behavior.
 *
 * @param initialCapacity
 *            the initial capacity of this hash map.
 * @param loadFactor
 *            the initial load factor.
 * @param accessOrder
 *            {@code true} if the ordering should be done based on the last
 *            access (from least-recently accessed to most-recently
 *            accessed), and {@code false} if the ordering should be the
 *            order in which the entries were inserted.
 * @throws IllegalArgumentException
 *             when the capacity is less than zero or the load factor is
 *             less or equal to zero.
 */
public LinkedHashMap(
        int initialCapacity, float loadFactor, boolean accessOrder) {
    super(initialCapacity, loadFactor);
    init();
    this.accessOrder = accessOrder;
}
这个是LinkedHashMap的构造方法,lru方式或者默认插入顺序

if (diskCacheFactory == null) {
    diskCacheFactory = new InternalCacheDiskCacheFactory(context);
}

磁盘缓存的处理方式 需要实现 DiskCache接口
Glide给出了默认实现,注意一提的是,读写文件要注意读写一致的问题。如果有相关的可以参考下这里。

if (engine == null) {
    engine = new Engine(memoryCache, diskCacheFactory, diskCacheService, sourceService);
}

这个Glide的引擎,目前的set方法还是test阶段,处理下载缓存等等的。
自己定义这个的话,就相当高级了,但是glide这边是支持扩展的哦。

if (decodeFormat == null) {
    decodeFormat = DecodeFormat.DEFAULT;
}

这个就是Bitmap的解码设置,默认是565的一个像素占2字节
/** The default value for DecodeFormat. */
public static final DecodeFormat DEFAULT = PREFER_RGB_565;

再来看下GlideModule怎么加载的,下面这个是Glide的创建
/**
 * Get the singleton.
 *
 * @return the singleton
 */
public static Glide get(Context context) {
    if (glide == null) {
        synchronized (Glide.class) {
            if (glide == null) {
                Context applicationContext = context.getApplicationContext();
                List<GlideModule> modules = new ManifestParser(applicationContext).parse();

                GlideBuilder builder = new GlideBuilder(applicationContext);
                for (GlideModule module : modules) {
                    module.applyOptions(applicationContext, builder);
                }
                glide = builder.createGlide();
                for (GlideModule module : modules) {
                    module.registerComponents(applicationContext, glide);
                }
            }
        }
    }

    return glide;
}

这GlideModule可以有多个,在多个模块进行加载。

/**
 * Parses {@link com.bumptech.glide.module.GlideModule} references out of the AndroidManifest file.
 */
public final class ManifestParser {
    private static final String GLIDE_MODULE_VALUE = "GlideModule";

    private final Context context;

    public ManifestParser(Context context) {
        this.context = context;
    }

    public List<GlideModule> parse() {
        List<GlideModule> modules = new ArrayList<GlideModule>();
        try {
            ApplicationInfo appInfo = context.getPackageManager().getApplicationInfo(
                    context.getPackageName(), PackageManager.GET_META_DATA);
            if (appInfo.metaData != null) {
                for (String key : appInfo.metaData.keySet()) {
                    if (GLIDE_MODULE_VALUE.equals(appInfo.metaData.get(key))) {
                        modules.add(parseModule(key));
                    }
                }
            }
        } catch (PackageManager.NameNotFoundException e) {
            throw new RuntimeException("Unable to find metadata to parse GlideModules", e);
        }

        return modules;
    }

    private static GlideModule parseModule(String className) {
        Class<?> clazz;
        try {
            clazz = Class.forName(className);
        } catch (ClassNotFoundException e) {
            throw new IllegalArgumentException("Unable to find GlideModule implementation", e);
        }

        Object module;
        try {
            module = clazz.newInstance();
        } catch (InstantiationException e) {
            throw new RuntimeException("Unable to instantiate GlideModule implementation for " + clazz, e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException("Unable to instantiate GlideModule implementation for " + clazz, e);
        }

        if (!(module instanceof GlideModule)) {
            throw new RuntimeException("Expected instanceof GlideModule, but found: " + module);
        }
        return (GlideModule) module;
    }
}

这个是对Module进行获取信息和转换的处理。
Glide源码学习七:自定义模块功能(1) 小编这些年深知大多数初中级Android工程师,想要提升自己,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。因此我收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、电子书籍、讲解视频,并且后续会持续更新一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人。 阅读详情

相关推荐

深入分析Glide源码

前言 最近研究了一下Glide源码,发现很多地方写的真的很精妙,值得细细品味。Glide 功能丰富,图片三级缓存、可深度定制(继承AppGlideModule、LibraryGlideModule实现更多功能)、修改网络请求库、支持多种输入输出资源的转换(例如输入Stream,输出bitmap等等)、生命周期的管理 虽然下面分析完了,整体的流程,但是想要真正领会设计思想,还需要好好沉淀一下。文章篇幅比较长,但逻辑并不复杂 一、基本使用流程 Glide最基本的使用流程就是下面这行代码,其它所有扩展的额外功能都

薛瑄的博客 6283

Glide源码阅读之建造者(builder)模式4总结【MemorySizeCalculator】【GlideExecutor】【PreFillType】【LazyHeaders】

Glide建造者模式的应用解析; 熟练识别组件中设计模式使用变种,一目了然这一堆参数设置和自定义意图 【设计模式】【面试】

产品:SmartApi;服务:大前端++;其他技术分享 1140

机器人学习-matlab四足机器人控制仿真

《机器人学,机器视觉与控制》学习笔记 使用工具箱版本9.10 题目与解决思路: 【1】. 通过减少复位期间的抬腿高度来缩短复位的轨迹 Z轴向下,为了减小复位器件的抬腿高度,应当缩小△Z,故可以将示例程序中zu值调大。 【2】. 增加腿的步幅 腿的步幅可由改变x方向上腿前进和后退运动的极限来达到,令xf = 7; xb = -xf;即可。 ...

weixin_44609769的博客 5538

Android面试题:Glide

目录 系列文章: 相关文章: Q1:看过Glide源码吗,你印象最深的是什么? Q2:简单说一下Glide的三级缓存? 我们先来看读取:Lru算法缓存、弱引用缓存、磁盘缓存 接下来我们看写入:弱引用缓存、Lru算法缓存、磁盘缓存 Q3:Glide加载一个一兆的图片(100*100),是否会压缩后再加载,放到一个200*200的view上会怎样,1000*1000呢,图片会很模糊,怎么...

songzi1228的博客 1万+

【农业生产系统模型】基于R语言APSIM模型进阶应用与参数优化、批量模拟实践技术

APSIM模型有Classic和Next Generation两个系列模型,能模拟几十种农作物、牧草和树木的土壤-植物-大气过程,被广泛应用于精细农业、水肥管理、气候变化、粮食安全、土壤碳周转、环境影响、农业可持续性、农业生态等诸多与农业生产和科研有关的领域。R语言是一门应用场景广泛、简单易学的程序语言,APSIM模型开发了许多R语言辅助包,在APSIM模型的气候、土壤、管理措施等数据准备,自动化模拟,参数优化和结果分析上都发挥着重要的作用。案例一:APSIM模型输入参数和土壤文件的制备。

2303_79243743的博客 1046

让AI镜头“活”起来:22个核心运镜提示词,告别视频画面呆板

介绍了22种影视级镜头语言的AI提示词用法。内容涵盖推轨/后拉镜头等距离变化技巧、横摇/俯仰等方向控制手法、环绕/升降等空间位移方式,以及POV视角等特殊构图。

weixin_43489601的博客 6272

Android Glide MemorySizeCalculator计算值,Kotlin

在实际的开发中,虽然Glide解决了快速加载图片的问题,但还有一个问题悬而未决:比如用户的头像,往往用户的头像是从服务器端读出的一个普通矩形图片,但是现在的设计一般要求在APP端的用户头像显示成圆形头像,那么此时虽然Glide可以加载,但加载出来的是一个矩形,如果要Glide_android 毛玻璃圆角。Android Glide数据更新及内存缓存、硬盘缓存清理事项Android的Glide在加载图片时候内部默认使用了缓存机制,Glide的缓存机制分为两级,第一级是内存缓存,然后第二级是硬盘缓存。

Zhang Phil 1296

顶刊《会计研究》数据复现|最新上市公司数智化数据

本文基于Python文本分析方法构建了中国A股上市公司数智化指标(1991-2024),通过识别年报中的"机器学习""智能医疗"等关键词,量化企业数字化与智能化融合程度。研究发现数智化企业更倾向于非正式渠道的定性披露以规避风险,该指标为监管完善信披规则提供了参考。研究还揭示了数智化对企业信息披露策略的转变,并提出了未来研究方向,包括数智化对绿色创新、ESG表现等影响机制。数据覆盖非金融类上市公司,采用文本挖掘技术构建结构化指标,为相关领域研究提供了微观基础。

PPdata_Academy的博客 1487

【Glide】缓存大小的计算策略

正确管理app内存

qq_23049111的博客 3499

11 CO配置-控制-成本中心会计-定义分割结构(OKES-Define Splitting Structure)

业务背景:定义分割结构 事务码: OKES SPRO路径:SPRO->控制->成本中心会计->实际过账->期末结算->作业分配->划分->定义分割结构 第1步,SPRO路径进入 第2步,选择“新的条目”创建 分割结构 第3步,选择分割结构代码 点击“分割规则”进行下一个界面,点击“新条目”创建 分割结构规则 第4步,点击“为规则选择” 为分割结构规则创建版本并保存 第5步,选择“分配”,点击“新的条目” 输入分割结构分配

4370

116、影像质量主观评价方法论:标准场景与专家判读

本文探讨了影像质量主观评价的方法论,强调标准场景构建和专家判读体系的重要性。作者基于15年行业经验指出,仅靠客观指标无法保证观感质量,提出四类标准场景(灰阶、肤色、纹理、动态)的构建原则和四种专家判读维度(通透性、干净度、自然感、流程化)。文章揭示了主观评价中的常见误区,包括光源单一性、个人判读偏差、显示设备影响等,并建议建立多专家交叉验证机制和主观评价数据库。最后强调主观评价是可标准化的专业技术,需要将人眼感知转化为可追溯的技术参数。

sundong_81的博客 38

glide配置学习

参考:https://muyangmin.github.io/glide-docs-cn/doc/configuration.html#应用程序 MemorySizeCalculator配置 MemorySizeCalculator(MemorySizeCalculator.Builderbuilder){ this.context=builder.context; //...

979

halcon第一讲:基本操作

本文通过Blob分析提取出图片中的硬币,来熟悉halcon的基本操作。 1、读取图像,halcon读取图像有三种方式:1)、文件-&gt;读取图像;2)、通过助手;3)、代码 *打开窗口 dev_open_window (0, 0, 512, 512, 'black', WindowHandle) *读取图像 read_image (Image,'1.png') 读取的图像如下: 2...

qq_24946843的博客 3万+

Glide源码分析(一)从用法来看之with方法

继续啃源码,用过Glide的人,肯定都觉得它好好用,我们一般只需要几行代码,就可以达到我们想要的效果,可以在这个背后是什么呢?就需要我们来看了。 我一般看源码,我喜欢先从用法来看,然后一步一步的再细扣,所以就先从用法来看Glide的整体流程。 用过Glide的人,用下面这段代码,就可以进行图片的加载: Glide.with(this) .load(url) ...

小薇子的博客 634

23 RAG 为什么答不准:召回、分块、排序的常见坑

RAG 答不准时,不要先怪模型。本文把常见失败拆成召回不到、召回不准、分块不完整、排序靠后、上下文污染和生成不忠实六类,并给出从 Top-K 检查到评估集的排查流程。

老于的笔记的专栏 245

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

Glide缓存调试日志级别:verbose/debug/info/warn/error

你是否在开发Android应用时遇到图片加载缓慢、缓存异常却难以定位问题的情况?Glide作为专注于平滑滚动的Android图片加载库,提供了灵活的日志级别控制功能,帮助开发者精准调试缓存问题。本文将详细介绍如何通过调整Glide的日志级别(verbose/debug/info/warn/error)来监控缓存行为,解决实际开发中的痛点。读完本文后,你将能够:掌握5种日志级别的适用场景、通过代码配...

gitblog_01109的博客 1046

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

面试题之---Glide源码解析

(一)Glide和Picasso相比较: 1,Glide可以gif动态图,Picasson不可以 2,Glide默认Bitmap格式是RGB_565,图片质量不如Picasso(ARGB_8888)加载的清晰,但耗内存小.(但Glide也可以准换成ARGB_8888,而且耗内存也相对小些) 2.1,如果你对默认的RGB_565效果还比较满意,可以不做任何事,但是如果你觉得难以接受,可以创建一...

qq_38859786的博客 5862

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

Glide源码解析篇之框架主体结构(一)

Gide作为Android最受欢迎的图片加载库之一,一直深受Android开发者的喜爱,很大原因就是它的功能极其强大,而使用却异常简单。无论是网络、缓存、特效,占位图,Glide团队都为开发者考虑的非常细致,也正因为这个原因,Glide框架的源代码变得极其复杂,生涩难懂,我观察到网上有写源码分析的某大神光写主体结构的代码分析都写了两个礼拜,可见Glide的源代码复杂程度超乎了很多程序员们的想象。不

late哥哥的博客 2949

Glide源码分析

Glide是由Google开发,常用的一个图片加载框架,今天我们来分析一下源码,学习下优秀的框架。本篇文章采用的源码是 com.github.bumptech.glide:glide:4.0.0-RC0 /** * A singleton to present a simple static interface for building requests with * {@link Reque...

atxxiang4的博客 543

Glide源码解析(六)探究Glide的自定义模块功能

转载自 guolin,略有删减改动 Glide源码解析(六)探究Glide的自定义模块功能 不知不觉中,我们的Glide系列教程已经到了第六篇了,距离第一篇Glide的基本用法发布已经过去了半年的时间。在这半年中,我们通过用法讲解和源码分析配合学习的方式,将Glide的方方面面都研究了个遍,相信一直能看到这里的朋友现在已经是一位Glide高手了。 整个Glide系列预计总共会有八篇文章,现在也是逐步进入尾声了。不过,越是到后面,我们探究的内容也越是更加深入。那么今天,我们就来一起探究一下Glide中一个比较

aha_jasper的博客 639

Glide源码学习八:实现带进度的Glide图片加载功能

目录 系列文章: 相关文章: 扩展目标 开始 替换通讯组件 实现下载进度监听 进度显示 系列文章: Android面试题:Glide Glide源码学习一:Glide框架介绍、with方法详解 Glide源码学习二:load()详解 Glide源码学习三:into()详解 Glide源码学习四:缓存 Glide源码学习五:回调与监听 Glide源码学习六:图片变换 ...

songzi1228的博客 490

Android图片加载框架——Glide(Glide v4)

原文地址 Android图片加载框架——Glide(Glide v4) 前言 android中图片加载框架有很多,所有框架最终达到的目都是在Android平台上以极度简单的方式加载和展示图片,如果我们每个都拿来学习和使用的话,这样会极大的浪费我们的时间和经历,所以经过我的一番比较之后,我决定用Glide作为我研究和今后使用的对象。经过一个礼拜的学习和研究之后,我发现Glide是真的强大,通过简单的一行代码就可以展示图片,但是其背后所做的是事却是我们没法想象的,想深入去学习源码的可以去看下郭神的Glide最全

silencefly的博客 2329

3 条命令让 k6 压测在 Grafana 实时出图:性能测试监控上手

性能测试跑完,终端里只剩数字在滚,你说不清系统到底卡在哪一步。k6 用 JavaScript 写压测用例、Go 驱动内核,能把每次请求的数据写进 Grafana 监控仪表盘。全文 3 条命令,做完后响应时间、错误、吞吐的曲线会实时动起来。 ## 三个组件的数据链路:k6 指标如何流入 Grafana 一句话说清分工:k6 产数据,InfluxDB 存数据,Grafana 画数据,三者串起来,压

gitblog_00493的博客 1044

Glide 系列-1:预热、Glide 的常用配置方式及其原理

在接下来的几篇文章中,我们会对 Android 中常用的图片加载框架 Glide 进行分析。在本篇文章中,我们先通过介绍 Glide 的几种常用的配置方式来了解 Glide 的部分源码。后续的文中,我们会对 Glide 的源码进行更详尽的分析。 对于 Glide,相信多数 Android 开发者并不陌生,在本文中,我们不打算对其具体使用做介绍,你可以通过查看官方文档进行学习。Glide 的 API...

你好,开发者 1700

Glide源码分析Two

一、Glide基本使用 Glide官方文档地址 1.1、 Example Glide.with(imageView.context) .load(roundRectUrl) .apply(RequestOptions().priority(Priority.HIGH)) .apply(RequestOptions().diskCacheStrategy(DiskCacheS...

weixin_33735077的博客 148

Glide 阅读源码解疑

转载请标明地址 QuincySx: http://www.jianshu.com/p/e8adc9581f69 问题不定时更新,如果你也有问题欢迎在评论区提出 Glide 是如何拓展不同的资源获取器的 在 manifest 文件中 添加 meta-data 标签、key 为 GlideModule...

weixin_34279246的博客 73
上一篇: Glide源码之生命周期
下一篇: 图解AsyncTask
method_chen
博客等级 码龄15年 25粉丝 61原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

method_chen

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值