一、图像解码器ImageDecoder
早期的Android只支持3种图像格式,分别是JPEG,PNG,GIF 虽然这三类图片都能在ImageView上显示,但对于GIF格式图来说,图像视图仅仅能显示动图的初始画面,无法直接播放动画效果,并且随着图片大小 越来越大,使得手机存储空间越发吃紧,这也要求更高效的压缩算法
目前智能手机行业仅剩安卓和IOS两大阵营,两大阵营纷纷推出新的图像压缩算法,安卓推出了WebP格式,IOS推出了HEIF格式,它们都具备以下的优异特性
1:支持透明背景 JPEG不支持
2:支持动画效果 JPEG和PNG不支持动画效果
3:支持有损压缩 PNG和GIF不支持有损压缩 因为它们图片体积偏大
利用图像解码器加载并显示图片的步骤分为以下三步
1:调用ImageDecoder的createSource方法 从指定地方获得数据源
2:调用ImageDecoder的decodeDrawable方法 从数据源解码得到Drawable类型的图形信息
3:调用图像视图的setImageDrawable方法 设置图像视图的图形对象
ImageDecoder相比于传统方式主要有以下两个优点
1:调用带两个参数的decodeDrawable方法,此时输入第二个监听器参数,在监听器种可以获得图像的媒体类型,以及该图像是否为动图
2:判断解码得到的图形对象是否为Animatable类型,如果是的话,就调用start方法播放动画
效果如下 动图的播放动画已上传至我的个人主页 可前往观看~~~
代码如下
Java类
package com.example.chapter13;
import androidx.appcompat.app.AppCompatActivity;
import android.annotation.TargetApi;
import android.graphics.ImageDecoder;
import android.graphics.ImageDecoder.OnHeaderDecodedListener;
import android.graphics.drawable.Animatable;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.Spinner;
import android.widget.TextView;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
@TargetApi(Build.VERSION_CODES.P)
public class ImageSpecialActivity extends AppCompatActivity {
private TextView tv_info; // 声明一个文本视图对象
private ImageView iv_pic; // 声明一个图像视图对象
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_image_special);
tv_info = findViewById(R.id.tv_info);
iv_pic = findViewById(R.id.iv_pic);
initTypeSpinner(); // 初始化图像类型下拉框
}
// 初始化图像类型下拉框
private void initTypeSpinner() {
ArrayAdapter<String> typeAdapter = new ArrayAdapter<String>(this,
R.layout.item_select, typeArray);
Spinner sp_type = findViewById(R.id.sp_type);
sp_type.setPrompt("请选择图像类型");
sp_type.setAdapter(typeAdapter);
sp_type.setOnItemSelectedListener(new ImageSpecialActivity.ImageTypeListener());
sp_type.setSelection(0);
}
private String[] typeArray = {"直接显示GIF", "直接显示WebP", "显示GIF动图", "显示WebP动图", "显示HEIF图片"};
class ImageTypeListener implements AdapterView.OnItemSelectedListener {
public void onItemSelected(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
if (arg2 == 0) {
tv_info.setText("");
iv_pic.setImageResource(R.drawable.happy);
} else if (arg2 == 1) {
tv_info.setText("");
iv_pic.setImageResource(R.drawable.world_cup_2014);
} else if (arg2 == 2) {
showImage(R.drawable.happy); // 显示gif和webp图片
} else if (arg2 == 3) {
showImage(R.drawable.world_cup_2014); // 显示gif和webp图片
} else if (arg2 == 4) {
showHeic(R.raw.lotus); // 显示Heif图片(扩展名为heif或者heic)
}
}
public void onNothingSelected(AdapterView<?> arg0) {}
}
// 显示Heif图片(扩展名为heif或者heic)
private void showHeic(int imageId) {
try (InputStream is = getResources().openRawResource(imageId)) { // 从资源文件中获取输入流对象
byte[] bytes = new byte[is.available()]; // 创建临时存放的字节数组
is.read(bytes); // 从输入流中读取字节数组
// 利用Android 9.0新增的ImageDecoder读取图片
ImageDecoder.Source source = ImageDecoder.createSource(ByteBuffer.wrap(bytes));
showImageSource(source); // 显示指定来源的图像
} catch (Exception e) {
e.printStackTrace();
}
}
// 显示gif和webp图片
private void showImage(int imageId) {
try {
// 利用Android 9.0新增的ImageDecoder读取图片
ImageDecoder.Source source = ImageDecoder.createSource(getResources(), imageId);
showImageSource(source); // 显示指定来源的图像
} catch (Exception e) {
e.printStackTrace();
}
}
// 显示指定来源的图像
private void showImageSource(ImageDecoder.Source source) throws IOException {
// 从数据源解码得到图形信息
Drawable drawable = ImageDecoder.decodeDrawable(source, new OnHeaderDecodedListener() {
@Override
public void onHeaderDecoded(ImageDecoder decoder, ImageDecoder.ImageInfo info, ImageDecoder.Source source) {
// 获取图像信息的媒体类型与是否动图
String desc = String.format("该图片类型为%s,它%s动图",
info.getMimeType(), info.isAnimated()?"是":"不是");
tv_info.setText(desc);
}
});
iv_pic.setImageDrawable(drawable); // 设置图像视图的图形对象
if (drawable instanceof Animatable) { // 如果是动画图形,则开始播放动画
((Animatable) iv_pic.getDrawable()).start();
}
}
}
解码器类
package com.example.chapter13;
import androidx.appcompat.app.AppCompatActivity;
import android.annotation.TargetApi;
import android.content.Intent;
import android.graphics.ImageDecoder;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.view.View;
import android.widget.ImageView;
@TargetApi(Build.VERSION_CODES.P)
public class ImageDecoderActivity extends AppCompatActivity implements View.OnClickListener {
private final static String TAG = "ImageDecoderActivity";
private ImageView iv_photo; // 声明一个图像视图对象
private int CHOOSE_CODE = 3; // 选择照片的请求码
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_image_decoder);
iv_photo = findViewById(R.id.iv_photo);
findViewById(R.id.btn_choose).setOnClickListener(this);
}
@Override
public void onClick(View v) {
if (v.getId() == R.id.btn_choose) {
// 创建一个内容获取动作的意图(准备跳到系统相册)
Intent albumIntent = new Intent(Intent.ACTION_GET_CONTENT);
albumIntent.setType("image/*"); // 设置内容类型为图像
startActivityForResult(albumIntent, CHOOSE_CODE); // 打开系统相册
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
super.onActivityResult(requestCode, resultCode, intent);
if (resultCode == RESULT_OK && requestCode == CHOOSE_CODE) {
if (intent.getData() != null) { // 从相册选择一张照片
Uri imageUri = intent.getData();
showDecodedImage(imageUri); // 显示解码后的图像
}
}
}
// 显示解码后的图像
private void showDecodedImage(Uri imageUri) {
try {
// 利用Android 9.0新增的ImageDecoder读取图片
ImageDecoder.Source source = ImageDecoder.createSource(getContentResolver(), imageUri);
// 从数据源解码得到图形信息
Drawable drawable = ImageDecoder.decodeDrawable(source);
iv_photo.setImageDrawable(drawable); // 设置图像视图的图形对象
} catch (Exception e) {
e.printStackTrace();
}
}
}
XML文件
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="40dp"
android:orientation="horizontal"
android:layout_marginLeft="5dp" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="图像类型:"
android:textColor="@color/black"
android:textSize="17sp" />
<Spinner
android:id="@+id/sp_type"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:spinnerMode="dialog" />
</LinearLayout>
<TextView
android:id="@+id/tv_info"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="5dp"
android:textColor="#000000"
android:textSize="17sp"/>
<ImageView
android:id="@+id/iv_pic"
android:layout_width="match_parent"
android:layout_height="250dp"
android:scaleType="fitCenter" />
</LinearLayout>