https://avatars.githubusercontent.com/u/22124534?v=4

Watson Wang

OnClickListener2048

把一件事坚持30天会怎么样?

30天,一件小事:它能如何改变你?

在快节奏的现代生活中,我们常常渴望掌握新技能,无论是编程、乐器、绘画还是运动,但又苦于时间稀缺,迟迟不敢开始。你是否曾想过,仅仅坚持一件事30天,会带来怎样的改变?

在YouTube上,有一个累积观看接近4000万的TED演讲,它提出了一个引人深思的理论:每天投入40分钟,坚持30天,累积大约20小时,你就能学会任何一门新技能。

是的,你没听错,不是200小时,也不是2000小时,仅仅是20小时。当然,这20小时并非让你成为奥运冠军或行业专家,而是让你能够比较体面地使用某项技能,具备初步的实践能力和信心。演讲者本人就用这个“20小时理论”,成功学会了瑜伽、编程、盲打、围棋、弹琴、乃至冲浪等多项技能。

那么,这20小时究竟是如何“炼成”的,以及这30天的坚持会带给我们什么?

20小时学习的四大核心步骤

这并非盲目的“苦练”,而是有策略的“巧练”。演讲者强调了四个关键步骤,它们是高效学习的基石:

1. 分解技能:化繁为简

任何一项看似复杂的技能,都可以被分解成一系列更小、更具体的子技能。例如,学习编程可能包括“理解变量”、“编写循环”、“调试错误”等。你的任务是找出其中最常用、最能快速产生效果的核心小技能,并优先练习它们。这能让你迅速建立起“我能行”的信心,并看到初步的成果。

2. 学习足够理论以自我纠正:拒绝“理论陷阱”

不要陷入无休止的理论学习中。目标是阅读3-4本(或更少)关于这项技能的基础教材或教程,学习到能够让你在练习时,可以识别出自己哪里做得不够好、需要进步的地方即可。过多的理论会拖延你的实践进程,而真正的学习和提升往往发生在动手的那一刻。

3. 移除学习障碍:创造无干扰环境

“磨刀不误砍柴工”,清除一切可能让你分心的因素是成功的关键。在练习时,请关掉手机通知,准备好所有需要的工具(例如,如果你要学习吉他,确保你的吉他已调好音,乐谱和教程就在手边)。为自己打造一个专注、高效的学习环境,让你的每一分钟都物有所值。

4. 投入20小时专注练习:日积月累,水滴石穿

这是最核心的部分:积累满20小时的专注练习时间。 按照每天40分钟的节奏,这恰好是30天的持续投入。每天坚持,哪怕只是一小段固定的时间,其累积效应是惊人的。你的大脑会逐渐建立新的神经通路,肌肉会形成记忆,技能会在无形中得到强化。

坚持30天,你会看到这些变化:

当你按照这个方法,真正将一件事坚持30天后,你会体验到以下几个层面的蜕变:

  • 技能的初步掌握与自信心的飞跃: 经过20小时的有效练习,你会发现自己真的能“体面地”使用这项技能了。无论是流利地敲出代码、流畅地弹奏一段乐曲,还是自信地用新语言进行日常交流,这种从“完全不会”到“基本掌握”的跨越,将极大地增强你的自我效能感和学习信心。你会发现,学习新事物并非遥不可及。

  • 习惯的初步养成与惰性的减弱: 30天的坚持,足以让这项活动在你生活中占据一席之地。最初的抵触和拖延会逐渐消退,它会变得不再那么像一项“任务”,而更像你日常生活的一部分。你的大脑会开始期待并适应这种规律,从而为你未来更长久的坚持打下坚实基础。

  • 时间管理能力的提升: 你会发现,即使每天只拿出40分钟,你也能“创造”出时间来学习。这会让你对自己的时间分配有更深的理解和更强的掌控感,从而优化生活中的其他方面,发现原来有这么多“碎片时间”可以利用。

  • 韧性与自我纪律的培养: 坚持30天并非一帆风顺,你可能会遇到身体不适、情绪低落、突发事件等干扰。每一次克服困难、重新回到轨道上的努力,都是对你韧性和自我纪律的磨砺。你会变得更强大,更不容易被挫折打倒。

  • 身份认同的转变: 当你每天都进行这项活动时,你会开始在潜意识中认同自己是“一个会编程的人”、“一个热爱跑步的人”或者“一个弹吉他的人”。这种积极的身份认同会进一步强化你的行为,形成良性循环。

你的20小时,从何开始?

30天,20小时,这是一个既有挑战性又充满可能性的数字。它提醒我们,学习不一定要漫长而痛苦,只要方法得当,持续投入,即使是看似微不足道的努力,也能汇聚成改变的力量。

现在,是时候问问自己:有什么新技能是你一直渴望掌握的? 拿起你的笔记本,按照这四个步骤,为自己开启一个为期30天的学习之旅吧!相信我,当30天结束时,你会对自己的潜能感到惊喜。


深入理解 Java GC:核心算法与常见收集器

前言

Java 开发者通常不需要像 C/C++ 开发者那样手动管理内存分配和释放,这得益于 Java 虚拟机(JVM)强大的**垃圾回收(Garbage Collection, GC)**机制。GC 自动地查找并回收不再被程序使用的内存(即“垃圾”),从而避免了内存泄漏和野指针等问题。

然而,GC 并非没有代价。不合适的 GC 配置或算法选择可能导致应用暂停(Stop-the-World, STW),影响性能和用户体验。因此,理解 GC 的基本原理和常用算法对于 Java 性能调优至关重要。

GC 的核心任务:识别垃圾

GC 的首要任务是找出哪些内存可以被回收。现代 JVM 主要采用**可达性分析(Reachability Analysis)**算法来判断对象是否存活:

  1. GC Roots: 首先确定一系列必须存活的“根”对象(GC Roots)。常见的 GC Roots 包括:
    • 虚拟机栈(栈帧中的本地变量表)中引用的对象。
    • 方法区中类静态属性引用的对象。
    • 方法区中常量引用的对象。
    • 本地方法栈中 JNI(即 Native 方法)引用的对象。
    • 活动线程。
    • 同步锁(synchronized 关键字)持有的对象。
  2. 可达性分析: 从 GC Roots 开始,沿着引用链向下搜索。如果一个对象可以通过任何引用链从 GC Roots 到达,则称该对象是可达的 (Reachable),意味着它正在被使用,不能回收。
  3. 不可达对象: 如果一个对象无法从任何 GC Roots 通过引用链到达,则认为该对象是不可达的 (Unreachable),即为“垃圾”,可以被回收。

注意: 即使是不可达对象,也至少要经历两次标记过程才真正被回收(涉及 finalize() 方法,但此方法已不推荐使用)。

基本 GC 算法

基于可达性分析找到垃圾后,就需要具体的算法来回收这些空间。以下是几种基础的 GC 算法思想,它们是现代复杂 GC 收集器的基石:

面试官:Android中加载大图和长图的正确方式是什么?

面试官您好,加载大图(高分辨率图)和长图(超高图)是 Android 开发中常见的性能和内存挑战。处理它们的核心原则是 避免一次性将整个原始尺寸的图片完整加载到内存中。我会根据图片类型采用不同的策略:

1. 加载“大图”(高分辨率图片 High-Resolution Images)

这里的“大”通常指图片的像素尺寸远超需要显示它的 ImageView 或屏幕的尺寸。

  • 核心技术:降采样 (Downsampling)
  • 目标: 在解码图片时就只加载一个缩小版的、内存占用更小的 Bitmap 到内存中,而不是加载完整大图后再缩放。
  • 实现步骤:
    1. 仅获取图片边界信息:
      • 创建 BitmapFactory.Options 对象。
      • 设置 options.inJustDecodeBounds = true
      • 调用 BitmapFactory.decodeStream(), decodeFile(), decodeResource() 等方法。此时,解码器只会读取图片的宽度、高度和 MIME 类型等元数据到 options 中(outWidth, outHeight),不会真正分配 Bitmap 内存
    2. 计算采样率 inSampleSize
      • 获取目标 ImageView 的尺寸(reqWidth, reqHeight)。如果 View 尚未布局完成,可能需要通过 View.post()ViewTreeObserver 等方式获取。
      • 比较图片原始尺寸 (options.outWidth, options.outHeight) 和目标显示尺寸 (reqWidth, reqHeight)。
      • 计算一个合适的 inSampleSize 值。该值表示缩小的倍数(宽和高都将缩小 inSampleSize 倍)。关键点inSampleSize 应该是 2 的整数次幂 (1, 2, 4, 8…),这样解码效率最高,效果最好。计算逻辑通常是找到一个最小的 2 的幂,使得解码后的图片尺寸(原始尺寸 / inSampleSize)略大于或等于目标尺寸。
      • 例如,可以封装一个 calculateInSampleSize(options, reqWidth, reqHeight) 的工具方法来实现这个计算逻辑。
    3. 实际解码缩小后的图片:
      • options.inJustDecodeBounds 设置回 false
      • 设置计算得到的 options.inSampleSize 值。
      • (可选优化)设置 options.inPreferredConfig 为更节省内存的格式,如 Bitmap.Config.RGB_565 (如果不需要 Alpha 通道)。
      • 再次调用 BitmapFactory.decodeXXX() 方法。这次会根据 inSampleSize 加载一个缩小版的 Bitmap 对象,内存占用大大降低。
  • 最佳实践:使用图片加载框架
    • Glide, Coil, Picasso 这样的成熟图片加载框架,内部已经完美封装了降采样的逻辑。它们会自动根据目标 ImageView 的尺寸(或通过 override() API 指定的尺寸)来计算并应用合适的 inSampleSize
    • 因此,在绝大多数场景下,直接使用这些优秀的图片库是加载“大图”的最佳且最简单的方式

2. 加载“长图”(Very Tall Images / Scrolling Long Screenshots)

这里的“长”指的是图片的高度远超屏幕高度,通常需要用户滚动来查看完整内容。

HTTP vs. HTTPS:深入理解差异与 HTTPS 全流程

前言

当我们在浏览器地址栏输入网址时,通常会看到 http://https:// 开头。虽然只差一个 “S”,但它们代表着截然不同的网络通信方式,尤其在安全性方面。理解 HTTP 与 HTTPS 的区别以及 HTTPS 的工作原理,对于 Web 开发者和关心网络安全的用户都至关重要。

什么是 HTTP?

HTTP (Hypertext Transfer Protocol),即超文本传输协议,是用于从万维网(WWW)服务器传输超文本到本地浏览器的传送协议。它是互联网上应用最为广泛的一种网络协议,所有的 WWW 文件都必须遵守这个标准。

HTTP 的主要特点:

  1. 无连接: 限制每次连接只处理一个请求。服务器处理完客户的请求,并收到客户的应答后,即断开连接(现代 HTTP 版本如 HTTP/1.1 支持持久连接 Keep-Alive)。
  2. 无状态: 协议对于事务处理没有记忆能力。每个请求都是独立的,服务器不知道客户端之前的请求历史。这通常需要 Cookie 或 Session 等机制来维持状态。
  3. 明文传输: 这是 HTTP 最致命的缺点。所有传输的数据(包括用户名、密码、银行卡信息等)都是未加密的,在传输过程中容易被窃听、截取和篡改。

什么是 HTTPS?

HTTPS (Hypertext Transfer Protocol Secure),即安全超文本传输协议。简单来说,它就是 HTTP 的安全版本。HTTPS 在 HTTP 的基础上加入了 SSL/TLS 协议,依靠 SSL/TLS 来加密数据包、验证服务器身份和保证数据完整性。

HTTPS 的核心优势:

  1. 数据加密: 通信内容通过对称加密和非对称加密技术进行加密,即使被截获,攻击者也无法轻易解密获取真实内容。
  2. 身份认证: 通过数字证书验证服务器的真实身份,防止用户访问到仿冒的钓鱼网站。
  3. 数据完整性: 通过消息认证码(MAC)校验数据在传输过程中是否被篡改。

HTTP 与 HTTPS 的主要区别

特性HTTPHTTPS
安全性明文传输,不安全使用 SSL/TLS 加密,安全
协议层应用层协议HTTP + SSL/TLS 协议(在传输层和应用层之间)
URL 前缀http://https://
默认端口80443
证书不需要需要 CA 颁发的 SSL/TLS 证书
连接过程简单,TCP 三次握手后直接传输 HTTP 报文TCP 三次握手后,还需要进行 SSL/TLS 握手
性能性能开销小建立连接(握手)有一定性能开销,但传输过程影响不大
SEO不利于 SEO对 SEO 友好,被搜索引擎(如 Google)推荐

HTTPS 的网络全流程详解

HTTPS 的通信过程比 HTTP 复杂,主要增加了 SSL/TLS 握手 阶段。以下是简化但关键的步骤:

Android冷启动优化

[toc]

1、冷启动时间检测

通过adb命令来检测应用冷启动时间

adb shell am start -W package/Activity路径

运行结果如下所示

  • TotalTime:应用的启动时间,包括创建进程+Application初始化+Activity初始化到界面显示。
  • WaitTime:一般比TotalTime大点,是AMS启动Activity的总耗时。
  • Android 5.0以下没有WaitTime,所以我们只需要关注TotalTime即可。
Starting: Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] cmp=***/***.SplashActivity }
Warning: Activity not started, intent has been delivered to currently running top-most instance.
Status: ok
LaunchState: UNKNOWN (0)
Activity: ***/***.MainActivity
TotalTime: 785
WaitTime: 787
Complete

2、冷启动时间消耗在哪

2.1、MultiDex耗时

apk的编译过程

  • 1、打包资源文件,生成R.java文件(使用工具AAPT)
  • 2、处理AIDL文件,生成java代码(没有AIDL则忽略)
  • 3、编译 java 文件,生成对应.class文件(java compiler)
  • 4、.class 文件转换成dex文件(dex)
  • 5、打包成没有签名的apk(使用工具apkbuilder)
  • 6、使用签名工具给apk签名(使用工具Jarsigner)
  • 7、对签名后的.apk文件进行对齐处理,不进行对齐处理不能发布到Google Market(使用工具zipalign)

为什么需要使用MultiDex

在apk编译流程的第4步,将class文件转换成dex文件,默认只会生成一个dex文件,单个dex文件中的方法数不能超过65536,不然编译会报错: