Android Studio App开发之利用图像解码器ImageDecoder播放GIF动图、Webp、HEIF图片(附源码 简单实用)

简介: Android Studio App开发之利用图像解码器ImageDecoder播放GIF动图、Webp、HEIF图片(附源码 简单实用)

需要源码和图片集请点赞关注收藏后评论区留言~~~

一、图像解码器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>

创作不易 觉得有帮助请 点赞关注收藏~~~

相关文章
|
23天前
|
Android开发 数据安全/隐私保护 开发者
Android自定义view之模仿登录界面文本输入框(华为云APP)
本文介绍了一款自定义输入框的实现,包含静态效果、hint值浮动动画及功能扩展。通过组合多个控件完成界面布局,使用TranslateAnimation与AlphaAnimation实现hint文字上下浮动效果,支持密码加密解密显示、去除键盘回车空格输入、光标定位等功能。代码基于Android平台,提供完整源码与attrs配置,方便复用与定制。希望对开发者有所帮助。
|
4月前
|
JavaScript 前端开发 Android开发
【03】仿站技术之python技术,看完学会再也不用去购买收费工具了-修改整体页面做好安卓下载发给客户-并且开始提交网站公安备案-作为APP下载落地页文娱产品一定要备案-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
【03】仿站技术之python技术,看完学会再也不用去购买收费工具了-修改整体页面做好安卓下载发给客户-并且开始提交网站公安备案-作为APP下载落地页文娱产品一定要备案-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
146 13
【03】仿站技术之python技术,看完学会再也不用去购买收费工具了-修改整体页面做好安卓下载发给客户-并且开始提交网站公安备案-作为APP下载落地页文娱产品一定要备案-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
|
16天前
|
安全 Java Android开发
为什么大厂要求安卓开发者掌握Kotlin和Jetpack?深度解析现代Android开发生态优雅草卓伊凡
为什么大厂要求安卓开发者掌握Kotlin和Jetpack?深度解析现代Android开发生态优雅草卓伊凡
43 0
为什么大厂要求安卓开发者掌握Kotlin和Jetpack?深度解析现代Android开发生态优雅草卓伊凡
|
23天前
|
XML 搜索推荐 Android开发
Android改变进度条控件progressbar的样式(根据源码修改)
本文介绍了如何基于Android源码自定义ProgressBar样式。首先分析了系统源码中ProgressBar样式的定义,发现其依赖一张旋转图片实现动画效果。接着分两步指导开发者实现自定义:1) 模仿源码创建一个旋转动画XML文件(放置在drawable文件夹),修改图片为自定义样式;2) 在UI控件中通过`indeterminateDrawable`属性应用该动画。最终实现简单且个性化的ProgressBar效果,附带效果图展示。
|
2月前
|
数据采集 JSON 网络安全
移动端数据抓取:Android App的TLS流量解密方案
本文介绍了一种通过TLS流量解密技术抓取知乎App热榜数据的方法。利用Charles Proxy解密HTTPS流量,分析App与服务器通信内容;结合Python Requests库模拟请求,配置特定请求头以绕过反爬机制。同时使用代理IP隐藏真实IP地址,确保抓取稳定。最终成功提取热榜标题、内容简介、链接等信息,为分析热点话题和用户趋势提供数据支持。此方法也可应用于其他Android App的数据采集,但需注意选择可靠的代理服务。
113 11
移动端数据抓取:Android App的TLS流量解密方案
|
3月前
|
JavaScript Linux 网络安全
Termux安卓终端美化与开发实战:从下载到插件优化,小白也能玩转Linux
Termux是一款安卓平台上的开源终端模拟器,支持apt包管理、SSH连接及Python/Node.js/C++开发环境搭建,被誉为“手机上的Linux系统”。其特点包括零ROOT权限、跨平台开发和强大扩展性。本文详细介绍其安装准备、基础与高级环境配置、必备插件推荐、常见问题解决方法以及延伸学习资源,帮助用户充分利用Termux进行开发与学习。适用于Android 7+设备,原创内容转载请注明来源。
572 76
|
2月前
|
NoSQL 应用服务中间件 PHP
布谷一对一直播源码android版环境配置流程及功能明细
部署需基于 CentOS 7.9 系统,硬盘不低于 40G,使用宝塔面板安装环境,包括 PHP 7.3(含 Redis、Fileinfo 扩展)、Nginx、MySQL 5.6、Redis 和最新 Composer。Swoole 扩展需按步骤配置。2021.08.05 后部署需将站点目录设为 public 并用 ThinkPHP 伪静态。开发环境建议 Windows 操作系统与最新 Android Studio,基础配置涉及 APP 名称修改、接口域名更换、包名调整及第三方登录分享(如 QQ、微信)的配置,同时需完成阿里云与腾讯云相关设置。
|
4月前
|
JavaScript 搜索推荐 Android开发
【01】仿站技术之python技术,看完学会再也不用去购买收费工具了-用python扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-客户的麻将软件需要下载落地页并且要做搜索引擎推广-本文用python语言快速开发爬取落地页下载-优雅草卓伊凡
【01】仿站技术之python技术,看完学会再也不用去购买收费工具了-用python扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-客户的麻将软件需要下载落地页并且要做搜索引擎推广-本文用python语言快速开发爬取落地页下载-优雅草卓伊凡
121 8
【01】仿站技术之python技术,看完学会再也不用去购买收费工具了-用python扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-客户的麻将软件需要下载落地页并且要做搜索引擎推广-本文用python语言快速开发爬取落地页下载-优雅草卓伊凡
|
4月前
|
数据采集 JavaScript Android开发
【02】仿站技术之python技术,看完学会再也不用去购买收费工具了-本次找了小影-感觉页面很好看-本次是爬取vue需要用到Puppeteer库用node.js扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
【02】仿站技术之python技术,看完学会再也不用去购买收费工具了-本次找了小影-感觉页面很好看-本次是爬取vue需要用到Puppeteer库用node.js扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
138 7
【02】仿站技术之python技术,看完学会再也不用去购买收费工具了-本次找了小影-感觉页面很好看-本次是爬取vue需要用到Puppeteer库用node.js扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
|
4月前
|
安全 Android开发 iOS开发
escrcpy:【技术党必看】Android开发,Escrcpy 让你无线投屏新体验!图形界面掌控 Android,30-120fps 超流畅!🔥
escrcpy 是一款基于 Scrcpy 的开源项目,使用 Electron 构建,提供图形化界面来显示和控制 Android 设备。它支持 USB 和 Wi-Fi 连接,帧率可达 30-120fps,延迟低至 35-70ms,启动迅速且画质清晰。escrcpy 拥有丰富的功能,包括自动化任务、多设备管理、反向网络共享、批量操作等,无需注册账号或广告干扰。适用于游戏直播、办公协作和教育演示等多种场景,是一款轻量级、高性能的 Android 控制工具。
208 1