Potato icon indicating copy to clipboard operation
Potato copied to clipboard

Read the fucking source code for the Android interview

Results 73 Potato issues
Sort by recently updated
recently updated
newest added

# Android plug-in and hotfix summary [TOC] ## 插件化和热修复总述 首先明确一点,两者不是同一个概念。虽然在技术实现的角度来说,他们都是从系统加载起的角度出发,无论是 hook ,或者代理还是其他底层方式实现,都是通过 欺骗 Android 系统的方式,让宿主正常的加载和运行插件(补丁)中的内容; 但是两者的出发点不同。插件化,更多是想把需要实现的模块或者功能当作一个独立模块提取出来,较少宿主的大小,当需要使用到相应的功能时再去加载相应的模块。热修复则是从修复 bug 出发,强调的是在不需要二次安装应用的前提下修复已知的 bug。 * 宿主:当前运行的 APP * 插件:相对于插件化技术来说,就是要加载运行的 apk类文件 * 补丁:对于热修复技术来说,就是要加载运行的 .patch, .dex 等一系列包含...

DOING

# SparseArray and ArrayMap [TOC] Android 设备为了较少内存的使用和装拆箱损耗的性能,提供一些特有的数据结构代替 java 中原来的数据结构,适当采用这些数据结构可以优化应用的内存。 ## ArrayMap 用于代替 HashMap 使用,有几个特点: * 内部实现基于两个数组,可以避免在数据插入 Map 时额外的空间消耗 * 有扩容和收缩功能 * 不适合存储大容量数据;数据量大时,性能退化至少 50 %。 ```java /** {@hide} */ public ArrayMap(int...

SOURCE CODE

# Kotlin Coroutine [TOC] ## 科普解释进程,线程,协程 链接:https://www.zhihu.com/question/20511233/answer/24260355 没有啥复杂的东西,考虑清楚需求,就可以很自然的衍生出这些解决方案。 - 一开始大家想要同一时间执行那么三五个程序,大家能一块跑一跑。特别是UI什么的,别一上计算量比较大的玩意就跟死机一样。于是就有了**并发**,从程序员的角度可以看成是多个独立的逻辑流。内部可以是多cpu并行,也可以是单cpu时间分片,能快速的切换逻辑流,看起来像是大家一块跑的就行。 - 但是一块跑就有问题了。我计算到一半,刚把多次方程解到最后一步,你突然插进来,我的中间状态咋办,我用来储存的内存被你覆盖了咋办?所以跑在一个cpu里面的并发都需要处理上下文切换的问题。**进程**就是这样抽象出来个一个概念,搭配虚拟内存、进程表之类的东西,用来管理独立的程序运行、切换。 - 后来一电脑上有了好几个cpu,好咧,大家都别闲着,一人跑一进程。就是所谓的**并行**。 - 因为程序的使用涉及大量的计算机资源配置,把这活随意的交给用户程序,非常容易让整个系统分分钟被搞跪,资源分配也很难做到相对的公平。所以核心的操作需要陷入内核(kernel),切换到操作系统,让老大帮你来做。 - 有的时候碰着I/O访问,阻塞了后面所有的计算。空着也是空着,老大就直接把CPU切换到其他进程,让人家先用着。当然除了I\O阻塞,还有时钟阻塞等等。一开始大家都这样弄,后来发现不成,太慢了。为啥呀,一切换进程得反复进入内核,置换掉一大堆状态。进程数一高,大部分系统资源就被进程切换给吃掉了。后来搞出**线程**的概念,大致意思就是,这个地方阻塞了,但我还有其他地方的逻辑流可以计算,这些逻辑流是共享一个地址空间的,不用特别麻烦的切换页表、刷新TLB,只要把寄存器刷新一遍就行,能比切换进程开销少点。 - 如果连时钟阻塞、 线程切换这些功能我们都不需要了,自己在进程里面写一个逻辑流调度的东西。那么我们即可以利用到并发优势,又可以避免反复系统调用,还有进程切换造成的开销,分分钟给你上几千个逻辑流不费力。这就是**用户态线程**。 - 从上面可以看到,实现一个用户态线程有两个必须要处理的问题:一是碰着阻塞式I\O会导致整个进程被挂起;二是由于缺乏时钟阻塞,进程需要自己拥有调度线程的能力。如果一种实现使得每个线程需要自己通过调用某个方法,主动交出控制权。那么我们就称这种用户态线程是协作式的,即是**协程**。 **本质上协程就是用户空间下的线程。**

CONCEPT

# Java common collections [TOC] ## Collection 最基本的集合类型,所有实现Collection接口的类都必须提供两个标准的构造函数:无参数的构造函数用于创建一个共的Collection,有一个Collection参数的构造函数用于创建一个新的Collection,这个新的Collection与传入的Collection有相同的元素。 若要检查Collection中的元素,可以使用foreach进行遍历,也可以使用迭代器,Collection支持iterator()方法,通过该方法可以访问Collection中的每一个元素. ```java Iterator it=collection.iterator(); while(it.hasNext()){ Object obj=it.next(); } ``` Set和List是由Collection派生的两个接口 ### List List是有序的Collection,使用此接口能够精确的控制每个元素插入的位置。用户能够使用索引的位置来访问List中的元素,类似于Java数组。 List允许有相同的元素存在。 除了具有Collection接口必备的的iterator()方法外,还提供了listIterator()方法,放回一个 ListIterator接口。 实现List接口的常用类有LinkedList、ArrayList、Vector和Stack #### LinkedList类 LinkedList实现了List类接口,允许null元素。此外LinkedList提供额外的get、remove、insert方法在LinkedList的首部或尾部。这些操作使LinkedList可被用作堆栈(stack),队列(queue)或双向队列(deque)。LinkedList没有同步方法 #### AyyayList类...

CONCEPT

# LeakCanary Principle [TOC] 这篇文章介绍 LeakCanary 的原理,基于版本 2.0,kotlin。 ## 基本使用 加入依赖即可,以使用 ContentProvider 进行自动初始化。LifeCycle 库类似, 可用于初始化sdk,三方库等。 ```java dependencies { debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.0-alpha-2' } ``` ```kotlin internal class LeakSentryInstaller : ContentProvider() { override...

SOURCE CODE

# Android Invalidate() And RequestLayout() 这篇文章探讨能够触发 performTraversals() 执行的 invalidata(), requestLayout() 方法的流程。 在调用这几个方法到最后执行 performTravelsals() 方法,涉及到通过 Choroegrapher 请求 VSYNC 信号,实现按帧绘制的流程。 ## requestLayout invalidate() 和 postInvalidate() 都能够触发 View 的重画,这两个方法最终会调用 performTraversals() 中的performDraw() 来完成重绘制,是否执行 onMeasure...

CONCEPT

# Android Root Check [TOC] ## Android 安全机制 Android 是基于 Linux 多用户机制的访问控制。应用程序在默认的情况下不可以执行其他应用程序,包括读写用户的私有数据。一个应用程序的进程就是一个安全的沙盒(在受限的安全环境中运行应用程序,在沙盒中的所有改动对操作系统不会造成任何危害)。 每一个Android应用程序都会在安装时就分配一个独有的Linux用户ID,这就为它建立了一个沙盒,使其不能与其他应用程序进行接触。这个用户ID会在安装时分配给它,并在该设备上一直保持同一个数值。 所有的Android应用程序必须用证书进行签名认证,而这个证书的私钥是由开发者保有的。该证书可以用以识别应用程序的作者。签名影响安全性的最重要的方式是通过决定谁可以进入基于签名的permisssions,以及谁可以share 用户IDs。通过这样的机制,在不考虑root用户的情况下,每个应用都是相互隔离的,实现了一定的安全。 在Linux操作系统中,root的权限是最高的,也被称为超级权限的拥有者。 在系统中,每个文件、目录和进程,都归属于某一个用户,没有用户许可其它普通用户是无法操作的,但对root除外。 root用户的特权性还表现在:root可以超越任何用户和用户组来对文件或目录进行读取、修改或删除(在系统正常的许可范围内);对可执行程序的执行、终止;对硬件设备的添加、创建和移除等;也可以对文件和目录进行属主和权限进行修改,以适合系统管理的需要(因为root是系统中权限最高的特权用户);root是超越任何用户和用户组的,基于用户ID的权限机制的沙盒是隔离不了它的。 ## root的方式 * 不完全 root * 完全 root 目前获取Android root 权限常用方法是通过各种系统漏洞,替换或添加SU程序到设备,获取Root权限,而在获取root权限以后,会装一个程序用以提醒用户是否给予程序最高权限,可以一定程度上防止恶意软件,通常会使用Superuser或者 SuperSU...

CONCEPT

# Android Fragment 这篇文章讲解 Fragment 的基本概念使用。 ## 基础概念 > 因为support库是不断更新的,因此建议使用support库中的android.support.v4.app.Fragment,而不要用系统自带的android.app.Fragment。`而如果要使用support库的Fragment,Activity必须要继承FragmentActivity(AppCompatActivity是FragmentActivity的子类)`。 根据官方的定义: * framgent 依赖于 Activity,不能独立存在 * 一个 Activity 中可以有多个 Fragment * 一个 Fragment 可以被多个 Activity 重用。 * Fragment 有自己的生命周期,并能接收输入事件 *...

CONCEPT

# Android Bitmap Efficient Load [TOC] 文章转载:https://juejin.im/post/5b0e6e6a5188251570336972 将大图加载到内存中总是令人痛苦,经常会造成 OOM。Android系统的内存有限 > **建议使用Picasso或Glide来加载图片。没有必要重新发明轮子。** ## 将图片加载到内存中 只需要使用BitmapFactory来解码你的图片. ```java Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.hqimage); imageView.setImageBitmap(bitmap); ``` 看一下这张解码过的图片在内存中实际占据的空间大小。 **bitmap.getByteCount**()方法将返回bitmap的大小。 这张图片在内存中的大小为12262248字节,相当于12.3 MB。是的,你可能会感到困惑。因为这张图片在磁盘上的实际大小约为3.5 MB,而getByteCount()方法返回的值远大于它。原因如下: > 存储在磁盘上的图片是被压缩过的(以JPG,PNG或类似的格式存储)。 一旦将图片加载到内存中,它就不再被压缩,并占用尽可能多的图片的所有像素所需的内存空间。...

USAGE

# Android Service [TOC] Service 分为两种工作状态: * 启动状态:主要用于执行后台计算 * 绑定状态:主要用于其他组件和 Service 的交互 两种状态可以并存。 ## 生命周期 * onCreate:首次创建服务时,系统调用次方法;如果服务正在运行,则不会调用,只会执行一次。 * onStartCommand:但另一个组件调用 startService() 请求启动服务时,系统调用 * onBind:另一个组件通过调用 bindService() 与服务绑定时,系统将调用此方法 * onUnBind:另一个组件调用 unBindService() 与服务解绑,系统将调用此方法。 *...

CONCEPT