您现在的位置: 主页 > 嵌入式操作系统 > Android > 你见过哪些令你瞠目结舌的 Android 代码技巧?
本文所属标签:
为本文创立个标签吧:

你见过哪些令你瞠目结舌的 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"/>
但是这样的代码肯定不让你提交的,怎么办呢;用tools命名空间即可;这样只有IDE等开发工具才会关心这些特性,完全不用担心别的问题;更多用法请google。

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);
可以使用ContentProvider 解决这个异步的问题;可以把你的BinderPool实现放在ContentProvider里面,别的进程query拿到这个IBinder,这个过程是同步的;因此你可以在你的代码里面肆无忌惮地getService拿到一个远程接口,然后进行远程调用;完全跟调用本地接口一样,不需要binderService,不需要接受异步回调;具体实现需要序列化IBinder以及利用ContentProvider的call方法(API 11以下需要对query方法动点手脚)
当然,如果这个调用在主线成里面,还是有可能造成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);
然后这里我们使用了JDK动态代理方便实现代理模式,看看这个代理的Handler做了什么,它的invoke方法如下:
@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提前终止流程。

              查看评论 回复



嵌入式交流网主页 > 嵌入式操作系统 > Android > 你见过哪些令你瞠目结舌的 Android 代码技巧?
 一个 这个 方法

"你见过哪些令你瞠目结舌的 Android 代码技巧?"的相关文章

网站地图

围观()