标签归档:android

Android如何优雅的弹出键盘

在很多app中,为了避免ui样式被键盘顶起,从而会把主内容的编辑功能单独摘一个发布器,作为用户的编辑界面,如快手抖音的评论。如下图所示

因此作为发布器必须第一时间弹出输入法,但是过早的调用InputMethodManager.showSoftInput 是无法弹出键盘的,任何的showflag都是一样的,

网上大部分人告诉我们答案,只要将showSoftInput 进行延迟展示即可,更有离谱的告诉你监听draw,监听layout后再调用等

然而这些方法都是不可靠的,监听draw监听layout或者进行delay的话,你会发现换个手机就不生效了,要么就要继续把delay 时间延长保证线上的可靠性,不同手机的延长时间是不一样的。。。。 查看更多

Android 特定情况requestlayout 一直无效分析

问题的发现

在做一次项目重构后,发现偶现ViewPager页面出现滑动到一半停住,继续触摸继续滑动,连续滑动后,ViewPager不会有新的页面创建,所有页面都滑到了屏幕之外。

问题分析

既然问题出现在ViewPager,那么当然是从ViewPager的代码开始分析了,既然Viewpager可以滑动,但是松手的时候一切没有触发新页面的加载,于是我怀疑是Viewpager的populate(int item)方法有问题。

经过断点分析,发现这段逻辑完全正常,松手后,确实完美触发了populate 方法,index同样也是对的,那么为什么没有触发滚动动画和页面加载呢。

重新增加断点到Viewpager adapter里的View创建里,发现正常情况下,创建页面的调用栈是从View的onlayout触发的,而异常情况下,没有触发onLyaout。 查看更多

一个dexfile解析库

最近同事在研究自定义解释器加壳的的能力,简单的说就是,自己实现解释器来执行加密的字节码,从而让破解的人无法从内存中dump到完整的dex文件或者永远是错误的dex,加大了破解难度。

由于在Github上没找到合适的c/c++实现的 dex解析库,只好徒手从art虚拟机中扒出来。

这个dexfile只是从art 从抽出的代码,可以使用jni调用,没有封装好的jni接口。需要自己参考dumpdex里的代码或者了解dexfile里的实现才能用。

通过这个库可以获得dex file里的method field 以及各个method的opcode和oprand,如果想自己实现dex虚拟机玩玩可以试试

使用的ndk版本的是r21 cmak3.14 查看更多

Android 硬件和软件绘制的一些差异分析

1.从简单的现象出发

当布局关系如下图所示时,其中Child1和Child2有重叠

Applictaion关闭硬件绘制

使用软件绘制时,调用invalidate时候可以发现兄弟 Child2也进行了绘制,ParentLayout1的兄弟节点ParentLayout2 虽然执行了dispatchDraw,但是子控件并没有重绘

Applictation打开硬件绘制时

使用硬件绘制时,调用invalidate可以发现仅仅是Child1进行绘制但是Child2没有进行绘制

从上面的现象可以发现,硬件绘制时,即使view有重叠,在刷新ui的时候也可以保持只绘制一个,而且不管是软件还是硬件,父亲的兄弟节点之后的view也不需要重绘,这表明一个问题,使用硬件绘制和软件绘制的时候,方法的调用流程似乎是不一样的。 查看更多

从Invalidate到Draw的辗转历程

以android Q的源码为例子,一步步分析invalidate的调用流程。

在写自定义控件的时候时常会用到 invalide 方法,都知道调用 invalide 后会回调Draw方法,但其中的辗转历程鲜有人知,为了搞清这个流程,我从android Q 源码入手分析了整个调用流程。在此记录一下,省得以后忘了

1.App Call SufaceFlinger

1.任何的View的invalidate方法最终都会调用到ViewRootImpl.java的invalidate()或者invalidateChildInParent,区别只是mDirty的大小,这个mDirty表示这个区域需要重绘

frameworks/base/core/java/android/view/ViewRootImpl.java

2.scheduleTraversals的实现如下

frameworks/base/core/java/android/view/ViewRootImpl.java

3.这里需要注意的是一个插入同步屏障的过程,插入同步屏障后,只有异步的消息才能在MessageQeue循环,app这边 Handler之类的全部失去效果,所以在Traversals执行或者取消的时候会马上移除,如下所示 查看更多

ActivityThead.mNewActivities导致的内存泄漏

昨天有测试报告说这个版本的应用在重复跑测试case的时候内存不断变大

由于测试case会重复启动activity首先就怀疑是不是activitty导致的内存泄漏

Adb shell dumpsys meminfo [packagename]

通过dump 信息,发现activity的实例确实在不断变多,但查阅代码并未发现任何持有引用的地方

android studio profile来 dump内存信息发现最短的引用路径来自android os. ActivityThead

开始有点不信,不觉得系统的引用的会导致内存不断增加,然后再次使用MAT分析

发现确实来自ActivityThead.mNewActivities

源码分析

通关简单分析发现mNewActivities 是一个链表

搜索关键字发现仅仅只在ActivityThead.Idler这个私有类里进行了引用释放,这个

MessageQueue.IdleHandler 这是一个接口,查阅注释发现这个接口仅仅只有当前线程 MessageQueue 空闲之后才会回调 查看更多

悬浮窗开发的总结

1、动画和点击区域问题

可以使用hide方法viewTreeObserver下的方法进行窗口裁剪实现局部透过点击事件,这样在动画的时候就不需要考虑进行window大小变化了

2、 启动慢的问题

1)由于悬浮窗启动一般使用的是service启动,通过分析ams可以发现,在进行activity启动的是有进行powehint操作的,而一般的service是没有的,如果系统是自家的可以考虑在启动自己的服务的时候加上powerhint操作

2)使用startforgroundService的方式提高进程的优先级

3) 考虑使用异步layoutinfler来实现在applictaion创建时候就着手准备view

3、偶现UI不刷新,但没有anr

这个问题,赶紧查查进程的OOM_ADJ,大概率是优先级过低,得不到系统的资源调度问题 查看更多

从最上层到驱动层看Android Conetext.getSystemService究竟做了什么

曾经好奇为什么同样是binder接口,Conetext.getService为什么可以直接获取,而不需要像bindeService一样异步回调,今天终于从能够从上层源码到binder驱动源码,彻底了解这一过程,同时分析binder接口在调用的时候,底层究竟是如何实现的。

1.从getSystemService 到native的getContextObject

ContextImpl.java

SystemServiceRegistry.java

SYSTEM_SERVICE_FETCHERS是一个hasmap,键值是一个抽象类,ServiceFetcher,它在初始化的时候实现,见如下代码

registerService 的作用就是把CachedServiceFetcher 放到 SYSTEM_SERVICE_FETCHERS 中,这样每次取服务时都可以从这个缓存获取,因此我们第二次getSystemService时性能是非常高的,时间复杂度位O(1),然后所有系统服务端最终都会调用到这一步 查看更多

总结一下各路绕过反射限制的方法

为了防止app调用系统的hide方法,android 9.0对反射的调用做了一个限制,每个方法或者变量在编译后在flag里表示了该方法是hide还是公开,通过回溯调用栈判断该调用者的类是否是BootstrapClassLoader 如果是则信任

应对方法

1,定义和系统相同类,骗过编译器,直接调用隐藏方法

2. jni修改 javaruntime里的 隐藏api策略, hidden_api_policy_

3.既然只检查调用类是否是是系统类,那么使用反射去调用反射方法,两次反射,第二次调用系统方法,在检查的时候会发现调用者反射工具类,而反射工具类是系统方法

4。 修改 javaruntime .里的豁免条件GetHiddenApiExemptions ,可以使用反射+反射 查看更多

MMKV代替 SharedPreferences

SharedPreferences 的缺点

1.SharedPreferences 写入性能低,在线上项目经常出现anr的情况,虽然 SharedPreferences 已经提供了异步写入apply方法,但由于为了保证数据的可靠性, SharedPreferences 会在一些特定的生命周期(如onDestory方法)直接执行还在pending过程的任务,导致app anr

2.对于多进程的使用, SharedPreferences 并不是很好,因为 SharedPreferences 有内存缓存,不能跨进程立即刷新,而使用contentprovider的话代码量更重

MMKV的优势

1.MMKV由于使用内存映射,使得每次写入只需写入到内存快即可,刷入操作由内核控制,不需要频繁的主动写入硬盘,即使进程意外挂掉,内核也会保存数据,写入速度极快 查看更多