聊聊 Android N 开始支持的 Lambda
cmch0440
9年前
<p>Android N 正式版已经发布了。对于开发者来说一个重大的更新是对于Java支持到了Java8,其中一点就是支持Lambda。我们就来聊聊什么是lambda,怎么在Android中使用。</p> <h2><strong>什么是lambda</strong></h2> <p>Lambda 可以理解为匿名函数,帮助我们写出更加简洁的代码。</p> <p>给view设置一个clicklistener,原本你需要写出这样的代码:</p> <pre> <code class="language-java">v.setOnClickListener(newView.OnClickListener(View v) { @Override publicvoidonClick(View v){ Toast.makeText(getActivity(), "clicked", Toast.LENGTH_LONG).show() } }); </code></pre> <p>使用lambda之后:</p> <pre> <code class="language-java">.setOnClickListener(v -> Toast.makeText(getActivity(), "clicked", Toast.LENGTH_LONG).show()); </code></pre> <p>是不是代码量爆减。这里再看下怎么写lambda。</p> <p>在JavaScript,python等语言中函数是一等公民,但是Java中类才是。使用lambda时候,lambda其实应该是一个对象,依附于函数式接口(只包含一个抽象方法声明的接口,例如刚刚我们举例的 OnClickListener 就是,在Java 8 需要使用 @FunctionalInterface 这样保证在编译的时候一个接口只有一个抽象注解)。</p> <p>写法的基本规则是这样:</p> <pre> <code class="language-java">(arguments) -> {body} </code></pre> <p>arguments 是参数列表,0~n个, 参数为一个时候,可以不要括号</p> <p>body 为具体代码部分,如果代码只有一句的话可以不要大括号</p> <p>返回值会自动推导出类型</p> <p>一些写法实例:</p> <pre> <code class="language-java">(inta,intb) -> {returna + b; } () -> System.out.println("Hello World"); (String s) -> System.out.println(s); () -> 42 () -> { return3.1415}; (a, b) -> {returna+b;} </code></pre> <p>另外一点需要注意的是,在我们的lambda表达式中 this 关键指的是外部对象,而不是我们以为的lambda这个对象。在语法糖的实现过程中,lambda表达式最后会被变为类的私有方法,因此可以放心的使用this。</p> <h2><strong>使用retrolambda</strong></h2> <p>目前有个比较成熟的解决方案,使用 retrolambd ,接入的配置如下:</p> <pre> <code class="language-java">apply plugin:'com.android.application' apply plugin:'me.tatarka.retrolambda' buildscript { repositories { mavenCentral() } dependencies { classpath 'me.tatarka:gradle-retrolambda:3.2.5' } } // Required because retrolambda is on maven central repositories { mavenCentral() } android { compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } } //指定将源码编译的级别,以下会将代码编译到1.7的自己码格式 retrolambda { javaVersion JavaVersion.VERSION_1_7 } </code></pre> <p>当前,retrolambda对于android gradle插件是有依赖的,需要使用1.5+的插件才可以。</p> <p>retrolambda的原理是在编译的过程中,给class文件增加包裹,转成java 1.7支持的格式。</p> <h2><strong>使用jack</strong></h2> <p>在Android N,支持使用Java 8, google给我们提供了新的编译工具 jack ,因此可以直接支持lambda,为了支持低版本的Android也可以用lambda,我们需要将 targetSdkVersion 和 compileSdkVersion 设置为23或者更小。启用jack,修改 build.gradle 如下。</p> <pre> <code class="language-java">android { ... defaultConfig { ... jackOptions { enabled true } } compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } } </code></pre> <p>jack工具链会的编译步骤如下:</p> <pre> <code class="language-java">Jack (.java --> .jack --> .dex) </code></pre> <p>和之前相比,将中间转换为class文件的步骤省略了,不需要多个工具链。</p> <p>在低版本兼容lambda,也同样是使用的语法糖来实现。</p> <h2><strong>后记</strong></h2> <p>如上两种工具都可以让我们在进行Android开发的时候来使用lambda,retrolambda出来的时间更早,经过很多次的迭代,目前也有一些app在使用,相比较来说更加成熟。jack则是google开发,减少了对javac的依赖,更多谷歌的自主性,相信后面谷歌大力推广的,但是出于刚刚开发出来因此还不够成熟,对于lint,proguard,instant run还有很多地方支持不好的地方,我们相信以后jack会是趋势。</p> <p>出于尝鲜,还是可以来使用的,但是在大的项目里面还是不建议使用的,毕竟万一出了问题还是很难排查的。</p> <p>另外,如果想要在android开发更爽快的使用lambda,也可以去试试 kotlin 这个语言。</p> <p>参考资料:</p> <ol> <li><a href="/misc/goto?guid=4959715724500083108" rel="nofollow,noindex">http://viralpatel.net/blogs/Lambda-expressions-java-tutorial/</a></li> <li><a href="/misc/goto?guid=4959715724609022207" rel="nofollow,noindex">https://developer.android.com/guide/platform/j8-jack.html</a></li> <li><a href="/misc/goto?guid=4958870212861858623" rel="nofollow,noindex">https://github.com/evant/gradle-retrolambda</a></li> </ol> <p> </p> <p> </p> <p>来自:http://blog.isming.me/2016/09/13/android-lambda/</p> <p> </p>