Android Webp 完全解析 快来缩小apk的大小吧(1),面试被吊打

先自我介绍一下,小编浙江大学毕业,去过华为、字节跳动等大厂,目前阿里P7

深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年最新Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。
img
img
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以添加V获取:vip204888 (备注Android)
img

正文

这是一个完全不透明图的测试

Bitmap bitmap = BitmapFactory.decodeStream(getAssets().open(“icon.webp”));

imageView.setImageBitmap(bitmap);

找了台4.0.4(API15)的三星手机(ps:实在是找不到4.0的手机了),运行感觉还不错哟~

正在窃喜的时候,我又换了张图片,因为有些时候我们的图部分区域是透明了,于是我找了张图片,转化为webp,按照上述的代码,同样的操作,运行完成后,发现,整个图都显示不出来了

赶紧找了个4.2.2(API17)的手机,显示正常。

于是看一眼文档:

文档上对webp decode和encode的支持,是这样写的:

decode / encode

(Android 4.0+)

(Lossless, Transparency, Android 4.2.1+)

https://developer.android.com/guide/appendix/media-formats.html

那么结合文档和实验,大致可以有如下的结论:

  • 4.2.1+ 对于webp的decode、encode是完全支持的(包含半透明的webp图)

  • 对于4.0+ 到 4.2.1 ,只支持完全不透明的decode、encode的webp图

  • 4.0 以下,应该是默认不支持webp了

看到这个结论,那么就是大家的产品最低的支持版本了。

4.2.1起步的话,目前来看,我是不能接受的,所以只有引入so来做低版本兼容了。

(2)兼容so的获取

好在官方已经提供了相关webp支持的源码了,点击下载:

如果你的ndk的知识足够的话,可以自己利用源码,去生成so文件使用。

当然了,你也可以使用前人已经封装好的库:

我们这里选择使用第二个库,这里选择copy它生成的so文件以及辅助类到项目中,你也可以根据其readme打包一个aar出来使用。

首先下载下来webp-android,然后切换到webp-android/src/main/jni,执行ndk-build

然后等待执行结束,可以在其/webp-android/src/main/libs目录下copy出你需要的so,如果需要其他cpu架构的so,可以自己修改Application.mk文件。

/webp-android/src/main/libs

.

├── armeabi

│ └── libwebp_evme.so

├── armeabi-v7a

│ └── libwebp_evme.so

└── x86

└── libwebp_evme.so

然后将其WebDecoder的辅助类copy到项目中即可,注意保持原有包名。

ok,然后就可以用它提供的decode的方法了:

WebPDecoder.getInstance().decodeWebP(byte[] encoded)

于是,上述以InputStream为webp图片源的代码可以改写为:

大致的示例代码

InputStream is = getAssets().open(“weixin.webp”);

Bitmap bitmap = null;

if (Build.VERSION.SDK_INT > Build.VERSION_CODES.JELLY_BEAN) {

bitmap = WebPDecoder.getInstance().decodeWebP(streamToBytes(is));

} else {

bitmap = BitmapFactory.decodeStream(is);

}

imageView.setImageBitmap(bitmap);

private static byte[] streamToBytes(InputStream is) {

ByteArrayOutputStream os = new ByteArrayOutputStream(1024);

byte[] buffer = new byte[1024];

int len;

try {

while ((len = is.read(buffer)) >= 0) {

os.write(buffer, 0, len);

}

} catch (java.io.IOException e) {

}

return os.toByteArray();

}

ok,这样就可以对4.2.1以下的webp图片进行decode了。

服务端下发的图片为webp格式,然后app去decode显示即可。

注:webp-android这个库只提供了decode方法,如果需要encode需要自己去添加;建议有时间,看下源码中提供的方法,自己利用源码结合ndk相关知识自己做so文件的生成.

(3)应用中的资源文件

除了上述去加载外部图片的方式以外,还有个使用场景就是将项目中的资源文件直接替换为webp。

简单的使用:

直接将png转化为webp,放到res/drawable目录,我们看看效果

这样就可以了~~

从目前来看有2个选择:

  1. 仅替换不存在局部透明的图片,如果项目最小版本是4.0,可以不引入so直接使用。

  2. 全部替换(需要引入so的支持)

第一种,目前来看没什么好介绍的,换图即可。

主要看第二种的处理了,webp-android提供了一种做法是这样的:

<me.everything.webp.WebPImageView

android:layout_width=“wrap_content”

android:layout_height=“wrap_content”

webp:webp_src=“@drawable/your_webp_image” />

这样就可以happy的使用webp了。

但是我一点都不happy,使用webp很多都是已经存在的项目,让我去使用自定义类还要加属性,多麻烦,万一发现坑,我还得一个一个换回去,坚决不干。

所以我们需要一种,可以无缝切换的方式,基本不费力也能还原。

最无缝的方式,就是不动原本的布局文件了,那么如何去动态修改ImageView使其支持Webp呢(4.-)?

其实我们的SDK也有类似的做法,比如对很多View支持了tint属性,原本是不支持的,忽然就支持了,怎么做到的呢?

就是在根据布局文件中ImageView标签名称,创建的时候去做了一些手脚,如果你一脸懵逼,可以先看Android 探究 LayoutInflater setFactory

实际上就是利用LayoutInflaterFactory了,有了方案,那么代码就好写了:

public class MainActivity extends AppCompatActivity {

private static final int[] LL = new int[]

{ //

android.R.attr.src,//

};

@Override

protected void onCreate(Bundle savedInstanceState) {

if(Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN){

LayoutInflaterCompat.setFactory(LayoutInflater.from(this), new LayoutInflaterFactory() {

@Override

public View onCreateView(View parent, String name, Context context, AttributeSet attrs) {

AppCompatDelegate delegate = getDelegate();

View view = delegate.createView(parent, name, context, attrs);

if (view instanceof ImageView) {

ImageView imageView = (ImageView) view;

TypedArray a = context.obtainStyledAttributes(attrs, LL);

int webpSourceResourceID = a.getResourceId(0, 0);

if (webpSourceResourceID == 0) {

return view;

}

InputStream rawImageStream = getResources().openRawResource(webpSourceResourceID);

byte[] data = streamToBytes(rawImageStream);

final Bitmap webpBitmap = WebPDecoder.getInstance().decodeWebP(data);

imageView.setImageBitmap(webpBitmap);

a.recycle();

}

return view;

}

});

}

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

}

}

一般我们的项目中的Activity都存在一个基类,那么直接在其中添加上述代码即可。

大致逻辑为:对于4.2以下的版本,我们设置一个LayoutInflaterFactory,当创建ImageView的时候,因为AppCompatActivity,ImageView的创建是由上述代码中的delegate指向的对象完成的,我们通过传入attrs,取出用户声明的src属性,经过一系列操作转化为bitmap,最好设置到创建好的ImageView上。

这样,剩下的我们直接将图换成webp就好了,如果发现不适合,只需要去掉这个factory设置的代码即可。

正在我窃喜的时候,忽然发现了一个问题。

就是假设我的资源文件更换并不彻底,还存在部分png的图,但是png的图在4.2以下的版本是不需要上述操作的。

  • 那么问题来了,如何区分webp和非webp的图片资源呢?

当然是根据后缀,那么我们现在能获取的仅仅是图片的resId,还能拿到文件完整的名称吗?

让人开心的是,可以拿到的。

TypedValue value = new TypedValue();

getResources().getValue(webpSourceResourceID, value, true);

String resname = value.string.toString().substring(13,

value.string.toString().length());

if (resname.endsWith(“.webp”)) {

// do

}

当然应该也可以通过图片的header信息来判断,header判断这种方式应该会更加精确,具体可以查找下相关代码。

对了,如果你的基类是FragmentActivity,那就不需要去设置什么LayoutFactory了,直接复写其onCreateView方法:

onCreateView(View parent, String name, Context context, AttributeSet attrs) {

final View view = super.onCreateView(parent, name, context, attrs);

if(view == null){

if (name.equals(“ImageView”)) {

view = new ImageView(context,attrs);

最后

今天关于面试的分享就到这里,还是那句话,有些东西你不仅要懂,而且要能够很好地表达出来,能够让面试官认可你的理解,例如Handler机制,这个是面试必问之题。有些晦涩的点,或许它只活在面试当中,实际工作当中你压根不会用到它,但是你要知道它是什么东西。

最后在这里小编分享一份自己收录整理上述技术体系图相关的几十套腾讯、头条、阿里、美团等公司19年的面试题,把技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节,由于篇幅有限,这里以图片的形式给大家展示一部分。

还有 高级架构技术进阶脑图、Android开发面试专题资料,高级进阶架构资料 帮助大家学习提升进阶,也节省大家在网上搜索资料的时间来学习,也可以分享给身边好友一起学习。

【Android核心高级技术PDF文档,BAT大厂面试真题解析】

【算法合集】

【延伸Android必备知识点】

【Android部分高级架构视频学习资源】

**Android精讲视频领取学习后更加是如虎添翼!**进军BATJ大厂等(备战)!现在都说互联网寒冬,其实无非就是你上错了车,且穿的少(技能),要是你上对车,自身技术能力够强,公司换掉的代价大,怎么可能会被裁掉,都是淘汰末端的业务Curd而已!现如今市场上初级程序员泛滥,这套教程针对Android开发工程师1-6年的人员、正处于瓶颈期,想要年后突破自己涨薪的,进阶Android中高级、架构师对你更是如鱼得水,赶快领取吧!

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加V获取:vip204888 (备注Android)
img

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

165)]

【Android部分高级架构视频学习资源】

**Android精讲视频领取学习后更加是如虎添翼!**进军BATJ大厂等(备战)!现在都说互联网寒冬,其实无非就是你上错了车,且穿的少(技能),要是你上对车,自身技术能力够强,公司换掉的代价大,怎么可能会被裁掉,都是淘汰末端的业务Curd而已!现如今市场上初级程序员泛滥,这套教程针对Android开发工程师1-6年的人员、正处于瓶颈期,想要年后突破自己涨薪的,进阶Android中高级、架构师对你更是如鱼得水,赶快领取吧!

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加V获取:vip204888 (备注Android)
[外链图片转存中…(img-flg9A3Uh-1713662050166)]

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 11
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值