六木Sir

Results 100 issues of 六木Sir

# Android 开发之旅之进阶 ### 高级UI绘制 - [x] UI流程绘制分享 - UI源码级分析 - View的测量 - View的布局 - View的绘制过程 - 绘图及特效制作 - Paint画笔高级技能(Paint的方法使用技巧、高级渲染(BitmapShader位图渲染、LinearGradient线性渲染、RadialGradient环形渲染、SweepGradient扫描渐变渲染、ComposeShader组合渲染)) - Xfermode、滤镜效果(BlurMaskFilter滤镜、EmbossMaskFilter滤镜) - 颜色通道过滤(ColorMatrixColorFilter 颜色矩阵过滤、LightingColorFilter曝光颜色过滤、PorterDuffColorFilter图层混合颜色过滤) - Canvas画板高级技能(Canvas基础使用技巧、Canvas区域切割技巧(实例:android实现IOS Reveal特效)) - Canvas变换使用技巧(translate、scale、rotate、skew斜拉画布)...

Android
进阶

电话面试题 1.ArrayList 和 Hashmap 简单说一些,区别,底层的数据结构. 2.Handler 消息机制 3.引起内存泄漏的场景 4.多线程的使用场景? 5.常用的线程池有哪几种? 6.在公司做了什么?团队规模?为什么离职? 面试中实际涉及到的问题 第一轮 1.知道哪些单例模式,写一个线程安全的单例,并分析为什么是线程安全的? 2.Java中的集合有哪些?解释一下HashMap?底部的数据结构?散列表冲突的处理方法,散列表是一个什么样的数据结构?HashMap是采用什么方法处理冲突的? 3.解释一下什么是MVP架构,画出图解,一句话解释MVP和MVC的区别? 4.Handle消息机制?在使用Handler的时候要注意哪些东西,是否会引起内存泄漏?画一下Handler机制的图解? 5.是否做过性能优化?已经采取了哪些措施进行优化? 6.引起内存泄漏的原因是什么?以及你是怎么解决的? 这些问题应该都是比较基础的问题,每个开发者都应该是非常熟悉并能详细叙述的.这一轮的面试官问的技术都是平时用到的. 第二轮 1.关于并发理解多少?说几个并发的集合? 2.Handler 消息机制图解? 3.在项目中做了哪些东西? 4.画图说明View 事件传递机制?并举一个例子阐述 5.类加载机制,如何换肤,换肤插件中存在的问题?hotfix是否用过,原理是否了解? 6.说说项目中用到了哪些设计模式,说了一下策略模式和观察者模式? 7.会JS么?有Hybid开发经验么?...

面试

### 计算一张图片的大小 图片占用内存的计算公式:图片高度 * 图片宽度 * 一个像素占用的内存大小.所以,计算图片占用内存大小的时候,要考虑图片所在的目录跟设备密度,这两个因素其实影响的是图片的高宽,android会对图片进行拉升跟压缩。 ### 加载bitmap过程(怎样保证不产生内存溢出) 由于Android对图片使用内存有限制,若是加载几兆的大图片便内存溢出。Bitmap会将图片的所有像素(即长x宽)加载到内存中,如果图片分辨率过大,会直接导致内存OOM,只有在BitmapFactory加载图片时使用BitmapFactory.Options对相关参数进行配置来减少加载的像素。 BitmapFactory.Options相关参数详解 (1).Options.inPreferredConfig值来降低内存消耗。 比如:默认值ARGB_8888改为RGB_565,节约一半内存。 (2).设置Options.inSampleSize 缩放比例,对大图片进行压缩 。 (3).设置Options.inPurgeable和inInputShareable:让系统能及时回 收内存。 A:inPurgeable:设置为True时,表示系统内存不足时可以被回 收,设置为False时,表示不能被回收。 B:inInputShareable:设置是否深拷贝,与inPurgeable结合使用,inPurgeable为false时,该参数无意义。 (4).使用decodeStream代替其他方法。 decodeResource,setImageResource,setImageBitmap等方法 ### LRUCache算法是怎样实现的。 内部存在一个LinkedHashMap和maxSize,把最近使用的对象用强引用存储在 LinkedHashMap中,给出来put和get方法,每次put图片时计算缓存中所有图片总大小,跟maxSize进行比较,大于maxSize,就将最久添加的图片移除;反之小于maxSize就添加进来。 之前,我们会使用内存缓存技术实现,也就是软引用或弱引用,在Android 2.3(APILevel 9)开始,垃圾回收器会更倾向于回收持有软引用或弱引用的对象,这让软引用和弱引用变得不再可靠。

面试

## 插件化相关技术,热修补技术是怎样实现的,和插件化有什么区别 ### 相同点: 都使用ClassLoader来实现的加载的新的功能类,都可以使用PathClassLoader与DexClassLoader ## 不同点: 热修复因为是为了修复Bug的,所以要将新的同名类替代同名的Bug类,要抢先加载新的类而不是Bug类,所以多做两件事:在原先的app打包的时候,阻止相关类去打上CLASS_ISPREVERIFIED标志,还有在热修复时动态改变BaseDexClassLoader对象间接引用的dexElements,这样才能抢先代替Bug类,完成系统不加载旧的Bug类. 而插件化只是增肌新的功能类或者是资源文件,所以不涉及抢先加载旧的类这样的使命,就避过了阻止相关类去打上CLASS_ISPREVERIFIED标志和还有在热修复时动态改变BaseDexClassLoader对象间接引用的dexElements. 所以插件化比热修复简单,热修复是在插件化的基础上在进行替旧的Bug类

面试

## 产生的内存泄露 1).资源对象没关闭造成的内存泄漏 2).构造Adapter时,没有使用缓存的convertView 3).Bitmap对象不在使用时调用recycle()释放内存 4).试着使用关于application的context来替代和activity相关的context 5).注册没取消造成的内存泄漏 6).集合中对象没清理造成的内存泄漏 ## 查找内存泄漏 ## 查找内存泄漏可以使用Android Stdio 自带的Android Profiler工具,也可以使用Square产品的LeadCanary.

面试

Android中的线程池都是之间或间接通过配置ThreadPoolExecutor来实现不同特性的线程池.Android中最常见的四类具有不同特性的线程池分别为FixThreadPool、CachedThreadPool、SingleThreadPool、ScheduleThreadExecutor. - 1).FixThreadPool 只有核心线程,并且数量固定的,也不会被回收,所有线程都活动时,因为队列没有限制大小,新任务会等待执行. 优点:更快的响应外界请求. - 2).SingleThreadPool 只有一个核心线程,确保所有的任务都在同一线程中按顺序完成.因此不需要处理线程同步的问题. - 3).CachedThreadPool 只有非核心线程,最大线程数非常大,所有线程都活动时,会为新任务创建新线程,否则会利用空闲线程(60s空闲时间,过了就会被回收,所以线程池中有0个线程的可能)处理任务. 优点:任何任务都会被立即执行(任务队列SynchronousQueue相当于一个空集合);比较适合执行大量的耗时较少的任务. - 4).ScheduledThreadPool 核心线程数固定,非核心线程(闲着没活干会被立即回收)数没有限制. 优点:执行定时任务以及有固定周期的重复任务 参考: [https://blog.csdn.net/seu_calvin/article/details/52415337](https://blog.csdn.net/seu_calvin/article/details/52415337)

面试

## 1、前台进程 用户当前正在做的事情需要这个进程。如果满足下面的条件之一,一个进程就被认为是前台进程: 1).这个进程拥有一个正在与用户交互的Activity(这个Activity的onResume()方法被调用)。 2).这个进程拥有一个绑定到正在与用户交互的activity上的Service。 3).这个进程拥有一个前台运行的Service(service调用了方法startForeground()). 4).这个进程拥有一个正在执行其任何一个生命周期回调方法(onCreate(),onStart(),或onDestroy())的Service。 5).这个进程拥有正在执行其onReceive()方法的BroadcastReceiver。 通常,在任何时间点,只有很少的前台进程存在。它们只有在达到无法调合的矛盾时才会被杀--如内存太小而不能继续运行时。通常,到了这时,设备就达到了一个内存分页调度状态,所以需要杀一些前台进程来保证用户界面的反应. ## 2、可见进程 一个进程不拥有运行于前台的组件,但是依然能影响用户所见。满足下列条件时,进程即为可见: 这个进程拥有一个不在前台但仍可见的Activity(它的onPause()方法被调用)。当一个前台activity启动一个对话框时,就出了这种情况。 ## 3、服务进程 一个可见进程被认为是极其重要的。并且,除非只有杀掉它才可以保证所有前台进程的运行,否则是不能动它的。 这个进程拥有一个绑定到可见activity的Service。 一个进程不在上述两种之内,但它运行着一个被startService()所启动的service。 尽管一个服务进程不直接影响用户所见,但是它们通常做一些用户关心的事情(比如播放音乐或下载数据),所以系统不到前台进程和可见进程活不下去时不会杀它。 ## 4、后台进程 一个进程拥有一个当前不可见的activity(activity的onStop()方法被调用)。 这样的进程们不会直接影响到用户体验,所以系统可以在任意时刻杀了它们从而为前台、可见、以及服务进程们提供存储空间。通常有很多后台进程在运行。它们被保存在一个LRU(最近最少使用)列表中来确保拥有最近刚被看到的activity的进程最后被杀。如果一个activity正确的实现了它的生命周期方法,并保存了它的当前状态,那么杀死它的进程将不会对用户的可视化体验造成影响。因为当用户返回到这个activity时,这个activity会恢复它所有的可见状态。 ## 5、空进程 一个进程不拥有入何active组件。 保留这类进程的唯一理由是高速缓存,这样可以提高下一次一个组件要运行它时的启动速度。系统经常为了平衡在进程高速缓存和底层的内核高速缓存之间的整体系统资源而杀死它们。

面试

## 1.了解Binder 在Android系统中,每一个应用程序都运行在独立的进程中,这也保证了当其中一个程序出现异常而不会影响另一个应用程序的正常运转。在许多情况下,我们activity都会与各种系统的service打交道,很显然,我们写的程序中activity与系统service肯定不是同一个进程,但是它们之间是怎样实现通信的呢?所以Binder是android中一种实现进程间通信(IPC)的方式之一。 - 1).首先,Binder分为Client和Server两个进程。 注意,Client和Server是相对的。谁发消息,谁就是Client,谁接收消息,谁就是Server。 举个例子,两个进程A和B之间使用Binder通信,进程A发消息给进程B,那么这时候A是Binder Client,B是Binder Server;进程B发消息给进程A,那么这时候B是Binder Client,A是Binder Server——其实这么说虽然简单了,但还是不太严谨,我们先这么理解着。 - 2).其次,我们看下面这个图(摘自田维术的博客),基本说明白了Binder的组成解构: ![image](https://user-images.githubusercontent.com/28669743/43046638-6847cc80-8dfe-11e8-9a6b-f98af369fbec.png) 图中的IPC就是进程间通信的意思。 图中的ServiceManager,负责把Binder Server注册到一个容器中。 有人把ServiceManager比喻成电话局,存储着每个住宅的座机电话,还是很恰当的。张三给李四打电话,拨打电话号码,会先转接到电话局,电话局的接线员查到这个电话号码的地址,因为李四的电话号码之前在电话局注册过,所以就能拨通;没注册,就会提示该号码不存在。 对照着Android Binder机制,对着上面这图,张三就是Binder Client,李四就是Binder Server,电话局就是ServiceManager,电话局的接线员在这个过程中做了很多事情,对应着图中的Binder驱动. - 3).接下来我们看Binder通信的过程,还是摘自田维术博客的一张图: ![image](https://user-images.githubusercontent.com/28669743/43046641-754f883c-8dfe-11e8-9c90-51a8ec5803bd.png) 注:图中的SM也就是ServiceManager。 我们看到,Client想要直接调用Server的add方法,是不可以的,因为它们在不同的进程中,这时候就需要Binder来帮忙了。 首先是Server在SM这个容器中注册。 其次,Client想要调用Server的add方法,就需要先获取Server对象, 但是SM不会把真正的Server对象返回给Client,而是把Server的一个代理对象返回给Client,也就是Proxy。...

面试

- 1).Android事件分发机制的本质是要解决:点击事件由哪个对象发出,经过哪些对象,最终达到哪个对象并最终得到处理。这里的对象是指Activity、ViewGroup、View. - 2).Android中事件分发顺序:Activity(Window) -> ViewGroup -> View. - 3).事件分发过程由dispatchTouchEvent() 、onInterceptTouchEvent()和onTouchEvent()三个方法协助完成 设置Button按钮来响应点击事件事件传递情况:(如下图) 布局如下: ![image](https://user-images.githubusercontent.com/28669743/43046603-0219a76c-8dfe-11e8-9692-894bc7857629.png) 最外层:Activiy A,包含两个子View:ViewGroup B、View C 中间层:ViewGroup B,包含一个子View:View C 最内层:View C 假设用户首先触摸到屏幕上View C上的某个点(如图中黄色区域),那么Action_DOWN事件就在该点产生,然后用户移动手指并最后离开屏幕。 ## 按钮点击事件: DOWN事件被传递给C的onTouchEvent方法,该方法返回true,表示处理这个事件; 因为C正在处理这个事件,那么DOWN事件将不再往上传递给B和A的onTouchEvent(); 该事件列的其他事件(Move、Up)也将传递给C的onTouchEvent();...

面试

 View的绘制流程:OnMeasure()——>OnLayout()——>OnDraw() 各步骤的主要工作: OnMeasure(): 测量视图大小。从顶层父View到子View递归调用measure方法,measure方法又回调OnMeasure。 OnLayout(): 确定View位置,进行页面布局。从顶层父View向子View的递归调用view.layout方法的过程,即父View根据上一步measure子View所得到的布局大小和布局参数,将子View放在合适的位置上。 OnDraw(): 绘制视图:ViewRoot创建一个Canvas对象,然后调用OnDraw()。六个步骤:①、绘制视图的背景;②、保存画布的图层(Layer);③、绘制View的内容;④、绘制View子视图,如果没有就不用;⑤、还原图层(Layer);⑥、绘制滚动条。

面试