欢迎光临
我们一直在努力

Glide V4 自定义配置

Android阅读(3521)

一、简介

Glide V4 的基本用法和旧版本基本一样(查看基本用法),主要区别在于新增了一个注解功能。

Glide v4 使用 注解处理器 (Annotation Processor) 来生成出一个 API,在 Application 模块中可使用该流式 API 一次性调用到 RequestBuilder, RequestOptions 和集成库中所有的选项。

Generated API 模式的设计出于以下两个目的:

1、集成库可以为 Generated API 扩展自定义选项。
2、在 Application 模块中可将常用的选项组打包成一个选项在 Generated API 中使用

虽然以上所说的工作均可以通过手动创建 RequestOptions 子类的方式来完成,但想将它用好更具有挑战,并且降低了 API 使用的流畅性。

二、配置

有多个模块的工程,个人建议在最底层基础模块中配置,这样可以保证每个模块都可以调用到。

1、添加 Glide 注解处理器的依赖

dependencies {
    annotationProcessor 'com.github.bumptech.glide:compiler:4.8.0'
}

2、在对应模块中(建议底层Base模块)实现一个AppGlideModule:

你不必去重写 AppGlideModule 中的任何一个方法。子类中完全可以不用写任何东西,它只需要继承 AppGlideModule 并且添加 @GlideModule 注解。

AppGlideModule 的实现必须使用 @GlideModule 注解标记。如果注解不存在,该 module 将不会被 Glide 发现,并且在日志中收到一条带有 Glide tag 的警告,表示 module 未找到。

package com.test.base.glide;

import com.bumptech.glide.annotation.GlideModule;
import com.bumptech.glide.module.AppGlideModule;

@GlideModule
public final class MyAppGlideModule extends AppGlideModule {
}

三、自定义配置

Glide 允许应用通过 AppGlideModule 实现来完全控制 Glide 的内存和磁盘缓存使用。Glide 试图提供对大部分应用程序合理的默认选项,但对于部分应用,可能就需要定制这些值。在你做任何改变时,请注意测量其结果,避免出现性能的倒退。

1、自定义内存缓存

默认情况下,Glide使用 LruResourceCache ,这是 MemoryCache 接口的一个缺省实现,使用固定大小的内存和 LRU 算法。LruResourceCache 的大小由 Glide 的 MemorySizeCalculator 类来决定,这个类主要关注设备的内存类型,设备 RAM 大小,以及屏幕分辨率。

应用程序可以自定义 MemoryCache 的大小,具体是在它们的 AppGlideModule 中使用 applyOptions(Context, GlideBuilder) 方法配置 MemorySizeCalculator :

@GlideModule
public class YourAppGlideModule extends AppGlideModule {
  @Override
  public void applyOptions(Context context, GlideBuilder builder) {
    MemorySizeCalculator calculator = new MemorySizeCalculator.Builder(context)
        .setMemoryCacheScreens(2)
        .build();
    builder.setMemoryCache(new LruResourceCache(calculator.getMemoryCacheSize()));
  }
}

也可以直接覆写缓存大小:

@GlideModule
public class YourAppGlideModule extends AppGlideModule {
  @Override
  public void applyOptions(Context context, GlideBuilder builder) {
    int memoryCacheSizeBytes = 1024 * 1024 * 20; // 20mb
    builder.setMemoryCache(new LruResourceCache(memoryCacheSizeBytes));
  }
}

甚至可以提供自己的 MemoryCache 实现:

@GlideModule
public class YourAppGlideModule extends AppGlideModule {
  @Override
  public void applyOptions(Context context, GlideBuilder builder) {
    builder.setMemoryCache(new YourAppMemoryCacheImpl());
  }
}

2、自定义Bitmap池

Glide 使用 LruBitmapPool 作为默认的 BitmapPool 。LruBitmapPool 是一个内存中的固定大小的 BitmapPool,使用 LRU 算法清理。默认大小基于设备的分辨率和密度,同时也考虑内存类和 isLowRamDevice 的返回值。具体的计算通过 Glide 的 MemorySizeCalculator 来完成,与 Glide 的 MemoryCache 的大小检测方法相似。

应用可以在它们的 AppGlideModule 中定制 [BitmapPool] 的尺寸,使用 applyOptions(Context, GlideBuilder) 方法并配置 MemorySizeCalculator:

@GlideModule
public class YourAppGlideModule extends AppGlideModule {
  @Override
  public void applyOptions(Context context, GlideBuilder builder) {
    MemorySizeCalculator calculator = new MemorySizeCalculator.Builder(context)
        .setBitmapPoolScreens(3)
        .build();
    builder.setBitmapPool(new LruBitmapPool(calculator.getBitmapPoolSize()));
  }
}

应用也可以直接复写这个池的大小:

@GlideModule
public class YourAppGlideModule extends AppGlideModule {
  @Override
  public void applyOptions(Context context, GlideBuilder builder) {
    int bitmapPoolSizeBytes = 1024 * 1024 * 30; // 30mb
    builder.setBitmapPool(new LruBitmapPool(bitmapPoolSizeBytes));
  }
}

甚至可以提供 BitmapPool 的完全自定义实现:

@GlideModule
public class YourAppGlideModule extends AppGlideModule {
  @Override
  public void applyOptions(Context context, GlideBuilder builder) {
    builder.setBitmapPool(new YourAppBitmapPoolImpl());
  }
}

3、自定义磁盘缓存

Glide 使用 DiskLruCacheWrapper 作为默认的 磁盘缓存 。 DiskLruCacheWrapper 是一个使用 LRU 算法的固定大小的磁盘缓存。默认磁盘大小为 250 MB ,位置是在应用的 缓存文件夹 中的一个 特定目录 。

假如应用程序展示的媒体内容是公开的(例如从无授权机制的网站或搜索引擎上加载),那么应用可以将这个缓存位置改到外部存储:

@GlideModule
public class YourAppGlideModule extends AppGlideModule {
  @Override
  public void applyOptions(Context context, GlideBuilder builder) {
    builder.setDiskCache(new ExternalCacheDiskCacheFactory(context));
  }
}

无论使用内部或外部磁盘缓存,应用程序都可以改变磁盘缓存的大小:

@GlideModule
public class YourAppGlideModule extends AppGlideModule {
  @Override
  public void applyOptions(Context context, GlideBuilder builder) {
    int diskCacheSizeBytes = 1024*1024*100;//100 MB
    builder.setDiskCache(new InternalCacheDiskCacheFactory(context, diskCacheSizeBytes));
  }
}

应用程序还可以改变缓存文件夹在外存或内存上的名字:

@GlideModule
public class YourAppGlideModule extends AppGlideModule {
  @Override
  public void applyOptions(Context context, GlideBuilder builder) {
    int diskCacheSizeBytes = 1024*1024*100;//100 MB
    builder.setDiskCache(
        new InternalCacheDiskCacheFactory(context, cacheFolderName, diskCacheSizeBytes));
  }
}

应用程序还可以自行选择 DiskCache 接口的实现,并提供自己的 DiskCache.Factory 来创建缓存。Glide 使用一个工厂接口来在后台线程中打开 磁盘缓存 ,这样方便缓存做诸如检查路径存在性等的IO操作而不用触发 严格模式 。

@GlideModule
public class YourAppGlideModule extends AppGlideModule {
  @Override
  public void applyOptions(Context context, GlideBuilder builder) {
    builder.setDiskCache(new DiskCache.Factory() {
        @Override
        public DiskCache build() {
          return new YourAppCustomDiskCache();
        }
    });
  }
}

或者通过DiskLruCacheFactory自定义路径和大小

@GlideModule
public class YourAppGlideModule extends AppGlideModule {
  @Override
  public void applyOptions(Context context, GlideBuilder builder) {
  	int diskCacheSizeBytes = 1024*1024*100;//100 MB
    builder.setDiskCache(
    	new DiskLruCacheFactory(context.getCacheDir().getPath(),"glideCache",diskCacheSizeBytes)
    });
  }
}

4、设置默认配置

虽然请求选项 通常由每个请求单独指定,你也可以通过 AppGlideModule 应用一个 请求选项的集合以作用于你应用中启动的每个加载:

@GlideModule
public class YourAppGlideModule extends AppGlideModule {
  @Override
  public void applyOptions(Context context, GlideBuilder builder) {
    builder.setDefaultRequestOptions(
        new RequestOptions()
          .format(DecodeFormat.RGB_565)
          .disallowHardwareBitmaps());
  }
}

一旦你创建了新的请求,这些选项将通过 GlideBuilder 中的 setDefaultRequestOptions 被应用上。因此,任何单独请求里应用的选项将覆盖 GlideBuilder 里设置的冲突选项。

类似地,RequestManagers 允许你为这个特定的 RequestManager 启动的所有加载请求设置默认的 请求选项。 因为每个 Activity 和 Fragment 都拥有自己的 RequestManager,你可以使用 RequestManager 的 applyDefaultRequestOptions 方法来设置默认的 RequestOption,并仅作用于一个特定的 Activity 或 Fragment:

Glide.with(fragment)
  .applyDefaultRequestOptions(
      new RequestOptions()
          .format(DecodeFormat.RGB_565)
          .disallowHardwareBitmaps());

RequestManager 还有一个 setDefaultRequestOptions 方法,可以完全替换掉之前设置的任意的默认 请求选项,无论它是通过 AppGlideModule 的 [GlideBuilder] 还是 RequestManager。使用 [setDefaultRequestOptions]要小心,因为很容易意外覆盖掉你其他地方设置的重要默认选项。 通常 applyDefaultRequestOptions更安全,使用起来更直观。

Glide V4 使用指南

Android阅读(1771)

一、简介

Glide是一个快速高效的Android图片加载库,注重于平滑的滚动,被Google推荐并广泛运用在Google的开源项目中。Glide提供了易用的API,高性能、可扩展的图片解码管道,以及自动的资源池技术。

Glide 支持拉取,解码和展示视频快照,图片,和GIF动画。Glide的Api是如此的灵活,开发者甚至可以插入和替换成自己喜爱的任何网络栈。默认情况下,Glide使用的是一个定制化的基于HttpUrlConnection的栈,但同时也提供了与Google Volley和Square OkHttp快速集成的工具库。

虽然Glide 的主要目标是让任何形式的图片列表的滚动尽可能地变得更快、更平滑,但实际上,Glide几乎能满足你对远程图片的拉取/缩放/显示的一切需求。

二、使用指南

1、版本说明

Min Sdk Version – 使用 Glide 需要 min SDK 版本 API 14 (Ice Cream Sandwich) 或更高。

Compile Sdk Version – Glide 必须使用 API 27 (Oreo MR1) 或更高版本的 SDK 来编译。

Support Library Version – Glide 使用的支持库版本为 27。

如果你需要使用不同的支持库版本,你需要在你的 build.gradle 文件里去从 Glide 的依赖中去除 “com.android.support”。例如,假如你想使用 v26 的支持库:

dependencies {
  implementation ("com.github.bumptech.glide:glide:4.8.0") {
    exclude group: "com.android.support"
  }
  implementation "com.android.support:support-fragment:26.1.0"
}

2、导入

在gradle的配置文件中加入如下配置:

repositories {
  mavenCentral()
  maven { url 'https://maven.google.com' }
}

dependencies {
    compile 'com.github.bumptech.glide:glide:4.8.0'
    annotationProcessor 'com.github.bumptech.glide:compiler:4.8.0'
}

3、基本用法

多数情况下,使用Glide加载图片非常简单,一行代码足以:

Glide.with(fragment)
    .load(myUrl)
    .into(imageView);

取消加载同样很简单:

Glide.with(fragment).clear(imageView);

尽管及时取消不必要的加载是很好的实践,但这并不是必须的操作。实际上,当 Glide.with() 中传入的 Activity 或 Fragment 实例销毁时,Glide 会自动取消加载并回收资源。

Android系统启动流程

Android阅读(1102)

1、启动电源

当电源按下时,引导芯片代码从预定义的地方开始执行。加载引导程序BootLoader到ram,然后执行。

2、引导程序BootLoader

引导程序BootLoader是在Android操作系统开始运行前的一个小程序,它的主要作用是把系统OS拉起来并运行。

3、Linux内核启动

当内核启动时,会设置换成、被保护存储器、计划列表、加载驱动。然后再系统文件中寻找init.rc文件,并启动init进程。

4、init进程启动

初始化和启动属性服务,并启动孵化器(Zygote)进程。

5、Zygote进程启动

创建Java虚拟机并未Java虚拟机注册JNI方法,创建服务器端Socket,启动SystemServer进程。

6、SystemServer进程启动

启动Binder线程池和SystemServiceManager,并启动各种系统服务。

7、Launcher启动。

Android系统架构

Android阅读(1185)

Android系统架构分为五层,从上到下依次是应用层、应用框架层、系统运行库层、硬件抽象层和Linux内核层。

一、应用层(Application层)

系统内置的应用程序以及非系统级的应用程序都属于应用层,大部分是由Java编写。

二、应用框架层(Framework层)

应用框架层为开发人员提供了可以开发应用程序所需要的API,我们平常开发应用程序都是调用的这一层所提供的API。这一层的是由Java代码编写的,每个APP开发人员都必须要掌握其内容。下面来看这一层所提供的主要的组件。

  • Activity Manager(活动管理器):管理各个应用程序生命周期以及通常的导航回退功能
  • Location Manager(位置管理器):提供地理位置以及定位功能服务
  • Package Manager(包管理器):管理所有安装在Android系统中的应用程序
  • Notification Manager(通知管理器):使得应用程序可以在状态栏中显示自定义的提示信息
  • Resource Manager(资源管理器):提供应用程序使用的各种非代码资源,如本地化字符串、图片、布局文件、颜色文件等
  • Telephony Manager(电话管理器):管理所有的移动设备功能
  • Package Manager(包管理器):管理所有安装在Android系统中的应用程序
  • Window Manager(窗口管理器):管理所有开启的窗口程序
  • Content Providers(内容提供器):使得不同应用程序之间可以共享数据
  • View System(视图系统):构建应用程序的基本组件

三、系统运行库层(Native层)

系统运行库层分为两部分,分别是C/C++程序库和Android运行时库。

1、C/C++程序库

这些库被Android系统中不同的组件使用,并且通过 Android 应用程序框架为开发者提供服务。以下是一些核心库:

  • Libc:从BSD继承来的标准C系统函数库,专门为基于嵌入式Linux的设备定制
  • Media Framework:多媒体库,该库支持多种常用的音频、视频格式回放和录制,同时支持静态图像文件。编码格式包括MPEG4,H.264,MP3,AAC,AMR,JPG,PNG。
  • Surface Manager:对显示子系统的管理,并且为多个应用程序提供了2D和3D图层的无缝融合
  • LibWebCore:一个最新的web浏览器引擎用,支持Android浏览器和一个可嵌入的web视图
  • SGL:底层的2D图形引擎
  • 3D libraries:基于OpenGLES1.0APIs实现;该库可以使用硬件3D加速(如果可用)或者使用高度优化的3D软加速
  • FreeType:可移植的字体引擎,它提供统一的接口来访问多种字体格式文件
  • SQLite:轻型的关系型数据库引擎

2、Android Runtime

运行时库又分为核心库和ART(5.0系统之后,Dalvik虚拟机被ART取代)。核心库提供了Java语言核心库的大多数功能,这样开发者可以使用Java语言来编写Android应用。相较于JVM,Dalvik虚拟机是专门为移动设备定制的,允许在有限的内存中同时运行多个虚拟机的实例,并且每一个Dalvik 应用作为一个独立的Linux 进程执行。独立的进程可以防止在虚拟机崩溃的时候所有程序都被关闭。而替代Dalvik虚拟机的ART 的机制与Dalvik 不同。在Dalvik下,应用每次运行的时候,字节码都需要通过即时编译器转换为机器码,这会拖慢应用的运行效率,而在ART 环境中,应用在第一次安装的时候,字节码就会预先编译成机器码,使其成为真正的本地应用。

四、Linux内核层

Android 的核心系统服务基于Linux 内核,在此基础上添加了部分Android专用的驱动。系统的安全性、内存管理、进程管理、网络协议栈和驱动模型等都依赖于该内核。

Android——应用启动过程

半醉, 人间阅读(1265)

以Launcher启动应用为例:

Launcher通知AMS启动应用,AMS记录应用信息,通过applicationThread通知Launcher进入Pause状态,Launcher进入Pause状态后通知AMS,然后AMS创建新的进程,创建ActivityThread,执行ActivityThread的main函数,然后将applicationThread传递给AMS,后续AMS就通过applicationThread来跟应用程序进行通信,然后AMS通知应用绑定ApplicationContext,启动MainActivity、创建和关联Context,然后调用onCreate、onStart、onResume方法

Android中常见的线程池

半醉, 人间阅读(1360)

Android中的线程池都是直接或者间接的通过配置ThreadPoolExecutor来实现不同特性的线程池的。Android中最常见的四类具有不同特性的线程池分别是:FixThreadPool、CacheThreadPool、SingleThreadPool、ScheduleThreadPool

  1. FixThreadPool
    只有核心线程,并且数量是固定的,所有线程都是活跃的,因为队列没有大小限制,新的任务会等待执行
    优点:更快的响应外界的请求

  2. SingleThreadPool
    只有一个核心线程,所有的任务都在同一个线程中顺序执行,因此不需要处理线程同步的问题

  3. CacheThreadPool
    只有非核心线程,最大线程数非常大,所有线程都在活动时,新的任务会创建新的线程,否则会利用空闲线程处理任务(60s空闲时间,过了就会被回收)

  4. ScheduleThreadPool
    核心线程数量固定,非核心线程数量没有限制(非核心线程空闲就会被回收)
    优点:用于执行定时任务以及有固定周期的重复任务

Android内存泄漏原因整理

半醉, 人间阅读(1076)

造成Android内存泄漏的原因大概有以下几方面:

  1. 资源对象没关闭造成的内存泄漏。(如:图片,文件等)

  2. 构造Adapter时,没有使用缓存的ContentView

  3. 注册没取消造成的内存泄漏(广播接收器)

  4. 集合中的对象没有清理造成的内存泄漏

  5. 单例造成的内存泄漏。比如:单例持有了一个Activity的Context。

  6. 非静态内部类静态实例造成的内存泄漏

  7. Handle 和 Runnable作为非静态内部类造成的内存泄漏

  8. 生命周期比Activity长的线程持有Activity造成的内存泄漏