Android异步加载全解析之大图处理

Android异步加载全解析之大图处理

异步加载中非常重要的一部分就是对图像的处理,这也是我们前面用异步加载图像做演示例子的原因。一方面是因为图像处理不好的话会非常占内存,而且容易OOM,另一方面,图像也比文字要大,加载比较慢。所以,在讲解了如何进行多线程、AsyncTask进行多线程加载后,先暂停下后面的学习,来对图像的异步处理进行一些优化工作。

为什么要对图像处理

为什么要对图像进行处理,这是一个很直接的问题,一张图像,不管你拿手机、相机、单反还是什么玩意拍出来,它就有一定的大小,但是在不同的终端上,终端也有不同的大小,比如一张超高请无码大图,10M大小,在网页中看着挺爽,全高清,毛孔都看得清。同样一张图片,如果放在4.7寸的手机上,当然,同样还是一张高清无码大图,但这张图片10M,在电脑上可能不算什么,但在手机上,已经是非常大了,而这张图片在手机上,你拼命看,也就是那样,即使分辨率减少一半,你看上去也还是差不多。这就像所谓的视网膜屏、2k屏、4k屏,其实已经基本达到视觉分析的极限了,普通情况下,差别并不大。

但是,虽然你看着区别不大,但对系统来说,差别就非常大了,手机的内存,要像使用你藏的私房钱一样,每一分都要三思而用。所以,我们在下载高分辨率的图片的时候,可以对图像进行压缩,显示上虽然没有太大区别,但是却帮系统节省了大量的私房钱。

BitmapFactory之inSampleSize

BitmapFactory是Android中提供的对图像的解析方法,通过它的一些静态方法,我们可以对图像进行解析,例如从文件中解析——decodeFile;从资源中解析——decodeResource;从网络中解析——decodeStream等等。

当我们从网络上进行图像下载的时候,看情况,是否需要对图像进行压缩,那么如何在系统不加载图像到内存之前,就获取图像的大小等参数呢?看上去非常矛盾,但系统给我们提供了一种简单的解决方法。

BitmapFactory提供了BitmapFactory.Options参数,这个参数有一个inJustDecodeBounds属性,当这个属性为true的时候,我们就可以禁止系统加载图像到内存,但是!!!这时候,Options参数中的图像宽高、类型等属性已经被赋值了,这样,我们就实现了空手套白狼,哦,不对,是不使用内存就获取图像的属性。

BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(getResources(), R.id.myimage, options);
// 获取属性值
int imageHeight = options.outHeight;
int imageWidth = options.outWidth;
String imageType = options.outMimeType;

在获得了图像的参数之后,我们就可以对图像进行相应的处理了,例如我们显示图像的ImageView只有200 X 200 像素,而我们的图片有800 X 800 像素,那你把这么大的一张图放到这么小的ImageView中,有啥用呢?白白浪费了内存。OK,那么下面我们就来对图像进行压缩,Options参数中给我们提供了这样一个属性——inSampleSize,这个属性可以设置图像的缩放比例,例如一张1000 X 1000像素的图像,设置inSampleSize为5,意思就是把这个图像缩放到了五分之一,即200 X 200 。OK,下面我们就通过这样一个方法来对图像进行优化,首先,我们需要创建一个方法来获取到一个合适的inSampleSize:

/**
 * 获取合适的inSampleSize
 * @param options
 * @param targetWidth 期望Width
 * @param targetHeight 期望Height
 * @return
 */
public static int getInSampleSize(BitmapFactory.Options options,
                                        int targetWidth, int targetHeight) {
    // 原始图片的高度和宽度
    final int height = options.outHeight;
    final int width = options.outWidth;
    int inSampleSize = 1;
    if (height > targetHeight || width > targetWidth) {
        // 计算出实际宽高和目标宽高的比率
        final int heightRate = Math.round((float) height / (float) targetHeight);
        final int widthRate = Math.round((float) width / (float) targetWidth);
        inSampleSize = heightRate < widthRate ? heightRate : widthRate;
    }
    return inSampleSize;
}

方法非常简单,就是通过期望长宽来获取缩放的比例。下面我们就创建一个方法来获取缩放后的图像,这里为了演示,我们只创建从资源文件中获取图像的方法:

/**
 * 使用targetWidth、targetHeight来获取合适的inSampleSize
 * 并使用inSampleSize来缩放得到合适大小的图像
 * @param res getResources()
 * @param resId id
 * @param targetWidth
 * @param targetHeight
 * @return
 */
public static Bitmap decodeSuitableBitmap(Resources res, int resId,
                                          int targetWidth, int targetHeight) {
    // 空手套白狼
    final BitmapFactory.Options options = new BitmapFactory.Options();
    options.inJustDecodeBounds = true;
    BitmapFactory.decodeResource(res, resId, options);
    // 计算合适的inSampleSize
    options.inSampleSize = getInSampleSize(options, targetWidth, targetHeight);
    // 加载到内存
    options.inJustDecodeBounds = false;
    return BitmapFactory.decodeResource(res, resId, options);
}

通过调用decodeSuitableBitmap这样一个方法,我们就可以非常简单的将图像进行压缩。

我的Github 我的视频 慕课网

时间: 2024-10-13 16:21:45

Android异步加载全解析之大图处理的相关文章

Android异步加载全解析之Bitmap

Android异步加载全解析之Bitmap 在这篇文章中,我们分析了Android在对大图处理时的一些策略--Android异步加载全解析之大图处理  戳我戳我 那么在这篇中,我们来对图像--Bitmap进行一个更加细致的分析,掌握Bitmap的点点滴滴. 引入 Bitmap这玩意儿号称Android App头号杀手,特别是3.0之前的版本,简直就是皇帝般的存在,碰不得.摔不得.虽然后面的版本Android对Bitmap的管理也进行了一系列的优化,但是它依然是非常难处理的一个东西.在Androi

Android异步加载全解析之引入一级缓存

Android异步加载全解析之引入缓存 为啥要缓存 通过对图像的缩放,我们做到了对大图的异步加载优化,但是现在的App不仅是高清大图,更是高清多图,动不动就是图文混排,以图代文,如果这些图片都加载到内存中,必定会OOM.因此,在用户浏览完图像后,应当立即将这些废弃的图像回收,但是,这又带来了另一个问题,也就是当用户在浏览完一次图片后,如果还要返回去再进行重新浏览,那么这些回收掉的图像又要重新进行加载,保不准就要那些无聊到蛋疼的人在那一边看你回收GC,一边看你重新加载.这两件事情,肯定是互相矛盾的

Android异步加载全解析之使用多线程

异步加载之使用多线程 初次尝试 异步.异步,其实说白了就是多任务处理,也就是多线程执行,多线程那就会有各种问题,我们一步步来看,首先,我们创建一个class--ImageLoaderWithoutCaches,从命名上,大家也看出来,这个类,我们实现的是不带缓存的图像加载,不多说,我们再创建一个方法--showImageByThread,通过多线程来加载图像: /** * Using Thread * @param imageView * @param url */ public void sh

Android异步加载全解析之使用AsyncTask

Android异步加载全解析之使用AsyncTask 概述 既然前面提到了多线程,就不得不提到线程池,通过线程池,不仅可以对并发线程进行管理,更可以提高他们执行的效率,优化整个App.当然我们可以自己创建一个线程池,不过这样是很烦的,要创建一个高效的线程池还是挺费事的,不过,Android系统给我吗提供了AsyncTask这样一个类,来帮助我们快速实现多线程开发,它的底层实现,其实就是一个线程池. AsyncTask初探 AsyncTask,顾名思义就是用来做异步处理的.通过AsyncTask,

Android异步加载全解析之IntentService

Android异步加载全解析之IntentService 搞什么IntentService 前面我们说了那么多,异步处理都使用钦定的AsyncTask,再不济也使用的Thread,那么这个IntentService是个什么鬼. 相对与前面我们提到的这两种异步加载的方式来说,IntentService有一个最大的特点,就是--IntentService不受大部分UI生命周期的影响,它为后台线程提供了一个更直接的操作方式.不过,IntentService的不足主要体现在以下几点: 不可以直接和UI做

Android异步加载全解析之开篇瞎扯淡

Android异步加载 概述 Android异步加载在Android中使用的非常广泛,除了是因为避免在主线程中做网络操作,更是为了避免在显示时由于时间太长而造成ANR,增加显示的流畅性,特别是像ListView.GridView这样的控件,如果getView的时间太长,就会造成非常严重的卡顿,非常影响性能. 本系列将展示在Android中如何进行异步加载操作,并使用ListView来作为演示的对象. 如何下载图像 下载自然是需要使用网络,使用网络就不能在主线程,在主线程就会爆炸.所以我们必须要在

Android引入高速缓存的异步加载全分辨率

Android引进高速缓存的异步加载全分辨率 为什么要缓存 通过图像缩放,我们这样做是对的异步加载优化的大图,但现在的App这不仅是一款高清大图.图.动不动就是图文混排.以图代文,假设这些图片都载入到内存中.必然会OOM.因此,在用户浏览完图像后.应当马上将这些废弃的图像回收,可是.这又带来了另一个问题.也就是当用户在浏览完一次图片后,假设还要返回去再进行又一次浏览,那么这些回收掉的图像又要又一次进行载入,保不准就要那些无聊到蛋疼的人在那一边看你回收GC.一边看你又一次载入.这两件事情,肯定是互

Android异步加载

Android异步加载 一.为什么要使用异步加载? 1.Android是单线程模型 2.耗时操作阻碍UI线程 二.异步加载最常用的两种方式 1.多线程.线程池 2.AsyncTask 三.实现ListView图文混排 3-1 实现读取网页中的json数据到ListView中 (图片首先为默认图片) 3.1.1:主布局只有一个ListView和一个listView_item的布局 3.1.2:网页json数据的链接(http://www.imooc.com/api/teacher?type=4&n

Android异步加载访问网络图片-解析json

来自:http://www.imooc.com/video/7871 推荐大家去学习这个视频,讲解的很不错. 慕课网提供了一个json网址可以用来学习:http://www.imooc.com/api/teacher?type=4&num=30.我们的任务就是建立一个listview,将json提供的一些参数,主要是name,picSmall,description显示出来,效果图如下:  主要思路如下:listview中图片的加载,程序中使用了两种方式,一种是使用Thread类,一种是使用As