你见过哪些令你瞠目结舌的 Android 代码技巧?
来源:android 网络用户发布,如有版权联系网管删除 2018-09-09
1. XML布局的时候,为了预览测试View布局的测试效果,你是不是经常写一些测试的代码,比如:
<Button
android:id="@+id/btn"
android:text="heheheheheh"
android:layout_width="match_parent"
android:layout_weight="1"
android:layout_height="match_parent"/>
2. 是否经常需要post一个Runable到主线程执行呢?通常情况下需要new一个Handler,但是,如果你能持有一个View,可以直接view.post() 系列方法;
3. 提前返回减少代码缩进;这个不仅仅适用于Android。例如,
private void test(boolean condition1, boolean condition2) {
if (condition1) {
while (true) {
if (condition2) {
// 这里是很大一段代码,可以看到这一段相对你的函数有三层缩进
}
}
}
}
private void test(boolean condition1, boolean condition2) {
if (!condition1) {
return;
}
while (true) {
if (!condition2) {
continue;
}
// 这里是你的核心逻辑; 只有一层嵌套
}
}
4. Binder连接池/同步Binder
在业务越来越多的时候,难道要给每一个AIDL写一个Service吗?主席的书《Android开发艺术探索》里面给出了一个解决方案,那就是Binder连接池;但是这个并不完美:必须在额外的线程获取Binder;不然由于onServiceConnection回调在主线程,这个异步回调无法用锁变成同步(在同一个线程);
另外,每次bindService的时候,必须接受一个异步回调才能干活,能不能有一个同步获取Service的办法呢?类似这样:
// 注意这个可以是任意线程, 而不是必须在工作线程
IBinder compute = sm.getService("compute");
ICompute computeImpl = ICompute.Stub.asInterface(compute);
当然,如果这个调用在主线成里面,还是有可能造成ANR的;但是,如果对业务模块有把控,确保这个调用不会耗时,那么就会大大方便平时的工作。
先挖坑,具体实现后面给出。
5. 使用代理的方法Hook掉系统的一些对象,比如AMS,PMS;从而实现手动控制Activity等的生命周期;这里举个例子,现在拦截系统对于startActivity方法的调用;我们知道,对于startActivity方法的调用最终都会调用到ActivityManagerService里面的startActivity方法;在真正进入到AMS的进程之前,会有通过一个AMS的本地代理ActivityManagerNative来完成,这个本地的代理的startActivity方法调用transact方法进入驱动完成了对远程进程AMS的真正的startActivity实现的调用;(这么一段是为了说清楚流程)
那么我们要Hook掉这个startActivity操作;可以对ActivityManagerNative做点手脚:
Class<?> activityManagerNativeClass = Class.forName("android.app.ActivityManagerNative");
Field gDefaultField = activityManagerNativeClass.getDeclaredField("gDefault");
gDefaultField.setAccessible(true);
Object gDefault = gDefaultField.get(null);
// gDefault是一个 android.util.Singleton对象; 我们取出这个单例里面的字段
Class<?> singleton = Class.forName("android.util.Singleton");
Field mInstanceField = singleton.getDeclaredField("mInstance");
mInstanceField.setAccessible(true);
// ActivityManagerNative 的gDefault对象里面原始的 IActivityManager对象
Object rawIActivityManager = mInstanceField.get(gDefault);
// 创建一个这个对象的代理对象, 然后替换这个字段, 让我们的代理对象帮忙干活
Class<?> iActivityManagerInterface = Class.forName("android.app.IActivityManager");
Object proxy = Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
new Class<?>[] { iActivityManagerInterface }, new IActivityManagerHandler(rawIActivityManager));
mInstanceField.set(gDefault, proxy);
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if ("startActivity".equals(method.getName())) {
// 只拦截这个方法
// 替换参数, 任你所为;甚至替换原始Activity启动别的Activity偷梁换柱
好了,懂的童鞋可能已经意识到什么了;我们可以管理四大组件的生命周期!这正是插件框架的基石。
2016.2.29 更新:第五条填坑完毕,关于AOP Hook系统API的方式,以及用它如何实现一个插件框架,可以参考我的系列文章:
Android插件化原理解析概要
Android插件化原理解析Hook机制之动态代理
Android插件化原理解析Hook机制之Binder Hook
不关心插件化的,直接看第三篇即可。
待补充======================================
补充一:
do-while(false) 循环:
只执行一次的循环,与直接去掉这个 do-while有什么区别?
可以用break提前终止流程。
查看评论 回复