jjzjj

解析AndroidProject 加载圆角图片 GlideApp加载网络图片

汪菜菜学习笔记 2023-03-28 原文

 

  • 演示效果

  

 

  • 核心代码

  普通图片

 GlideApp.with(this)
                    .load("https://www.baidu.com/img/bd_logo.png")
                    .into(mImageView); 

  圆形图片

 GlideApp.with(this)
                    .load("https://www.baidu.com/img/bd_logo.png")
                    .circleCrop()
                    .into(mImageView);

  圆角图片

 GlideApp.with(this)
                    .load("https://www.baidu.com/img/bd_logo.png")
                    .transform(new RoundedCorners((int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
                            20, getResources().getDisplayMetrics())))
                    .into(mImageView);

 

  • 引用依赖

   build.gradle

   // 图片加载框架:https://github.com/bumptech/glide
    // 官方使用文档:https://muyangmin.github.io/glide-docs-cn/
    implementation 'com.github.bumptech.glide:glide:4.12.0'
    annotationProcessor 'com.github.bumptech.glide:compiler:4.12.0'

  ⭐由于以上加载的为网络图片,引入网络请求框架以及网络权限

    // 网络请求框架:https://github.com/getActivity/EasyHttp
    implementation 'com.hjq:http:9.0'
    // OkHttp 框架:https://github.com/square/okhttp
    // noinspection GradleDependency
    implementation 'com.squareup.okhttp3:okhttp:3.12.12'

 

  • 添加权限

  AndroidManifest.xml

 <uses-permission android:name="android.permission.INTERNET"></uses-permission>

 

⭐此时加载了Glide 依赖,但仍然无法使用GlideApp

参考以下博文:GlideApp的由来

Glide4.0源码全解析(一),GlideAPP和.with()方法背后的故事

Glide4.0源码全解析(二),load()背后的故事

Glide4.0源码全解析(三),into()方法背后的故事

主要解决方法:创建一个类 extends AppGlideModule 添加 @GlideModule 注解

 

  • 添加AndroidProject的有关构建GlideApp代码

  

 

 GlideConfig.class

package com.hjq.demo.http.glide;

import android.content.Context;

import androidx.annotation.NonNull;

import com.bumptech.glide.Glide;
import com.bumptech.glide.GlideBuilder;
import com.bumptech.glide.Registry;
import com.bumptech.glide.annotation.GlideModule;
import com.bumptech.glide.load.engine.bitmap_recycle.LruBitmapPool;
import com.bumptech.glide.load.engine.cache.DiskLruCacheWrapper;
import com.bumptech.glide.load.engine.cache.LruResourceCache;
import com.bumptech.glide.load.engine.cache.MemorySizeCalculator;
import com.bumptech.glide.load.model.GlideUrl;
import com.bumptech.glide.module.AppGlideModule;
import com.bumptech.glide.request.RequestOptions;
import com.hjq.demo.R;
import com.hjq.http.EasyConfig;

import java.io.File;
import java.io.InputStream;

/**
 *    author : Android 轮子哥
 *    github : https://github.com/getActivity/AndroidProject
 *    time   : 2019/12/15
 *    desc   : Glide 全局配置
 */
@GlideModule
public final class GlideConfig extends AppGlideModule {

    /** 本地图片缓存文件最大值 */
    private static final int IMAGE_DISK_CACHE_MAX_SIZE = 500 * 1024 * 1024;

    @SuppressWarnings("ResultOfMethodCallIgnored")
    @Override
    public void applyOptions(@NonNull Context context, @NonNull GlideBuilder builder) {
        // 读写外部缓存目录不需要申请存储权限
        File diskCacheFile = new File(context.getCacheDir(), "glide");
        // 如果这个路径是一个文件
        if (diskCacheFile.exists() && diskCacheFile.isFile()) {
            // 执行删除操作
            diskCacheFile.delete();
        }
        // 如果这个路径不存在
        if (!diskCacheFile.exists()) {
            // 创建多级目录
            diskCacheFile.mkdirs();
        }
        builder.setDiskCache(() -> DiskLruCacheWrapper.create(diskCacheFile, IMAGE_DISK_CACHE_MAX_SIZE));

        MemorySizeCalculator calculator = new MemorySizeCalculator.Builder(context).build();
        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));

        builder.setDefaultRequestOptions(new RequestOptions()
                // 设置默认加载中占位图
                .placeholder(R.drawable.image_loading_bg)
                // 设置默认加载出错占位图
                .error(R.drawable.image_error_bg));
    }

    @Override
    public void registerComponents(@NonNull Context context, @NonNull Glide glide, @NonNull Registry registry) {
        // Glide 默认使用的是 HttpURLConnection 来做网络请求,这里切换成更高效的 OkHttp
        registry.replace(GlideUrl.class, InputStream.class, new OkHttpLoader.Factory(EasyConfig.getInstance().getClient()));
    }

    @Override
    public boolean isManifestParsingEnabled() {
        return false;
    }
}

OkHttpFetcher.class
package com.vertex.myapplication.http.glide;

import androidx.annotation.NonNull;

import com.bumptech.glide.Priority;
import com.bumptech.glide.load.DataSource;
import com.bumptech.glide.load.HttpException;
import com.bumptech.glide.load.data.DataFetcher;
import com.bumptech.glide.load.model.GlideUrl;
import com.bumptech.glide.util.ContentLengthInputStream;
import com.bumptech.glide.util.Preconditions;

import java.io.IOException;
import java.io.InputStream;
import java.util.Map;

import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.ResponseBody;

/**
 *    author : Android 轮子哥
 *    github : https://github.com/getActivity/AndroidProject
 *    time   : 2019/12/15
 *    desc   : OkHttp 加载器
 */
public final class OkHttpFetcher implements DataFetcher<InputStream>, Callback {

    private final Call.Factory mCallFactory;
    private final GlideUrl mGlideUrl;
    private InputStream mInputStream;
    private ResponseBody mResponseBody;
    private DataCallback<? super InputStream> mDataCallback;
    private volatile Call mCall;

    OkHttpFetcher(Call.Factory factory, GlideUrl url) {
        mCallFactory = factory;
        mGlideUrl = url;
    }

    @Override
    public void loadData(@NonNull Priority priority, @NonNull final DataCallback<? super InputStream> callback) {
        Request.Builder requestBuilder = new Request.Builder().url(mGlideUrl.toStringUrl());
        for (Map.Entry<String, String> headerEntry : mGlideUrl.getHeaders().entrySet()) {
            String key = headerEntry.getKey();
            requestBuilder.addHeader(key, headerEntry.getValue());
        }
        Request request = requestBuilder.build();
        mDataCallback = callback;

        mCall = mCallFactory.newCall(request);
        mCall.enqueue(this);
    }

    @Override
    public void onFailure(@NonNull Call call, @NonNull IOException e) {
        mDataCallback.onLoadFailed(e);
    }

    @Override
    public void onResponse(@NonNull Call call, @NonNull Response response) {
        mResponseBody = response.body();
        if (response.isSuccessful()) {
            long contentLength = Preconditions.checkNotNull(mResponseBody).contentLength();
            mInputStream = ContentLengthInputStream.obtain(mResponseBody.byteStream(), contentLength);
            mDataCallback.onDataReady(mInputStream);
        } else {
            mDataCallback.onLoadFailed(new HttpException(response.message(), response.code()));
        }
    }

    @Override
    public void cleanup() {
        try {
            if (mInputStream != null) {
                mInputStream.close();
            }
        } catch (IOException ignored) {}

        if (mResponseBody != null) {
            mResponseBody.close();
        }
        mDataCallback = null;
    }

    @Override
    public void cancel() {
        if (mCall != null) {
            mCall.cancel();
        }
    }

    @NonNull
    @Override
    public Class<InputStream> getDataClass() {
        return InputStream.class;
    }

    @NonNull
    @Override
    public DataSource getDataSource() {
        return DataSource.REMOTE;
    }
}

 OkHttpLoader.class

package com.hjq.demo.http.glide;

import androidx.annotation.NonNull;

import com.bumptech.glide.load.Options;
import com.bumptech.glide.load.model.GlideUrl;
import com.bumptech.glide.load.model.ModelLoader;
import com.bumptech.glide.load.model.ModelLoaderFactory;
import com.bumptech.glide.load.model.MultiModelLoaderFactory;

import java.io.InputStream;

import okhttp3.Call;

/**
 *    author : Android 轮子哥
 *    github : https://github.com/getActivity/AndroidProject
 *    time   : 2019/12/15
 *    desc   : OkHttp 加载模型
 */
public final class OkHttpLoader implements ModelLoader<GlideUrl, InputStream> {

    private final Call.Factory mFactory;

    private OkHttpLoader(@NonNull Call.Factory factory) {
        mFactory = factory;
    }

    @Override
    public boolean handles(@NonNull GlideUrl url) {
        return true;
    }

    @Override
    public LoadData<InputStream> buildLoadData(@NonNull GlideUrl model, int width, int height, @NonNull Options options) {
        return new LoadData<>(model, new OkHttpFetcher(mFactory, model));
    }

    public static class Factory implements ModelLoaderFactory<GlideUrl, InputStream> {

        private final Call.Factory mFactory;

        Factory(@NonNull Call.Factory factory) {
            mFactory = factory;
        }

        @NonNull
        @Override
        public ModelLoader<GlideUrl, InputStream> build(@NonNull MultiModelLoaderFactory multiFactory) {
            return new OkHttpLoader(mFactory);
        }

        @Override
        public void teardown() {}
    }
}

 

  •  GlideConfig占位图

Android vector 参考博文:Android Studio神器之Vector Asset

R.drawable.image_loading_bg

<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
    android:width="180dp"
    android:height="180dp"
    android:viewportWidth="180"
    android:viewportHeight="180">

    <path
        android:fillColor="@color/black"
        android:fillAlpha="0.18"
        android:strokeAlpha="0.18"
        android:pathData="M116.69,42.5 C118.34,42.3,120.68,41.43,121.74,43.27
C122.94,46.03,123.19,49.07,123.84,51.98 C124.39,55.2,125.59,58.45,124.77,61.74
C110.83,60.27,96.93,58.41,83.01,56.68 C79.82,56.36,76.64,55.92,73.55,55.04
C74.11,53.54,74.86,51.92,76.67,51.72 C89.99,48.59,103.36,45.63,116.69,42.5 Z" />
    <path
        android:fillColor="@color/black"
        android:fillAlpha="0.18"
        android:strokeAlpha="0.18"
        android:pathData="M39.17,62.06 C39.85,59.59,42.92,59.71,44.91,59.02
C45.75,64.24,44.56,69.47,43.63,74.6 C43.05,74.66,41.91,74.77,41.34,74.83
C40.41,70.62,39.1,66.41,39.17,62.06 Z" />
    <path
        android:fillColor="@color/black"
        android:fillAlpha="0.18"
        android:strokeAlpha="0.18"
        android:pathData="M55.17,63.02 C56.68,62.27,58.44,62.9,60.04,62.93
C85.05,66.1,110.07,69.09,135.08,72.19 C138.1,72.15,139.04,75.49,138.56,77.95
C136.78,94.98,134.69,111.99,132.7,129 C132.23,132.41,132.31,135.96,131.14,139.24
C129.69,141.09,127.08,140.18,125.09,140.15
C102.51,137.22,79.9,134.5,57.32,131.53 C54.25,131.04,51,131.11,48.08,129.93
C46.39,128.87,46.92,126.63,46.99,124.98 C49.21,106.65,51.23,88.31,53.18,69.95
C53.69,67.69,53.14,64.57,55.17,63.02 M118.3,81.47
C114.1,83.2,112.65,88.96,115.62,92.43 C118.38,96.38,125.14,95.34,126.76,90.86
C128.97,85.83,123.8,79.05,118.3,81.47 M84.19,87.31
C82.76,88.13,81.59,89.33,80.43,90.49 C73.1,98.12,65.54,105.54,58.11,113.07
C56.74,114.2,56.52,116.68,58.35,117.48 C61.47,118.46,64.76,118.66,67.99,119.05
C79.67,120.21,91.26,122.13,102.94,123.32 C108.96,123.91,114.94,125.48,121,125.15
C122.17,125.26,123.01,123.61,122.26,122.73
C118.02,115.66,113.63,108.67,109.28,101.66
C108.33,100.31,107.51,98.68,105.95,97.94 C102.43,97.99,100.63,103.03,97.03,101.9
C93.15,97.93,91.6,92.26,87.88,88.14 C86.97,87.13,85.45,86.64,84.19,87.31 Z" />
</vector>

 

R.drawable.image_error_bg

<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
    android:width="180dp"
    android:height="180dp"
    android:viewportWidth="180"
    android:viewportHeight="180">

    <path
        android:fillAlpha="0.18"
        android:fillColor="@color/black"
        android:pathData="M43.81,52.8 C45.6,50.77,48.52,51.06,50.96,50.96
C66.31,51.08,81.66,50.92,97.01,51.04 C95.9,55.94,94.85,60.85,93.65,65.73
C92.59,70.05,88.83,72.85,86.23,76.23 C82.75,80.75,77.93,84.49,76.21,90.12
C71.8,103.07,67.12,115.92,62.69,128.86 C57.47,128.98,52.24,129.3,47.04,128.82
C43.75,128.52,41.71,125.09,42.01,121.98 C41.95,101.33,42.07,80.68,41.96,60.03
C42.06,57.56,41.75,54.61,43.81,52.8 M62.28,66.36
C57.05,67.76,55.21,75.2,59.27,78.81 C63.12,83.04,70.98,80.6,71.83,74.97
C73.14,69.67,67.41,64.51,62.28,66.36 Z"
        android:strokeAlpha="0.18" />

    <path
        android:fillAlpha="0.18"
        android:fillColor="@color/black"
        android:pathData="M113.09,51.02 C119.42,51.05,125.76,50.82,132.09,51.08
C135.68,50.97,138.36,54.51,137.99,57.94 C138.05,78.63,137.93,99.32,138.04,120.01
C137.94,122.48,138.23,125.42,136.18,127.23
C134.37,129.24,131.45,128.94,129.01,129.04
C107.67,128.93,86.33,129.07,64.99,128.97 C72.1,115.15,79.43,101.45,86.52,87.62
C89.39,81.43,95.26,77.57,99.86,72.79 C104.5,68.7,105.29,62.22,108.21,57.06
C109.37,54.7,111.32,52.91,113.09,51.02 M112.33,85.3
C107.87,91.59,105.61,99.19,101.45,105.68
C101.1,105.77,100.4,105.96,100.05,106.05 C96.75,102.67,96.3,97.32,92.83,94.08
C90.19,92.61,88.59,95.75,87.63,97.68 C85.26,102.87,82.23,107.77,80.21,113.11
C78.99,115.54,81.76,117.35,83.95,116.96 C97.3,117.1,110.65,116.92,124,117.04
C125.72,116.89,127.67,117.19,129.19,116.21
C130.93,114.51,129.46,112.14,128.7,110.34
C124.84,102.81,121.14,95.19,117.31,87.64 C116.51,85.71,114.42,83.63,112.33,85.3
Z"
        android:strokeAlpha="0.18" />
</vector>

 

有关解析AndroidProject 加载圆角图片 GlideApp加载网络图片的更多相关文章

  1. Ruby 解析字符串 - 2

    我有一个字符串input="maybe(thisis|thatwas)some((nice|ugly)(day|night)|(strange(weather|time)))"Ruby中解析该字符串的最佳方法是什么?我的意思是脚本应该能够像这样构建句子:maybethisissomeuglynightmaybethatwassomenicenightmaybethiswassomestrangetime等等,你明白了......我应该一个字符一个字符地读取字符串并构建一个带有堆栈的状态机来存储括号值以供以后计算,还是有更好的方法?也许为此目的准备了一个开箱即用的库?

  2. ruby - 解析 RDFa、微数据等的最佳方式是什么,使用统一的模式/词汇(例如 schema.org)存储和显示信息 - 2

    我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i

  3. ruby - 用逗号、双引号和编码解析 csv - 2

    我正在使用ruby​​1.9解析以下带有MacRoman字符的csv文件#encoding:ISO-8859-1#csv_parse.csvName,main-dialogue"Marceu","Giveittohimóhe,hiswife."我做了以下解析。require'csv'input_string=File.read("../csv_parse.rb").force_encoding("ISO-8859-1").encode("UTF-8")#=>"Name,main-dialogue\r\n\"Marceu\",\"Giveittohim\x97he,hiswife.\"\

  4. ruby - 如何在续集中重新加载表模式? - 2

    鉴于我有以下迁移:Sequel.migrationdoupdoalter_table:usersdoadd_column:is_admin,:default=>falseend#SequelrunsaDESCRIBEtablestatement,whenthemodelisloaded.#Atthispoint,itdoesnotknowthatusershaveais_adminflag.#Soitfails.@user=User.find(:email=>"admin@fancy-startup.example")@user.is_admin=true@user.save!ende

  5. ruby - RuntimeError(自动加载常量 Apps 多线程时检测到循环依赖 - 2

    我收到这个错误:RuntimeError(自动加载常量Apps时检测到循环依赖当我使用多线程时。下面是我的代码。为什么会这样?我尝试多线程的原因是因为我正在编写一个HTML抓取应用程序。对Nokogiri::HTML(open())的调用是一个同步阻塞调用,需要1秒才能返回,我有100,000多个页面要访问,所以我试图运行多个线程来解决这个问题。有更好的方法吗?classToolsController0)app.website=array.join(',')putsapp.websiteelseapp.website="NONE"endapp.saveapps=Apps.order("

  6. ruby-on-rails - Ruby on Rails - 为文本区域和图片生成列 - 2

    我是Rails的新手,所以请原谅简单的问题。我正在为一家公司创建一个网站。那家公司想在网站上展示它的客户。我想让客户自己管理这个。我正在为“客户”生成一个表格,我想要的三列是:公司名称、公司描述和Logo。对于名称,我使用的是name:string但不确定如何在脚本/生成脚手架终端命令中最好地创建描述列(因为我打算将其设置为文本区域)和图片。我怀疑描述(我想成为一个文本区域)应该仍然是描述:字符串,然后以实际形式进行调整。不确定如何处理图片字段。那么……说来话长:我在脚手架命令中输入什么来生成描述和图片列? 最佳答案 对于“文本”数

  7. ruby - 用 Ruby 编写一个简单的网络服务器 - 2

    我想在Ruby中创建一个用于开发目的的极其简单的Web服务器(不,不想使用现成的解决方案)。代码如下:#!/usr/bin/rubyrequire'socket'server=TCPServer.new('127.0.0.1',8080)whileconnection=server.acceptheaders=[]length=0whileline=connection.getsheaders想法是从命令行运行这个脚本,提供另一个脚本,它将在其标准输入上获取请求,并在其标准输出上返回完整的响应。到目前为止一切顺利,但事实证明这真的很脆弱,因为它在第二个请求上中断并出现错误:/usr/b

  8. ruby-on-rails - 使用 config.threadsafe 时从 lib/加载模块/类的正确方法是什么!选项? - 2

    我一直致力于让我们的Rails2.3.8应用程序在JRuby下正确运行。一切正常,直到我启用config.threadsafe!以实现JRuby提供的并发性。这导致lib/中的模块和类不再自动加载。使用config.threadsafe!启用:$rubyscript/runner-eproduction'pSim::Sim200Provisioner'/Users/amchale/.rvm/gems/jruby-1.5.1@web-services/gems/activesupport-2.3.8/lib/active_support/dependencies.rb:105:in`co

  9. ruby-on-rails - 我更新了 ruby​​ gems,现在到处都收到解析树错误和弃用警告! - 2

    简而言之错误:NOTE:Gem::SourceIndex#add_specisdeprecated,useSpecification.add_spec.Itwillberemovedonorafter2011-11-01.Gem::SourceIndex#add_speccalledfrom/opt/local/lib/ruby/site_ruby/1.8/rubygems/source_index.rb:91./opt/local/lib/ruby/gems/1.8/gems/rails-2.3.8/lib/rails/gem_dependency.rb:275:in`==':und

  10. ruby-on-rails - 从应用程序中自定义文件夹内的命名空间自动加载 - 2

    我们目前正在为ROR3.2开发自定义cms引擎。在这个过程中,我们希望成为我们的rails应用程序中的一等公民的几个类类型起源,这意味着它们应该驻留在应用程序的app文件夹下,它是插件。目前我们有以下类型:数据源数据类型查看我在app文件夹下创建了多个目录来保存这些:应用/数据源应用/数据类型应用/View更多类型将随之而来,我有点担心应用程序文件夹被这么多目录污染。因此,我想将它们移动到一个子目录/模块中,该子目录/模块包含cms定义的所有类型。所有类都应位于MyCms命名空间内,目录布局应如下所示:应用程序/my_cms/data_source应用程序/my_cms/data_ty

随机推荐