一、Android图片资源
在Android中,图片资源通常放置在res/drawable目录下。图片资源存储在图片文件中,通常是在JPEG、PNG、GIF或者WebP格式中,这些图片文件的大小和分辨率都可能不一样,而Android设备中的屏幕分辨率也千差万别,这就会导致在不同屏幕上显示同样的图片可能会出现拉伸或压缩的变形情况。
我们需要一种能够针对不同分辨率屏幕的图片缩放方案,来提高用户体验并优化图片显示。
二、Android自带的图片缩放方案
Android提供了一种自动适应不同分辨率的图片适配方案,即为屏幕密度无关的单位dp。在res/drawable目录下建立相同资源文件名的子目录,并在子目录下存放对应dpi的图片,例如:
res/ drawable-mdpi/ icon.png drawable-hdpi/ icon.png drawable-xhdpi/ icon.png drawable-xxhdpi/ icon.png drawable-xxxhdpi/ icon.png
以上五个子目录中的icon.png分别适用于不同的屏幕密度,其中:ldpi密度下不推荐使用。
当Android系统做图片适配时,会去相应的dpi目录下查找对应分辨率的图片,找到后自动按照设备的dpi进行缩放并显示。
三、第三方库Universal Image Loader
虽然Android自带的图片适配方案能够适用于大多数情况,但是在某些场景下还是需要更灵活的图片缩放方案来提高用户体验。比如,在列表中加载大量图片时,每次加载图片都需要重新拉伸或者压缩,这样极大地降低了用户体验。
在这种情况下,我们可以使用Universal Image Loader库来进行图片缓存和异步加载,可以大幅度提高图片的显示效率,改善用户体验。
下面是Universal Image Loader的使用示例:
// 创建DisplayImageOptions对象并进行相关的配置 DisplayImageOptions options = new DisplayImageOptions.Builder() .cacheInMemory(true) // 开启内存缓存 .cacheOnDisk(true) // 开启硬盘缓存 .considerExifParams(true) // 考虑EXIF信息 .bitmapConfig(Bitmap.Config.RGB_565) // 设置图片的解码类型 .imageScaleType(ImageScaleType.IN_SAMPLE_INT) // 缩放类型 .build(); // 创建ImageLoader对象并进行相关配置 ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(context) .defaultDisplayImageOptions(options) // 设置默认的DisplayImageOptions对象 .threadPriority(Thread.NORM_PRIORITY - 2) // 线程优先级 .denyCacheImageMultipleSizesInMemory() // 禁止缓存多个尺寸图片在内存中 .diskCacheFileNameGenerator(new Md5FileNameGenerator()) // 硬盘缓存文件名生成器 .tasksProcessingOrder(QueueProcessingType.LIFO) // 图片加载任务顺序 .writeDebugLogs() // 调试输出选项 .build(); // 初始化ImageLoader并进行相关操作 ImageLoader.getInstance().init(config); // 初始化 // 加载图片 ImageView imageView = (ImageView) convertView.findViewById(R.id.image_view); String imageUrl = "http://www.example.com/image.png"; ImageLoader.getInstance().displayImage(imageUrl, imageView);
以上代码中,创建DisplayImageOptions对象用于配置图片显示参数,其中设置了开启内存和硬盘缓存、考虑EXIF信息、设置图片的解码类型和缩放类型等。
通过创建ImageLoaderConfiguration对象并进行各种配置,最后使用ImageLoader.getInstance()来初始化ImageLoader,然后再通过displayImage()方法进行图片加载和显示。
四、Android自带的图片压缩方式
在一些特定的场景下,我们需要在程序中对图片进行压缩处理以节省内存空间,并提高程序运行的稳定性。Android提供了两种方式对图片进行压缩处理:
第一种是使用BitmapFactory.Options的inSampleSize参数来为Bitmap对象指定一个整数缩放值,例如:
// 加载图片的选项设置 BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; BitmapFactory.decodeFile(path, options); // 计算图片的缩放比例 int width = options.outWidth; int height = options.outHeight; float maxWidth = 1024f; float maxHeight = 1024f; float scale = Math.min(maxWidth / width, maxHeight / height); int inSampleSize = Math.round(1 / scale); // 设置图片加载选项的缩放比例 options.inJustDecodeBounds = false; options.inSampleSize = inSampleSize; // 加载原始的Bitmap并进行压缩 Bitmap originBitmap = BitmapFactory.decodeFile(path, options); Bitmap compressedBitmap = Bitmap.createScaledBitmap(originBitmap, (int) (width * scale), (int) (height * scale), true); // 回收Bitmap对象并将其置为null originBitmap.recycle(); originBitmap = null; // 显示压缩后的Bitmap imageView.setImageBitmap(compressedBitmap);
以上代码中,首先设置Bitmap加载选项的inJustDecodeBounds属性为true,这会告诉BitmapFactory.decodeFile()方法只解析图片的原始数据并不将其加载到内存中。接着计算图片的缩放比例,并设置图片加载选项的inJustDecodeBounds属性为false以加载图片,然后对原始Bitmap进行压缩并回收原始的Bitmap对象。
第二种压缩方式是使用Bitmap.compress()方法将原始Bitmap对象压缩成JPEG或PNG格式存储,代码示例如下:
Bitmap originBitmap = BitmapFactory.decodeFile(path); ByteArrayOutputStream baos = new ByteArrayOutputStream(); originBitmap.compress(Bitmap.CompressFormat.JPEG, 80, baos); byte[] bitmapBytes = baos.toByteArray(); Bitmap compressedBitmap = BitmapFactory.decodeByteArray(bitmapBytes, 0, bitmapBytes.length, null); // 回收Bitmap对象并将其置为null originBitmap.recycle(); originBitmap = null; // 显示压缩后的Bitmap imageView.setImageBitmap(compressedBitmap);
以上代码中,首先使用BitmapFactory.decodeFile()方法加载原始的Bitmap对象,然后将其压缩为JPEG格式的图像,并使用ByteArrayOutputStream将其以字节数组的形式返回。接着使用BitmapFactory.decodeByteArray()方法将字节数组解码成Bitmap对象并显示在ImageView中。