热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

关于移动端:高性能图片优化方案

目录介绍01.图片根底概念介绍1.1图片占用内存介绍1.2加载网络图片流程1.3三方库加载图片逻辑1.4从网络间接拉取图片1.5加载图片的流程1.6Bitmap能间接存

目录介绍

  • 01.图片根底概念介绍

    • 1.1 图片占用内存介绍
    • 1.2 加载网络图片流程
    • 1.3 三方库加载图片逻辑
    • 1.4 从网络间接拉取图片
    • 1.5 加载图片的流程
    • 1.6 Bitmap能间接存储吗
    • 1.7 Bitmap创立流程
    • 1.8 图片框架如何设计
  • 02.图片内存计算形式

    • 2.1 如何计算占用内存
    • 2.2 下面计算内存对吗
    • 2.3 一个像素占用内存
    • 2.4 应用API获取内存
    • 2.5 影响Bitmap内存因素
    • 2.6 加载xhdpi和xxhdpi图片
    • 2.7 图片一些注意事项
  • 03.大图的内存优化

    • 3.1 常见图片压缩
    • 3.2 图片尺寸压缩
    • 3.3 图片品质压缩
    • 3.4 双线性采样压缩
    • 3.5 高清图分片加载
    • 3.6 图片综合压缩
  • 04.色调格局及内存优化

    • 4.1 RGB色彩品种
    • 4.2 ARGB色调模式
    • 4.3 扭转色调格局优化
  • 05.缓存的应用实际优化

    • 5.1 Lru内存缓存
    • 5.2 Lru内存注意事项
    • 5.3 应用Lru磁盘缓存
  • 06.不同版本对Bitmap治理

    • 6.1 演变过程
    • 6.2 治理Bitmap内存
    • 6.3 进步Bitmap复用
  • 07.图片其余方面优化

    • 7.1 缩小PNG图片的应用
    • 7.2 控件切割圆角优化
    • 7.3 如何给图片置灰色
    • 7.4 如何解决图片旋转呢
    • 7.5 保留图片且刷相册
    • 7.6 对立图片域名优化
    • 7.7 优化H5图片加载
    • 7.8 优化图片暗影成果
    • 7.9 图片资源的压缩

01.图片根底概念介绍

1.1 图片占用内存介绍

  • 挪动设施的系统资源无限,所以利用应该尽可能的升高内存的应用。

    • 在利用运行过程中,Bitmap (图片)往往是内存占用最大的一个局部,Bitmap 图片的加载和解决,通常会占用大量的内存空间,所以在操作 Bitmap 时,应该尽可能的小心。
  • Bitmap 会耗费很多的内存,特地是诸如照片等内容丰盛的大图。

    • 例如,一个手机拍摄的 2700 1900 像素的照片,须要 5.1M 的存储空间,然而在图像解码配置 ARGB_8888 时,它加载到内存须要 19.6M 内存空间(2592 1936 * 4 bytes),从而迅速消耗掉该利用的残余内存空间。
    • OOM 的问题也是咱们常见的重大问题,OOM 的产生的一个次要场景就是在大图片分配内存的时候产生的,如果 APP 可用内存缓和,这时加载了一张大图,内存空间不足以调配该图片所须要的内存,就会产生 OOM,所以管制图片的高效应用是必备技能。

1.2 加载网络图片流程

  • 这一部分压缩和缓存图片,在glide源码剖析的文章里曾经做出了比拟具体的阐明。在这里简略说一下图片申请加载过程……
  • 在应用App的时候,会常常须要加载一些网络图片,个别的操作步骤大略是这样的:

    • 第一步从网络加载图片:个别都是通过网络拉取的形式去服务器端获取到图片的文件流后,再通过BitmapFactory.decodeStream(InputStream)来加载图片Bitmap。
    • 第二步这种压缩图片:网络加载图片形式加载一两张图片倒不会呈现问题,然而如果短时间内加载十几张或者几十张图片的时候,就很有可能会造成OOM(内存溢出),因为当初的图片资源大小都是十分大的,所以咱们在加载图片之前还须要进行相应的图片压缩解决。
    • 第三步变换图片:比方须要裁剪,切割圆角,旋转,增加高斯含糊等属性。
    • 第四步缓存图片:但又有个问题来了,在应用挪动数据的状况下,如果用户每次进入App的时候都会去进行网络拉取图片,这样就会十分的节约数据流量,这时又须要对图片资源进行一些相应的内存缓存以及磁盘缓存解决,这样不仅节俭用户的数据流量,还能放慢图片的加载速度。
    • 第五步异步加载:尽管利用缓存的形式能够放慢图片的加载速度,但当须要加载很多张图片的时候(例如图片墙瀑布流成果),就还需用到多线程来加载图片,应用多线程就会波及到线程同步加载与异步加载问题。

1.3 三方库加载图片逻辑

  • 先说出论断,目前市面较为罕用的大略是Glide,Picasso,Fresco等。大略的解决图片波及次要逻辑有:

    • 从网络或者本地等门路拉取图片;而后解码图片;而后进行压缩;接着会有图片罕用圆角,含糊或者裁剪等解决;而后三级缓存加载的图片;当然加载图片过程波及同步加载和异步加载;最初设置到具体view控件上。

1.4 从网络间接拉取图片

  • 间接通过网络申请将网络图片转化成bitmap

    • 在这将采纳最原生的网络申请形式HttpURLConnection形式进行图片获取。
    • 通过测试,申请8张图片,耗时毫秒值174。个别是通过get申请拉取图片的。这种办法应该是最根底的网络申请,大家也能够回顾一下,个别开发中很少用这种形式加载图片。具体能够看:ImageToolLib
  • 如何加载一个图片呢?

    • 能够看看BitmapFactory类为咱们提供了四类办法来加载Bitmap:decodeFile、decodeResource、decodeStream、decodeByteArray;也就是说Bitmap,Drawable,InputStream,Byte[] 之间是能够进行转换。

1.5 加载图片的流程

  • 搞清楚一个图片概念

    • 在电脑上看到的 png 格局或者 jpg 格局的图片,png(jpg) 只是这张图片的容器。是通过绝对应的压缩算法将原图每个像素点信息转换用另一种数据格式示意。
  • 加载图片显示到手机

    • 通过代码,将这张图片加载进内存时,会先解析(也就是解码操作)图片文件自身的数据格式,而后还原为位图,也就是 Bitmap 对象。
  • 图片大小vs图片内存大小

    • 一张 png 或者 jpg 格局的图片大小,跟这张图片加载进内存所占用的大小齐全是两回事。

1.6 Bitmap能间接存储吗

  • Bitmap根底概念

    • Bitmap对象实质是一张图片的内容在手机内存中的表达形式。它将图片的内容看做是由存储数据的无限个像素点组成;每个像素点存储该像素点地位的ARGB值。每个像素点的ARGB值确定下来,这张图片的内容就相应地确定下来了。
  • Bitmap实质上不能间接存储

    • 为什么?bitmap是一个对象,如果要存储老本地能够查看的图片文件,则必须对bitmap进行编码,而后通过io流写到本地file文件上。

1.7 Bitmap创立流程

  • 对于图片OOM,能够发现一个景象。

    • heapsize(虚拟机的内存配置)越大越不容易 OOM,Android8.0 及之后的版本更不容易 OOM,这个该如何了解呢?
  • Bitmap对象内存的变动:

    • 在 Android 8.0 之前,Bitmap 像素占用的内存是在 Java heap 中调配的;8.0 及之后,Bitmap 像素占用的内存调配到了 Native Heap。
    • 因为 Native heap 的内存调配下限很大,32 位利用的可用内存在 3~4G,64 位上更大,虚拟内存简直很难耗尽,所以揣测 OOM 时 Java heap 中占用内存较多的对象是 Bitmap” 成立的状况下,利用更不容易 OOM。
  • 搞清楚Bitmap对象内存调配

    • Bitmap 的构造方法是不公开的,在应用 Bitmap 的时候,个别都是通过 Bitmap、BitmapFactory 提供的静态方法来创立 Bitmap 实例。
    • 以 Bitmap.createBitmap 阐明了 Bitmap 对象的次要创立过程剖析,能够看到 Java Bitmap 对象是在 Native 层通过 NewObject 创立的。
    • allocateJavaPixelRef,是 8.0 之前版本为 Bitmap 像素从 Java heap 申请内存。其外围原理是Bitmap 的像素是保留在 Java 堆上。
    • allocateHeapBitmap,是 8.0 版本为 Bitmap 像素从 Native heap 申请内存。其外围原理次要是通过 calloc 为 Bitmap 的像素分配内存,这个调配就在 Native 堆上。
    • 更多具体内容能够看:Bitmap对象内存调配

1.8 图片框架如何设计

  • 大多数图片框架加载流程

    • 概括来说,图片加载蕴含封装,解析,下载,解码,变换,缓存,显示等操作。
  • 图片框架是如何设计的

    • 封装参数:从指定起源,到输入后果,两头可能经验很多流程,所以第一件事就是封装参数,这些参数会贯通整个过程;
    • 解析门路:图片的起源有多种,格局也不尽相同,须要规范化;比方glide能够加载file,io,id,网络等各种图片资源
    • 读取缓存:为了缩小计算,通常都会做缓存;同样的申请,从缓存中取图片(Bitmap)即可;
    • 查找文件/下载文件:如果是本地的文件,间接解码即可;如果是网络图片,须要先下载;比方glide这块是发动一个申请
    • 解码:这一步是整个过程中最简单的步骤之一,有不少细节;比方glide中解析图片数据源,旋转方向,图片头等信息
    • 变换和压缩:解码出Bitmap之后,可能还须要做一些变换处理(圆角,滤镜等),还要做图片压缩;
    • 缓存:失去最终bitmap之后,能够缓存起来,以便下次申请时间接取后果;比方glide用到三级缓存
    • 显示:显示后果,可能须要做些动画(淡入动画,crossFade等);比方glide设置显示的时候能够增加动画成果

02.图片内存计算形式

2.1 如何计算占用内存

  • 如果图片要显示下Android设施上,ImageView最终是要加载Bitmap对象的,就要思考单个Bitmap对象的内存占用了,如何计算一张图片的加载到内存的占用呢?其实就是所有像素的内存占用总和:
  • bitmap内存大小 = 图片长度 x 图片宽度 x 单位像素占用的字节数
  • 起决定因素就是最初那个参数了,Bitmap常见有2种编码方式:ARGB_8888和RGB_565,ARGB_8888每个像素点4个byte,RGB_565是2个byte,个别都采纳ARGB_8888这种。那么常见的1080*1920的图片内存占用就是:1920 x 1080 x 4 = 7.9M

2.2 下面计算内存对吗

  • 我看到好多博客都是这样计算的,然而这样算对吗?有没有哥们试验过这种办法正确性?我感觉看博客要对博主示意狐疑,论证他人写的是否正确。

    • 说出我的论断:下面2.1这种说法也对,然而不全对,没有阐明场景,同时也疏忽了一个影响项:Density。接下来看看源代码。
    • inDensity默认为图片所在文件夹对应的密度;inTargetDensity为以后零碎密度。
    • 加载一张本地资源图片,那么它占用的内存 = width height nTargetDensity/inDensity 一个像素所占的内存。

      @Nullable
      public static Bitmap decodeResourceStream(@Nullable Resources res, @Nullable TypedValue value,
          @Nullable InputStream is, @Nullable Rect pad, @Nullable Options opts) {
      validate(opts);
      if (opts == null) {
          opts = new Options();
      }
      
      if (opts.inDensity == 0 && value != null) {
          final int density = value.density;
          if (density == TypedValue.DENSITY_DEFAULT) {
              opts.inDensity = DisplayMetrics.DENSITY_DEFAULT;
          } else if (density != TypedValue.DENSITY_NONE) {
              opts.inDensity = density;
          }
      }
      
      if (opts.inTargetDensity == 0 && res != null) {
          opts.inTargetDensity = res.getDisplayMetrics().densityDpi;
      }
      
      return decodeStream(is, pad, opts);
      }
  • 正确说法,这个留神呢?计算公式如下所示

    • 对资源文件:width height nTargetDensity/inDensity nTargetDensity/inDensity 一个像素所占的内存;
    • 别的:width height 一个像素所占的内存;

2.3 一个像素占用内存

  • 一个像素占用多大内存?Bitmap.Config用来形容图片的像素是怎么被存储的?

    • ARGB_8888: 每个像素4字节. 共32位,默认设置。
    • Alpha_8: 只保留透明度,共8位,1字节。
    • ARGB_4444: 共16位,2字节。
    • RGB_565:共16位,2字节,只存储RGB值。

2.4 应用API获取内存

  • Bitmap应用API获取内存

    • getByteCount()

      • getByteCount()办法是在API12退出的,代表存储Bitmap的色素须要的起码内存。API19开始getAllocationByteCount()办法代替了getByteCount()。
    • getAllocationByteCount()

      • API19之后,Bitmap加了一个Api:getAllocationByteCount();代表在内存中为Bitmap调配的内存大小。
  • 思考: getByteCount()与getAllocationByteCount()的区别?

    • 个别状况下两者是相等的;通过复用Bitmap来解码图片,如果被复用的Bitmap的内存比待分配内存的Bitmap大,那么getByteCount()示意新解码图片占用内存的大小(并非理论内存大小,理论大小是复用的那个Bitmap的大小),getAllocationByteCount()示意被复用Bitmap实在占用的内存大小(即mBuffer的长度)。
  • 在复用Bitmap的状况下,getAllocationByteCount()可能会比getByteCount()大。

2.5 影响Bitmap内存因素

  • 影响Bitmap占用内存的因素:

    • 图片最终加载的分辨率;
    • 图片的格局(PNG/JPEG/BMP/WebP);
    • 图片所寄存的drawable目录;
    • 图片属性设置的色调模式;
    • 设施的屏幕密度;

2.6 加载xhdpi和xxhdpi图片

  • 提个问题,加载xhdpi和xxhdpi中雷同的图片,显示在控件上会一样吗?内存大小一样吗?为什么?

    • 必定是不一样的。xhdpi:240dpi–320dpi,xxhdpi:320dpi–480dpi,
  • app中设置的图片是如何从hdpi中查找的?

    • 首先计算dpi,比方手机分辨率是1920×1080,5.1寸的手机。那么失去的dpi公式是(√ ̄1920² + 1080²)/5.1 =2202/5.1= 431dpi。这样优先查找xxhdpi
    • 如果xxhdpi里没有查找图片,如果没有会往上找,遵循“先高再低”准则。如果xhdpi里有这个图片会应用xhdpi里的图片,这时候发现会比在xhdpi里的图片放大了。
  • 为何要引入不同hdpi的文件治理?

    • 比方:xxhdpi放94×94,xhdpi放74×74,hdpi放45×45,这样不论是什么样的手机图片都能在指定的比例显示。引入多种hdpi是为了让这个图片在任何手机上都是手机的这个比例。

2.7 图片一些注意事项

  • 同样图片显示在大小不雷同的ImageView上,内存是一样吗?

    • 图片占据内存空间大小与图片在界面上显示的大小没有关系。
  • 图片放在res不同目录,加载的内存是一样的吗?

    • 最终图片加载进内存所占据的大小会不一样,因为零碎在加载 res 目录下的资源图片时,会依据图片寄存的不同目录做一次分辨率的转换,而转换的规定是:新图的高度 = 原图高度 * (设施的 dpi / 目录对应的 dpi )

03.大图的内存优化

3.1 常见图片压缩

  • 常见压缩办法Api

    • Bitmap.compress(),品质压缩,不会对内存产生影响;
    • BitmapFactory.Options.inSampleSize,内存压缩;
  • Bitmap.compress()品质压缩

    • 品质压缩,不会对内存产生影响。它是在放弃像素的前提下扭转图片的位深及透明度等,来达到压缩图片的目标,不会缩小图片的像素。进过它压缩的图片文件大小会变小,然而解码成bitmap后占得内存是不变的。
  • BitmapFactory.Options.inSampleSize内存压缩

    • 解码图片时,设置BitmapFactory.Options类的inJustDecodeBounds属性为true,能够在Bitmap不被加载到内存的前提下,获取Bitmap的原始宽高。而设置BitmapFactory.Options的inSampleSize属性能够实在的压缩Bitmap占用的内存,加载更小内存的Bitmap。
    • 设置inSampleSize之后,Bitmap的宽、高都会放大inSampleSize倍。例如:一张宽高为2048×1536的图片,设置inSampleSize为4之后,理论加载到内存中的图片宽高是512×384。占有的内存就是0.75M而不是12M,足足节俭了15倍。
    • 备注:inSampleSize值的大小不是轻易设、或者越大越好,须要依据理论状况来设置。inSampleSize比1小的话会被当做1,任何inSampleSize的值会被取靠近2的幂值。

3.2 图片尺寸压缩

3.2.1 如何了解尺寸压缩
  • 通常在大多数状况下,图片的理论大小都比须要出现的尺寸大很多。

    • 例如,咱们的原图是一张 2700 1900 像素的照片,加载到内存就须要 19.6M 内存空间,然而,咱们须要把它展现在一个列表页中,组件可展现尺寸为 270 190,这时,咱们实际上只须要一张原图的低分辨率的缩略图即可(与图片显示所对应的 UI 控件匹配),那么实际上 270 * 190 像素的图片,只须要 0.2M 的内存即可。
    • 能够看到,优化前后相差了 98 倍,原来显示 1 张,当初能够显示 98 张图片,成果十分显著。
  • 既然在对原图缩放能够显著缩小内存大小,那么咱们应该如何操作呢?

    • 先加载到内存,再进行操作吗,能够如果先加载到内存,如同也不太对,这样只接占用了 19.6M + 0.2M 2份内存了,而咱们想要的是,在原图不加载到内存中,只接将缩放后的图片加载到内存中,能够实现吗?
  • BitmapFactory 提供了从不同资源创立 Bitmap 的解码办法:

    • decodeByteArray()、decodeFile()、decodeResource() 等。然而,这些办法在结构位图的时候会尝试分配内存,也就是它们会导致原图间接加载到内存了,不满足咱们的需要。咱们能够通过 BitmapFactory.Options 设置一些附加的标记,指定解码选项,以此来解决该问题。
    • 如何操作呢?答案来了:将 inJustDecodeBounds 属性设置为 true,能够在解码时防止内存的调配,它会返回一个 null 的 Bitmap ,然而能够获取 outWidth、outHeight 和 outMimeType 值。利用该属性,咱们就能够在图片不占用内存的状况下,在图片压缩之前获取图片的尺寸。
  • 怎样才能对图片进行压缩呢?

    • 通过设置BitmapFactory.Options中inSampleSize的值就能够实现。其计算形式大略就是:计算出理论宽高和指标宽高的比率,而后抉择宽和高中最小的比率作为inSampleSize的值,这样能够保障最终图片的宽和高。
3.2.2 设置BitmapFactory.Options属性
  • 大略步骤如下所示

    • 要将BitmapFactory.Options的inJustDecodeBounds属性设置为true,解析一次图片。留神这个中央是外围,这个解析图片并没有生成bitmap对象(也就是说没有为它分配内存控件),而仅仅是拿到它的宽低等属性。
    • 而后将BitmapFactory.Options连同冀望的宽度和高度一起传递到到calculateInSampleSize办法中,就能够失去适合的inSampleSize值了。这一步会压缩图片。
    • 之后再解析一次图片,应用新获取到的inSampleSize值,并把inJustDecodeBounds设置为false,就能够失去压缩后的图片了。此时才正式创立了bitmap对象,因为后面曾经对它压缩了,所以你会发现此时所占内存大小曾经很少了。
  • 具体的实现代码

    public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId, 
            int reqWidth, int reqHeight) { 
        // 第一次解析将inJustDecodeBounds设置为true,来获取图片大小 
        final BitmapFactory.Options optiOns= new BitmapFactory.Options(); 
        options.inJustDecodeBounds = true; 
        BitmapFactory.decodeResource(res, resId, options); 
        // 调用下面定义的办法计算inSampleSize值 
        options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight); 
        // 应用获取到的inSampleSize值再次解析图片 
        options.inJustDecodeBounds = false; 
        return BitmapFactory.decodeResource(res, resId, options); 
    }
  • 思考:inJustDecodeBounds这个参数是干什么的?

    • 如果设置为true则示意decode函数不会生成bitmap对象,仅是将图像相干的参数填充到option对象里,这样咱们就能够在不生成bitmap而获取到图像的相干参数了。
  • 为何设置两次inJustDecodeBounds属性?

    • 第一次:设置为true则示意decode函数不会生成bitmap对象,仅是将图像相干的参数填充到option对象里,这样咱们就能够在不生成bitmap而获取到图像的相干参数。
    • 第二次:将inJustDecodeBounds设置为false再次调用decode函数时就能生成bitmap了。而此时的bitmap曾经压缩减小很多了,所以加载到内存中并不会导致OOM。

3.3 图片品质压缩

  • 在Android中,对图片进行品质压缩,通常咱们的实现形式如下所示:

    //quality 为0~100,0示意最小体积,100示意最高品质,对应体积也是最大
    bitmap.compress(Bitmap.CompressFormat.JPEG, quality , outputStream);
  • 在上述代码中,咱们抉择的压缩格局是CompressFormat.JPEG,除此之外还有两个抉择:

    • 其一,CompressFormat.PNG,PNG格局是无损的,它无奈再进行品质压缩,quality这个参数就没有作用了,会被疏忽,所以最初图片保留成的文件大小不会有变动;
    • 其二,CompressFormat.WEBP,这个格局是google推出的图片格式,它会比JPEG更加省空间,通过实测大略能够优化30%左右。
  • Android品质压缩逻辑,函数compress通过一连串的java层调用之后,最初来到了一个native函数:

    • 具体看:Bitmap.cpp,最初调用了函数encoder->encodeStream(…)编码保留本地。该函数是调用skia引擎来对图片进行编码压缩。

3.4 双线性采样压缩

  • 双线性采样(Bilinear Resampling)在 Android 中的应用形式个别有两种:

    bm = Bitmap.createScaledBitmap(bitmap, bitmap.getWidth()/2, bitmap.getHeight()/2, true);
    
    //或者间接应用 matrix 进行缩放
    Matrix matrix = new Matrix();
    matrix.setScale(0.5f, 0.5f);
    bm = Bitmap.createBitmap(bitmap, 0, 0, bit.getWidth(), bit.getHeight(), matrix, true);
  • 看源码能够晓得createScaledBitmap函数最终也是应用第二种形式的matrix进行缩放

    • 双线性采样应用的是双线性內插值算法,这个算法不像邻近点插值算法一样,间接粗犷的抉择一个像素,而是参考了源像素相应地位四周2×2个点的值,依据绝对地位取对应的权重,通过计算之后失去指标图像。

3.5 高清图分片加载

  • 实用场景 : 当一张图片十分大 , 在手机中只须要显示其中一部分内容 , BitmapRegionDecoder 十分有用 。
  • 次要作用 : BitmapRegionDecoder 能够从图像中 解码一个矩形区域 。相当于手在滑动的过程中,计算以后显示区域的图片绘制进去。
  • 根本应用流程 : 先创立,后解码 。调用 newInstance 办法 , 创立 BitmapRegionDecoder 对象 ;而后调用 decodeRegion 办法 , 获取指定 Rect 矩形区域的解码后的 Bitmap 对象

3.6 图片综合压缩

  • 个别状况下图片综合压缩的整体思路如下:

    • 第一步进行采样率压缩;
    • 第二步进行宽高的等比例压缩(微信对原图和缩略图限度了最大长宽或者最小长宽);
    • 第三步就是对图片的品质进行压缩(个别75或者70);
    • 第四步就是采纳webP的格局。
  • 对于图片压缩的综合案例如下

    • 具体能够参考:CompressServer

04.色调格局及内存优化

4.1 RGB色彩品种

  • RGB 色调模式是工业界的一种色彩规范

    • 通过对红(R)、绿(G)、蓝(B)三个色彩通道的变动以及它们相互之间的叠加来失去各式各样的色彩的,RGB即是代表红、绿、蓝三个通道的色彩,这个规范简直包含了人类视力所能感知的所有色彩,是使用最广的色彩零碎之一。Android 中,像素的存储形式应用的色调模式正是 RGB 色调模式。

4.2 ARGB色调模式

  • 在 Android 中,咱们常见的一些色彩设置,都是 RGB 色调模式来形容像素色彩的,并且他们都带有透明度通道,也就是所谓的 ARGB。例如,咱们常见的色彩定义如下:

    //在代码中定义色彩值:蓝色
    public final int blue=0xff0000ff;
    
    //或者在xml中定义:
    #ff0000ff  
  • 以上设置中,色彩值都是应用 16 进制的数字来示意的。以上色彩值都是带有透明度(通明通道)的色彩值,格局是 AARRGGBB,透明度、红色、绿色、蓝色四个色彩通道,各占有 2 位,也就是一个色彩通道,应用了 1 个字节来存储。

4.3 扭转色调格局优化

  • Android 中有多种 RGB 模式,咱们能够设置不同的格局,来管制图片像素色彩的显示品质和存储空间。
  • Android.graphics.Bitmap 类里有一个外部类 Bitmap.Config 类,它定义了能够在 Android 中应用的几种色调格局:

    public enum Config {
        ALPHA_8     (1),
        RGB_565     (3),
        @Deprecated
        ARGB_4444   (4),
        ARGB_8888   (5),
        RGBA_F16    (6),
        HARDWARE    (7);
    }
  • 解释一下这几个值别离代表了什么含意?咱们曾经晓得了:A 代表透明度、R 代表红色、G 代表绿色、B 代表蓝色。

    • ALPHA_8:示意,只存在 Alpha 通道,没有存储色调值,只含有透明度,每个像素占用 1 个字节的空间。
    • RGB_565:示意,R 占用 5 位二进制的地位,G 占用了6位,B 占用了 5 位。每个像素占用 2 个字节空间,并且不蕴含透明度。
    • ARGB_4444:示意,A(透明度)、R(红色)、G(绿色)、B(蓝色)4个通道各占用 4 个 bit 位。每个像素占用 2 个字节空间。
    • ARGB_8888:示意,A(透明度)、R(红色)、G(绿色)、B(蓝色)4个通道各占用 8 个 bit 位。每个像素占用 4 个字节空间。
    • RGBA_F16:示意,每个像素存储在8个字节上。此配置特地适宜广色域和HDR内容。
    • HARDWARE:非凡配置,当位图仅存储在图形内存中时。 此配置中的位图始终是不可变的。
  • 那么开发中个别抉择哪一种比拟适合呢

    • Android 中的图片在加载时,默认的色调格局是 ARGB_8888,也就是每个像素占用 4 个字节空间,一张 2700 1900 像素的照片,加载到内存就须要 19.6M 内存空间(2592 1936 * 4 bytes)。
    • 如果图片在 UI 组件中显示时,不须要太高的图片品质,例如显示一张缩略图(不通明图片)等场景,这时,咱们就没必要应用 ARGB_8888 的色调格局了,只须要应用 RGB_565 模式即可满足显示的须要。
    • 那么,咱们的优化操作就能够是:
    • 将 2700 1900 像素的原图,压缩到原图的低分辨率的缩略图 270 190 像素的图片,这时须要 0.2M 的内存。也就是从 19.6M内存,压缩为 0.2 M内存。
    • 咱们还能够进一步优化色调格局,由 ARGB_8888 改为 RGB_565 模式,这时,指标图片须要的内存就变为 270 190 2 = 0.1M 了。图片内存空间又减小了一倍。

05.缓存的应用实际优化

5.1 Lru内存缓存

  • LruCache 类特地适宜用来缓存 Bitmap,它应用一个强援用的 LinkedHashMap 保留最近援用的对象,并且在缓存超出设定大小时,删除最近起码应用的对象。
  • 给 LruCache 确定一个适合的缓存大小十分重要,咱们须要思考几个因素:

    • 利用残余多少可用内存?
    • 须要有多少张图片同时显示到屏幕上?有多少图片须要筹备好以便马上显示到屏幕?
    • 设施的屏幕大小和密度是多少?高密度的设施须要更大的缓存空间来缓存同样数量的图片。
    • Bitmap 的尺寸配置是多少,破费多少内存?
    • 图片被拜访的频率如何?如果其中一些比另外一些拜访更频繁,那么咱们可能心愿在内存中保留那些最常拜访的图片,或者依据拜访频率给 Bitmap 分组,为不同的 Bitmap 组设置多个 LruCache 对象。
    • 是否能够在缓存图片的品质和数量之间寻找平衡点?有时,保留大量低质量的 Bitmap 会十分有用,加载更高质量的图片的工作能够交给另外一个后盾线程解决。
    • 缓存太小会导致额定的花销却没有显著的益处,缓存太大同样会导致 java.lang.OutOfMemory 的异样,并且使得你的程序只留下小局部的内存用来工作(缓存占用太多内存,导致其余操作会因为内存不够而抛出异样)。所以,咱们须要剖析理论状况之后,提出一个适合的解决方案。
  • LruCache是Android提供的一个缓存类,通常使用于内存缓存

    • LruCache是一个泛型类,它的底层是用一个LinkedHashMap以强援用的形式存储外界的缓存对象来实现的。
    • 为什么应用LinkedHashMap来作为LruCache的存储,是因为LinkedHashMap有两种排序形式,一种是插入排序形式,一种是拜访排序形式,默认状况下是以拜访形式来存储缓存对象的;LruCache提供了get和put办法来实现缓存的获取和增加,当缓存满时,会将最近起码应用的对象移除掉,而后再增加新的缓存对象。如下源码所示,底层是LinkedHashMap。

      public LruCache(int maxSize) {
      if (maxSize <= 0) {
          throw new IllegalArgumentException("maxSize <= 0");
      }
      this.maxSize = maxSize;
      this.map = new LinkedHashMap(0, 0.75f, true);
      }
  • 在应用LruCache的时候,首先须要获取以后设施的内存容量,通常状况下会将总容量的八分之一作为LruCache的容量,而后重写LruCache的sizeof办法,sizeof办法用于计算缓存对象的大小,单位须要与调配的容量的单位统一;

    // 获取零碎最大缓存
    int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
    // set LruCache size;
    // 应用最大可用内存值的1/8作为缓存的大小
    int cacheSize = maxMemory / 8;
    LruCache memoryCache = new LruCache(cacheSize) {
        @Override
        protected int sizeOf(@NonNull String uri, @NonNull Bitmap bitmap) {
            // 重写此办法来掂量每张图片的大小,默认返回图片数量
            return bitmap.getRowBytes() * bitmap.getHeight() / 1024;
        }
    };
    //插入对象
    memoryCache.put(key, bitmap);
    //取出对象
    memoryCache.get(key);
  • 如何淘汰缓存

    • 这个就要看LinkedHashMap汇合的特点呢!LinkedHashMap 构造函数的第三个参数:accessOrder,传入true时, 元素会按拜访顺序排列,最初拜访的在遍历器最初端。在进行淘汰时,移除遍历器前端的元素,直至缓存总大小升高到指定大小以下。

5.2 Lru内存注意事项

  • 看一个实在的场景

    • 假如咱们的LruCache能够缓存80张,每次刷新从网络获取20张图片且不反复,那么在刷新第五次的时候,依据LruCache缓存的规定,第一次刷新的20张图片就会从LruCache中移出,处于期待被零碎GC的状态。如果咱们持续刷新n次,期待被回收的张数就会累积到 20 * n 张。
  • 会呈现什么问题

    • 会呈现大量的Bitmap内存碎片,咱们不晓得零碎什么时候会触发GC回收掉这些无用的Bitmap,对于内存是否会溢出,是否会频繁GC导致卡顿等未知问题。
  • 解决方案该怎么做?

    • 第一种:在3.0当前引入了 BitmapFactory.Options.inBitmap,如果设置此项,须要解码的图片就会尝试应用该Bitmap的内存,这样勾销了内存的动态分配,进步了性能,节俭了内存。
    • 第二种:把处于无用的状态的Bitmap放入SoftReference。SoftReference援用的对象会在内存溢出之前被回收。
    • 对于Lru缓存案例和代码能够参考:AppLruCache

5.3 应用Lru磁盘缓存

  • 内存缓存可能进步拜访最近用过的 Bitmap 的速度,然而咱们无奈保障最近拜访过的 Bitmap 都可能保留在缓存中。像相似 GridView 等须要大量数据填充的控件很容易就会用尽整个内存缓存。另外,咱们的利用可能会被相似打电话等行为而暂停并退到后盾,因为后盾利用可能会被杀死,那么内存缓存就会被销毁,外面的 Bitmap 也就不存在了。一旦用户复原利用的状态,那么利用就须要重新处理那些图片。
  • 磁盘缓存能够用来保留那些曾经解决过的 Bitmap,它还能够缩小那些不再内存缓存中的 Bitmap 的加载次数。当然从磁盘读取图片会比从内存要慢,而且因为磁盘读取操作工夫是不可预期的,读取操作须要在后盾线程中解决。
  • 留神:如果图片会被更频繁的拜访,应用 ContentProvider 或者会更加适合,比方在图库利用中。
  • 留神:因为初始化磁盘缓存波及到 I/O 操作,所以它不应该在主线程中进行。然而这也意味着在初始化实现之前缓存能够被拜访。为了解决这个问题,在下面的实现中,有一个锁对象(lock object)来确保在磁盘缓存实现初始化之前,利用无奈对它进行读取。
  • 内存缓存的查看是能够在 UI 线程中进行的,磁盘缓存的查看须要在后盾线程中解决。磁盘操作永远都不应该在 UI 线程中产生。当图片解决实现后,Bitmap 须要增加到内存缓存与磁盘缓存中,不便之后的应用。

06.不同版本对Bitmap治理

6.1 演变过程

  • Android 2.3.3 (API level 10)以及之前,

    • 一个 Bitmap 的像素数据是寄存在 Native 内存空间中的。这些数据与 Bitmap 对象自身是隔离的,Bitmap 自身被寄存在 Dalvik 堆中。并且无奈预测在 Native 内存中的像素级数据何时会被开释,这意味着程序容易超过它的内存限度并且解体。
  • Android 3.0 (API Level 11)开始

    • 像素数据则是与 Bitmap 自身一起寄存在 Dalvik 堆中。
  • Android 8.0(Android O)及之后的版本中

    • Bitmap 的像素数据的内存调配又回到了 Native 层,它是在 Native 堆空间进行调配的。

6.2 治理Bitmap内存

  • 治理 Android 2.3.3 及以下版本的内存应用

    • 在 Android 2.3.3 (API level 10) 以及更低版本上,举荐应用 recycle() 办法。 如果在利用中显示了大量的 Bitmap 数据,咱们很可能会遇到 OutOfMemoryError 的谬误。 recycle() 办法能够使得程序更快的开释内存。
  • 治理 Android 3.0 及其以上版本的内存

    • 从 Android 3.0 (API Level 11)开始,引进了 BitmapFactory.Options.inBitmap 字段。 如果应用了这个设置字段,decode 办法会在加载 Bitmap 数据的时候去重用曾经存在的 Bitmap。这意味着 Bitmap 的内存是被从新利用的,这样能够晋升性能,并且缩小了内存的调配与回收。然而,应用 inBitmap 有一些限度,特地是在Android 4.4 (API level 19)之前,只有等同大小的位图才能够被重用。
  • 治理 Android 8.0 及其以上版本的内存

    • 在 Android 8.0 及其以上版本,解决内存,也遵循 Android 3.0 以上版本同样的形式。同时,图片像素数据存储在 native 层,并且不占用 Java 堆的空间,这也代表着咱们领有更大的图片存储空间,能够加载品质更高、数据更多的图片到内存中。然而,内存仍然不是有限的,利用还是要受到手机内存的限度,所以肯定要留神这一点。

6.3 进步Bitmap复用

  • Android3.0之后,并没有强调Bitmap.recycle();而是强调Bitmap的复用。

    • 应用LruCache对Bitmap进行缓存,当再次应用到这个Bitmap的时候间接获取,而不必重走编码流程。
    • Android3.0(API 11之后)引入了BitmapFactory.Options.inBitmap字段,设置此字段之后解码办法会尝试复用一张存在的Bitmap。这意味着Bitmap的内存被复用,防止了内存的回收及申请过程,显然性能体现更佳。
    • 应用这个字段有几点限度:

      • 申明可被复用的Bitmap必须设置inMutable为true;
      • Android4.4(API 19)之前只有格局为jpg、png,等同宽高(要求刻薄),inSampleSize为1的Bitmap才能够复用;
      • Android4.4(API 19)之前被复用的Bitmap的inPreferredConfig会笼罩待分配内存的Bitmap设置的inPreferredConfig;
      • Android4.4(API 19)之后被复用的Bitmap的内存必须大于须要申请内存的Bitmap的内存;
      • Android4.4(API 19)之前待加载Bitmap的Options.inSampleSize必须明确指定为1。
  • Bitmap复用的试验,代码如下所示,而后看打印的日志信息

    • 从内存地址的打印能够看出,两个对象其实是一个对象,Bitmap复用胜利;
    • bitmapReuse占用的内存(4346880)正好是bitmap占用内存(1228800)的四分之一;
    • getByteCount()获取到的是以后图片该当所占内存大小,getAllocationByteCount()获取到的是被复用Bitmap实在占用内存大小。尽管bitmapReuse的内存只有4346880,然而因为是复用的bitmap的内存,因此其实在占用的内存大小是被复用的bitmap的内存大小(1228800)。这也是getAllocationByteCount()可能比getByteCount()大的起因。

      @RequiresApi(api = Build.VERSION_CODES.KITKAT)
      private void initBitmap() {
      BitmapFactory.Options optiOns= new BitmapFactory.Options();
      // 图片复用,这个属性必须设置;
      options.inMutable = true;
      // 手动设置缩放比例,使其取整数,不便计算、察看数据;
      options.inDensity = 320;
      options.inTargetDensity = 320;
      Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.bg_autumn_tree_min, options);
      // 对象内存地址;
      Log.i("ycBitmap", "bitmap = " + bitmap);
      Log.i("ycBitmap", "ByteCount = " + bitmap.getByteCount() + ":::bitmap:AllocatiOnByteCount= " + bitmap.getAllocationByteCount());
      // 应用inBitmap属性,这个属性必须设置;
      options.inBitmap = bitmap; options.inDensity = 320;
      // 设置缩放宽高为原始宽高一半;
      options.inTargetDensity = 160;
      options.inMutable = true;
      Bitmap bitmapReuse = BitmapFactory.decodeResource(getResources(), R.drawable.bg_kites_min, options);
      // 复用对象的内存地址;
      Log.i("ycBitmap", "bitmapReuse = " + bitmapReuse);
      Log.i("ycBitmap", "bitmap:ByteCount = " + bitmap.getByteCount() + ":::bitmap:AllocatiOnByteCount= " + bitmap.getAllocationByteCount());
      Log.i("ycBitmap", "bitmapReuse:ByteCount = " + bitmapReuse.getByteCount() + ":::bitmapReuse:AllocatiOnByteCount= " + bitmapReuse.getAllocationByteCount());
      
      //11-26 18:24:07.971 15470-15470/com.yc.ycbanner I/ycBitmap: bitmap = [email protected]
      //11-26 18:24:07.972 15470-15470/com.yc.ycbanner I/ycBitmap: bitmap:ByteCount = 4346880:::bitmap:AllocatiOnByteCount= 4346880
      //11-26 18:24:07.994 15470-15470/com.yc.ycbanner I/ycBitmap: bitmapReuse = [email protected]
      //11-26 18:24:07.994 15470-15470/com.yc.ycbanner I/ycBitmap: bitmap:ByteCount = 1228800:::bitmap:AllocatiOnByteCount= 4346880
      //11-26 18:24:07.994 15470-15470/com.yc.ycbanner I/ycBitmap: bitmapReuse:ByteCount = 1228800:::bitmapReuse:AllocatiOnByteCount= 4346880
      }

07.图片其余方面优化

7.1 缩小PNG图片的应用

  • 这里要介绍一种新的图片格式:Webp,它是由 Google 推出的一种既保留 png 格局的长处,又可能缩小图片大小的一种新型图片格式。
  • 在 Android 4.0(API level 14) 中反对有损的 WebP 图像,在 Android 4.3(API level 18) 和更高版本中反对无损和通明的 WebP 图像。
  • 留神一下,Webp格局图片仅仅只是缩小图片的品质大小,并不会缩小加载图片后的内存占用。

7.2 切割圆角优化

  • 计划1:间接采纳Canvas.clipPath 相干api,裁剪出一个圆角区域。

    • 该计划简略暴力,通用性强。如果只是一个动态的单图视图,该办法问题不大,但如果是简单页面,滚动的时候,测试就会跟你说,页面卡顿了,要优化。起因就是 Canvas.clip的相干api损耗绝对较大。
  • 计划2:零碎提供的CardView设置圆角

    • 把原来全工程各个视频控件和图片控件的外层,都加上一层CardView。革新老本大,布局层级更深一层,layout工夫加长。
  • 计划3:应用setXfermode法

    • 此种形式就是再new一个雷同尺寸的bitmap,而后应用paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));先画圆角矩形,再画原始bitmap,而后就失去了一个圆角的bitmap。晚期用得较多,占用bitmap双倍内存。
  • 计划4:图片加载库比方Glide,Fresco等

    • 在底层,无非也是应用下面的这两种种形式。晚期的应用setXfermode来实现,起初应用BitmapShader实现。应用简略,稳固。
  • 计划5:遮罩

    • 还是应用setXfermode,不过与办法一不同的是:不对图片作任何更改,只在圆角之外再画一层与背景色彩雷同的四个角来遮挡,在视觉上造成圆角图片的成果。
  • 那个切割圆角该怎么优化呢?

    • 应用计划3,能够采纳自定义view,反对LinearLayout、RelativeLayout、FrameLayout、ConstraintLayout、ImageView、TextView、View、Button等设置圆角。
    • 具体案例可见:RoundCorners

7.3 如何给图片置灰色

  • 大略的操作步骤。具体能够参考:PicCalculateUtils

    • 第一步:获取原始图片的宽高,而后创立一个bitmap可变位图对象。
    • 第二步:创立画板canvas对象,而后创立画笔paint。而后调用canvas.drawBitmap办法绘制图片
    • 第三步:对画笔进行润饰,设置画笔色彩属性,这里应用到了ColorMatrix,外围就是设置饱和度为0,即可绘制灰色内容

7.4 如何解决图片旋转呢

  • 在Android中应用ImageView显示图片的时候发现图片显示不正,方向偏了或者倒过去了。

    • 解决这个问题很天然想到的两步走,首先是要自动识别图像方向,计算旋转角度,而后对图像进行旋转并显示。
  • 辨认图像方向

    • 首先在这里提一个概念EXIF(Exchangeable Image File Format,可替换图像文件)。简而言之,Exif是一个规范,用于电子照相机(也包含手机、扫描器等)上,用来标准图片、声音、视屏以及它们的一些辅助标记格局。
    • Exif反对的格局如下:图像;压缩图像文件:JPEG、DCT;非压缩图像文件:TIFF;音频;RIFF、WAV
    • Android提供了对JPEG格局图像Exif接口反对,能够读取JPEG文件metadata信息,参见ExifInterface。这些Metadata信息总的来说大抵分为三类:日期工夫、空间信息(经纬度、高度)、Camera信息(孔径、焦距、旋转角、曝光量等等)。
  • 对于图像旋转

    • 获取了图片的旋转方向后,而后再设置图像旋转。最初Bitmap提供的动态createBitmap办法,能够对图片设置旋转角度。具体看:PicCalculateUtils

7.5 保留图片且刷相册

  • 大略的操作步骤如下所示。具体可看:ImageSaveUtils

    • 第一步:创立图片文件,而后将bitmap对象写到图片文件中
    • 第二步:通过MediaStore将图片插入到共享目录相册中
    • 第三步:发送告诉,告诉相册中刷新插入图片的数据。留神,获取图片资源uri刷新即可,防止刷新所有数据造成等待时间过长。

7.6 对立图片域名优化

  • 域名对立

    • 缩小了10%+的反复图片下载和内存耗费。同时缩小之前多域名图片加载时反复创立HTTPS申请的过程,缩小图片加载工夫。

7.7 优化H5图片加载

  • 通过拦挡WebView图片加载的形式,让原生图片库来下载图片之后传递图片二进制数据给WebView显示。
  • 采纳OkHttp拦挡资源缓存,上面是大略的思路。缓存的入口从shouldInterceptRequest登程

    • 第一步,拿到WebResourceRequest对象中申请资源的url还有header,如果开发者设置不缓存则返回null
    • 第二步,如果缓存,通过url判断拦挡资源的条件,过滤非http,音视频等资源,这个是可自在配置缓存内容比方css,png,jpg,xml,txt等
    • 第三步,判断本地是否有OkHttp缓存数据,如果有则间接读取本地资源,通过url找到对应的path门路,而后读取文件流,组装数据返回。
    • 第四步,如果没有缓存数据,创立OkHttp的Request申请,将资源网络申请交给okHttp来解决,并且用它自带的缓存性能,当然如果是申请失败或者异样则返回null,否则返回失常数据
  • 对于webView图片缓存的计划,能够间接参考:YCWebView

7.8 优化图片暗影成果

  • 暗影成果有哪些实现形式

    • 第一种:应用CardView,然而不能设置暗影色彩
    • 第二种:采纳shape叠加,存在前期UI成果不便优化
    • 第三种:UI切图
    • 第四种:自定义View
    • 第五种:自定义Drawable
  • 否定上背后两种计划起因剖析?

    • 第一个计划的CardView渐变色和暗影成果很难管制,只能反对线性或者环装模式突变,这种不满足需要,因为暗影自身是一个周围一层很淡的色彩突围,在一个矩形框的层面上色彩大略统一,而且这个CardView有很多局限性,比方不能批改暗影的色彩,不能批改暗影的深浅。所以这个思路无奈实现这个需要。
    • 第二个采纳shape叠加,能够实现暗影成果,然而影响UI,且暗影局部是占像素的,而且不灵便。
    • 第三个计划询问了一下ui。他们给出的后果是如果应用切图的话那标注的话很难标,身为一个优良的设计师大多对像素点都和敏感,界面上的像素点有一点不协调那都是无奈容忍的。
  • 网上一些介绍暗影成果计划

    • 所有在深奥的技术,也都是为需要做筹备的。也就是须要实际并且能够用到理论开发中,这篇文章不再形象介绍暗影成果原理,了解三维空间中如何解决偏移光线达到暗影视差等,网上看了一些文章也没看明确或者了解。这篇博客间接通过调用api实现预期的成果。
    • 多个drawable叠加,应用layer-list能够将多个drawable依照程序层叠在一起显示,默认状况下,所有的item中的drawable都会主动依据它附上view的大小而进行缩放,layer-list中的item是依照程序从下往上叠加的,即先定义的item在上面,前面的顺次往上面叠放
  • 暗影是否占位

    • 应用CardView暗影不占位,不能设置暗影色彩和成果
    • 应用shape暗影是能够设置暗影色彩,然而是占位的
  • 几种计划优缺点比照剖析

    • CardView 长处:自带性能实现简略 毛病:自带圆角不肯定可适配所有需要
    • layer(shape叠加) 长处:实现模式简略 毛病:成果个别
    • 自定义实现 长处:实现成果好可配置能力高 毛病:须要开发者自行开发
  • 对于解决暗影成果

    • 具体各种计划的比照能够参考这个demo:AppShadowLib

7.9 图片资源的压缩

  • 咱们利用中应用的图片,设计师出的原图通常都十分大,他们通常会应用工具,通过肯定的压缩,缩减到比拟小一些的大小。
  • 然而,这些图片通常都有肯定的可压缩空间,我在之前的我的项目中,对图片进行了二次压缩,整体压缩率达到了 40%~50% ,成果还是十分不错的。
  • 这里介绍下罕用的,图片压缩的办法:

    • 应用压缩工具对图片进行二次压缩。
    • 依据最终图片是否须要透明度展现,优先选择不通明的图片格式,例如,咱们应该防止应用 png 格局的图片。
    • 对于色调简略,例如,一些背景之类的图片,能够抉择应用布局文件来定义(矢量图),这样就会十分节俭内存了。
    • 如果蕴含透明度,优先应用 WebP 等格局图像。
  • 图片在上线前进行压缩解决,岂但能够缩小内存的应用,如果图片是网络获取的,也能够缩小网络加载的流量和工夫。

    • 举荐一个图片压缩网站:tinypng网站

推荐阅读
  • 本文讨论了在手机移动端如何使用HTML5和JavaScript实现视频上传并压缩视频质量,或者降低手机摄像头拍摄质量的问题。作者指出HTML5和JavaScript无法直接压缩视频,只能通过将视频传送到服务器端由后端进行压缩。对于控制相机拍摄质量,只有使用JAVA编写Android客户端才能实现压缩。此外,作者还解释了在交作业时使用zip格式压缩包导致CSS文件和图片音乐丢失的原因,并提供了解决方法。最后,作者还介绍了一个用于处理图片的类,可以实现图片剪裁处理和生成缩略图的功能。 ... [详细]
  • 本文详细介绍了SQL日志收缩的方法,包括截断日志和删除不需要的旧日志记录。通过备份日志和使用DBCC SHRINKFILE命令可以实现日志的收缩。同时,还介绍了截断日志的原理和注意事项,包括不能截断事务日志的活动部分和MinLSN的确定方法。通过本文的方法,可以有效减小逻辑日志的大小,提高数据库的性能。 ... [详细]
  • 本文介绍了Python高级网络编程及TCP/IP协议簇的OSI七层模型。首先简单介绍了七层模型的各层及其封装解封装过程。然后讨论了程序开发中涉及到的网络通信内容,主要包括TCP协议、UDP协议和IPV4协议。最后还介绍了socket编程、聊天socket实现、远程执行命令、上传文件、socketserver及其源码分析等相关内容。 ... [详细]
  • 本文介绍了在Python3中如何使用选择文件对话框的格式打开和保存图片的方法。通过使用tkinter库中的filedialog模块的asksaveasfilename和askopenfilename函数,可以方便地选择要打开或保存的图片文件,并进行相关操作。具体的代码示例和操作步骤也被提供。 ... [详细]
  • 基于layUI的图片上传前预览功能的2种实现方式
    本文介绍了基于layUI的图片上传前预览功能的两种实现方式:一种是使用blob+FileReader,另一种是使用layUI自带的参数。通过选择文件后点击文件名,在页面中间弹窗内预览图片。其中,layUI自带的参数实现了图片预览功能。该功能依赖于layUI的上传模块,并使用了blob和FileReader来读取本地文件并获取图像的base64编码。点击文件名时会执行See()函数。摘要长度为169字。 ... [详细]
  • 无损压缩算法专题——LZSS算法实现
    本文介绍了基于无损压缩算法专题的LZSS算法实现。通过Python和C两种语言的代码实现了对任意文件的压缩和解压功能。详细介绍了LZSS算法的原理和实现过程,以及代码中的注释。 ... [详细]
  • 也就是|小窗_卷积的特征提取与参数计算
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了卷积的特征提取与参数计算相关的知识,希望对你有一定的参考价值。Dense和Conv2D根本区别在于,Den ... [详细]
  • HTML学习02 图像标签的使用和属性
    本文介绍了HTML中图像标签的使用和属性,包括定义图像、定义图像地图、使用源属性和替换文本属性。同时提供了相关实例和注意事项,帮助读者更好地理解和应用图像标签。 ... [详细]
  • 本文介绍了在Windows环境下如何配置php+apache环境,包括下载php7和apache2.4、安装vc2015运行时环境、启动php7和apache2.4等步骤。希望对需要搭建php7环境的读者有一定的参考价值。摘要长度为169字。 ... [详细]
  • 本文总结了在开发中使用gulp时的一些技巧,包括如何使用gulp.dest自动创建目录、如何使用gulp.src复制具名路径的文件以及保留文件夹路径的方法等。同时介绍了使用base选项和通配符来保留文件夹路径的技巧,并提到了解决带文件夹的复制问题的方法,即使用gulp-flatten插件。 ... [详细]
  • 突破MIUI14限制,自定义胶囊图标、大图标样式,支持任意APP
    本文介绍了如何突破MIUI14的限制,实现自定义胶囊图标和大图标样式,并支持任意APP。需要一定的动手能力和主题设计师账号权限或者会主题pojie。详细步骤包括应用包名获取、素材制作和封包获取等。 ... [详细]
  • PDO MySQL
    PDOMySQL如果文章有成千上万篇,该怎样保存?数据保存有多种方式,比如单机文件、单机数据库(SQLite)、网络数据库(MySQL、MariaDB)等等。根据项目来选择,做We ... [详细]
  • 解决文件名过长下载失败问题的jQuery方案
    本文介绍了使用jQuery解决文件名过长导致下载失败的问题。原方案中存在文件名部分丢失的问题,通过动态生成隐藏域表单并提交的方式来解决。详细的解决方案和代码示例在文章中给出。 ... [详细]
  • 本文介绍了使用哈夫曼树实现文件压缩和解压的方法。首先对数据结构课程设计中的代码进行了分析,包括使用时间调用、常量定义和统计文件中各个字符时相关的结构体。然后讨论了哈夫曼树的实现原理和算法。最后介绍了文件压缩和解压的具体步骤,包括字符统计、构建哈夫曼树、生成编码表、编码和解码过程。通过实例演示了文件压缩和解压的效果。本文的内容对于理解哈夫曼树的实现原理和应用具有一定的参考价值。 ... [详细]
  • 本文介绍了Android中的assets目录和raw目录的共同点和区别,包括获取资源的方法、目录结构的限制以及列出资源的能力。同时,还解释了raw目录中资源文件生成的ID,并说明了这些目录的使用方法。 ... [详细]
author-avatar
愛攝影的新胖
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有