2024年Android最全Android 屏幕适配从未如斯简单(已废弃该使用方式)(2),字节跳动面试经验

文末

初级工程师拿到需求会直接开始做,然后做着做着发现有问题了,要么技术实现不了,要么逻辑有问题。

而高级工程师拿到需求会考虑很多,技术的可行性?对现有业务有没有帮助?对现有技术架构的影响?扩展性如何?等等…之后才会再进行设计编码阶段。

而现在随着跨平台开发,混合式开发,前端开发之类的热门,Android开发者需要学习和掌握的技术也在不断的增加。

通过和一些行业里的朋友交流讨论,以及参考现在大厂面试的要求。我们花了差不多一个月时间整理出了这份Android高级工程师需要掌握的所有知识体系。你可以看下掌握了多少。

混合式开发,微信小程序。都是得学会并且熟练的

这些是Android相关技术的内核,还有Java进阶

高级进阶必备的一些技术。像移动开发架构项目实战等

Android前沿技术;包括了组件化,热升级和热修复,以及各种架构跟框架的详细技术体系

以上即是我们整理的Android高级工程师需要掌握的技术体系了。可能很多朋友觉得很多技术自己都会了,只是一些新的技术不清楚而已。应该没什么太大的问题。

而这恰恰是问题所在!为什么别人高级工程师能年限突破30万,而你只有十几万呢?

就因为你只需补充你自己认为需要的,但并不知道企业需要的。这个就特别容易造成差距。因为你的技术体系并不系统,是零碎的,散乱的。那么你凭什么突破30万年薪呢?

我这些话比较直接,可能会戳到一些人的玻璃心,但是我知道肯定会对一些人起到点醒的效果的。而但凡只要有人因为我的这份高级系统大纲以及这些话找到了方向,并且付出行动去提升自我,为了成功变得更加努力。那么我做的这些就都有了意义。

喜欢的话请帮忙转发点赞一下能让更多有需要的人看到吧。谢谢!

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

需要这份系统化学习资料的朋友,可以戳这里获取

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

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

如上就是竖屏以 360dp 为宽度和横屏以 360dp 为高度的适配效果。

原理

如果看了上面今日头条的那篇适配文章,那么你可能已经知道其原理了,不明白的话可以继续看下我的解释: 我们知道 px = dp * density,我们要适配的话需要确保 dp 不变去修改 density,而安卓默认 density = dpi / 160,其意思就是 1dp 有多少 px,也就是像素密度,我们开发是按照一份设计稿来做的,那么有没有什么办法来让 density 和设计稿尺寸做联系呢?假设我们设计稿是宽度是 1080px,资源放在 xxhdpi,那么我们宽度转换为 dp 就是 1080 / 3 = 360dp,要在不同设备上宽度都表现为 360dp,那么就需要修改其 density = screenWidthPx / 360,这样就满足了上述条件,而和 density 相关的还有 densityDpi、scaledDensity,我们根据 density 等比修改 densityDpi、scaledDensity 即可。

由于 API 26 及以上的 Activity#getResources()#getDisplayMetrics()Application#getResources()#getDisplayMetrics() 是不同的引用,所以在 API 26 及以上适配是没有影响的,但在 API 26 以下 Activity#getResources()#getDisplayMetrics()Application#getResources()#getDisplayMetrics() 是相同的引用,导致适配有问题,这里要感谢 @MirkoWu 提出的问题,后面会有解决方案。

如果我们以 xxhdpi 的 360dp 来适配的话,首先在 AS 中预览是个问题,在接入第三方 SDK 带有界面或者 View 的话会导致它的尺寸全然不对,因为我们那样适配后界面宽度只有 360dp,而第三方 SDK 中很有可能写的布局会超出 360dp,这便会引发新的问题,当然这也是有响应的解决之道,比如暂时取消适配,但我们有更好的方式,着重看下面介绍。

我着重推荐以 mdpi 为特例来适配,比如前面说到的 xxhdpi 的 360dp,那么在 mdpi 下就是 360 * 3 = 1080dp,这样我们新建一个宽为 1080px 的 mdpi 设备(可以通过修改设备尺寸来达到 mdpi),然后切换为该设备来预览布局就完美解决了以上问题,我们在写布局的时候设计图是 36px,那么我们直接就写 36dp 即可,设计图字体是 24px, 我们直接就写 24sp 即可,这样便可达到和设计图一致的效果。另外,图片资源放在需要适配的最高 dpi 下面即可,比如 drawable-xxhdpi 或者 drawable-xxxhdpi,这样在高清屏上也不会导致失真。

但是这样会导致获取状态栏和导航栏高度有问题,其获取状态栏高度代码为如下所示:

public static int getStatusBarHeight() {
Resources resources = Utils.getApp().getResources();
int resourceId = resources.getIdentifier(“status_bar_height”, “dimen”, “android”);
return resources.getDimensionPixelSize(resourceId);
}

由于使用的是 Application#getResources,这会导致最后计算状态栏高度使用的是修改过后的 density,在这里也要感谢 @magic0908 无意间提到的 Resources.getSystem() 来获取系统的 Resources,果不其然可以获取到正确高度的状态栏高度,代码如下所示:

public static int getStatusBarHeight() {
Resources resources = Resources.getSystem();
int resourceId = resources.getIdentifier(“status_bar_height”, “dimen”, “android”);
return resources.getDimensionPixelSize(resourceId);
}

同理获取导航栏高度也可以这样。

考虑到了 Resources.getSystem(),那么我们在适配上岂不是可以更方便,不用区分版本什么的 Activity#getResources()#getDisplayMetrics()Application#getResources()#getDisplayMetrics(),也不需要什么中间变量来记录适配前的值,那些值我们直接在 Resources#getSystem()#getDisplayMetrics() 中获取 densitydensityDpiscaledDensity 即可,而且在修改系统字体的时候,Resources#getSystem()#getDisplayMetrics() 也会相应地改变,这样也就不需要注册 registerComponentCallbacks 来监听系统字体的改变,所以最终的源码很是简洁,但其中间遇到的问题很是复杂,光工具类我这些天就更新了很多版本来解决其问题,从1.18.01.18.7,有六个版本都是和这个适配有关系,但最终还是完美地找到了解决方案,也要感谢大家的帮助,其最终源码如下所示:

/**

  • Adapt the screen for vertical slide.
  • @param activity The activity.
  • @param designWidthInPx The size of design diagram’s width, in pixel.
    /
    public static void adaptScreen4VerticalSlide(final Activity activity,
    final int designWidthInPx) {
    adaptScreen(activity, designWidthInPx, true);
    }
    /
    *
  • Adapt the screen for horizontal slide.
  • @param activity The activity.
  • @param designHeightInPx The size of design diagram’s height, in pixel.
    /
    public static void adaptScreen4HorizontalSlide(final Activity activity,
    final int designHeightInPx) {
    adaptScreen(activity, designHeightInPx, false);
    }
    /
    *
  • Reference from: https://mp.weixin.qq.com/s/d9QCoBP6kV9VSWvVldVVwA
    /
    private static void adaptScreen(final Activity activity,
    final int sizeInPx,
    final boolean isVerticalSlide) {
    final DisplayMetrics systemDm = Resources.getSystem().getDisplayMetrics();
    final DisplayMetrics appDm = Utils.getApp().getResources().getDisplayMetrics();
    final DisplayMetrics activityDm = activity.getResources().getDisplayMetrics();
    if (isVerticalSlide) {
    activityDm.density = activityDm.widthPixels / (float) sizeInPx;
    } else {
    activityDm.density = activityDm.heightPixels / (float) sizeInPx;
    }
    activityDm.scaledDensity = activityDm.density * (systemDm.scaledDensity / systemDm.dens
    activityDm.densityDpi = (int) (160 * activityDm.density);
    appDm.density = activityDm.density;
    appDm.scaledDensity = activityDm.scaledDensity;
    appDm.densityDpi = activityDm.densityDpi;
    }
    /
    *
  • Cancel adapt the screen.
  • @param activity The activity.
    /
    public static void cancelAdaptScreen(final Activity activity) {
    final DisplayMetrics systemDm = Resources.getSystem().getDisplayMetrics();
    final DisplayMetrics appDm = Utils.getApp().getResources().getDisplayMetrics();
    final DisplayMetrics activityDm = activity.getResources().getDisplayMetrics();
    activityDm.density = systemDm.density;
    activityDm.scaledDensity = systemDm.scaledDensity;
    activityDm.densityDpi = systemDm.densityDpi;
    appDm.density = systemDm.density;
    appDm.scaledDensity = systemDm.scaledDensity;
    appDm.densityDpi = systemDm.densityDpi;
    }
    /
    *
  • Return whether adapt screen.
  • @return {@code true}: yes
    {@code false}: no
    */
    public static boolean isAdaptScreen() {
    final DisplayMetrics systemDm = Resources.getSystem().getDisplayMetrics();
    final DisplayMetrics appDm = Utils.getApp().getResources().getDisplayMetrics();
    return systemDm.density != appDm.density;
    }

坑点

在原理里都已经说完了哈。

建议

新老项目都可以用这套方案,老项目中如果有新的 Activity 加进来,那么可以对其使用该方案来适配,然后在启动其他老的 Activity 时候 cancelAdaptScreen 即可。新项目我建议采用我工具类中的使用,可以让你爽到极致,在 BaseActivitysetContentView(xx) 之前调用适配代码即可,记得第二个参数一定要传入设计图的实际像素尺寸,不再是曾经的 dp 尺寸了。

有了固定的尺寸,那么我们百分比是不是就很好实现了,计算后直接写 xxdp 即可,这样在所有设备上也都是一定的比例,哪里还需要什么百分比布局什么的来做?是不是 so easy,更多风骚的操作可待你解锁。

结语

如果我的工具类对你的适配造成了影响,欢迎到 AndroidUtilCode 提 issue,感谢今日头条的方案,让我可以站在巨人的肩膀上装一次 13。
最后
记得屏幕适配一定要用 1.19.0 版本及以上
记得屏幕适配一定要用 1.19.0 版本及以上
记得屏幕适配一定要用 1.19.0 版本及以上
给大家带来了麻烦,sorry。
GitHub issue

屏幕适配问题汇总

《设计思想解读开源框架》

第一章、 热修复设计

  • 第一节、 AOT/JIT & dexopt 与 dex2oat

  • 第二节、 热修复设计之 CLASS_ISPREVERIFIED 问题

  • 第三节、热修复设计之热修复原理

  • 第四节、Tinker 的集成与使用(自动补丁包生成)

    第二章、 插件化框架设计

  • 第一节、 Class 文件与 Dex 文件的结构解读

  • 第二节、 Android 资源加载机制详解

  • 第三节、 四大组件调用原理

  • 第四节、 so 文件加载机制

  • 第五节、 Android 系统服务实现原理

    第三章、 组件化框架设计

  • 第一节、阿里巴巴开源路由框——ARouter 原理分析

  • 第二节、APT 编译时期自动生成代码&动态类加载

  • 第三节、 Java SPI 机制

  • 第四节、 AOP&IOC

  • 第五节、 手写组件化架构

    第四章、图片加载框架

  • 第一节、图片加载框架选型

  • 第二节、Glide 原理分析

  • 第三节、手写图片加载框架实战

    第五章、网络访问框架设计

  • 第一节、网络通信必备基础

  • 第二节、OkHttp 源码解读

  • 第三节、Retrofit 源码解析

    第六章、 RXJava 响应式编程框架设计

  • 第一节、链式调用

  • 第二节、 扩展的观察者模式

  • 第三节、事件变换设计

  • 第四节、Scheduler 线程控制

    第七章、 IOC 架构设计

  • 第一节、 依赖注入与控制反转

  • 第二节、ButterKnife 原理上篇、中篇、下篇

  • 第三节、Dagger 架构设计核心解密

    第八章、 Android 架构组件 Jetpack

  • 第一节、 LiveData 原理

  • 第二节、 Navigation 如何解决 tabLayout 问题

  • 第三节、 ViewModel 如何感知 View 生命周期及内核原理

  • 第四节、 Room 架构方式方法

  • 第五节、 dataBinding 为什么能够支持 MVVM

  • 第六节、 WorkManager 内核揭秘

  • 第七节、 Lifecycles 生命周期


    本文包含不同方向的自学编程路线、面试题集合/面经、及系列技术文章等,资源持续更新中…

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

需要这份系统化学习资料的朋友,可以戳这里获取

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

源持续更新中…**
[外链图片转存中…(img-DSWZuLOF-1715605990480)]

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

需要这份系统化学习资料的朋友,可以戳这里获取

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值