字幕列表 影片播放 列印英文字幕 thanks Simon as developers we get the best work done when we just have the opportunity to sit down undistracted and get into the flow context switching greatly reduces our efficiency and it can cause us a lot of frustration how many of you would love to work in a world where you get to work in a consistent expressive concise and fun programming language all day both for the app development you do as well as the tools to build it I know I would when it comes to building Android we may use a mix of languages in the app source and the built will source everything from java groovy xml javascript if there's any web stuff native code could be in c c++ there's a lot of stuff going on here and it can really slow us down and inhibit new developers to the codebase I'm tie and I'm an Android developer at uber working on our external developer platform today I'm going to walk you through this under new language that some of you may have heard about by now called Kotlin and how it can help make your life a little bit better and more consistent throughout the entire development stack walk you through a short overview the language and then specific real-world examples primarily focused on using it in the the build tools but first remember to use the conference app to rate and ask questions before we begin with Scotland why isn't java good enough for us one of the major talking points lately has been when android will see true java 8 support recently along with the in release we did hear word of eight support with the new compiler jack however kind of in a fragmented worlds when it comes to the languages that android supports with Jack you get the land of support and you get that new API features for the brand new release but we all know how Android users are slow to adopt new versions of Java 7 has support for a larger set of devices i believe from KitKat and up and below that they're still stuck on java 6 support so with that fragmentation it's really hard to focus on just using a new language java android can both be quite error-prone as well capturing in her classes for example leaves your apps from the memory leaks especially when passing those onto asynchronous operations hopefully you got to see the talk by py earlier he does a lot more into the leaks that can be associated with that you didn't get a chance to see that today I'd recommend watching that video there are also several syntactical problems with java beside lambdas which is kind of the most popular thing that people say they want such as the collection streaming and other systemic problems such as the verbis no ability and mutability the syntactical problems can be resolved with some great libraries that help improve the app development experience and safely back fort some of those features from job and eight and seven to previous versions libraries like Jack retro lambda and even RX Java but the systemic problems cause for a bit of an issue though well Ruby is what is primarily used in for building Gradle and it's an expressive and useful language however I think it also has a few limitations that make it less than ideal for a world where we wanted this consistency across the first is that it's a that the first is that it's a dynamic language will call in a statically typed girls going to spend more time processing the language because of the runtime checking that needs to be done and it's been noted that using cotton in your Gradle bills will speed up the configuration step because previous dynamic harder for the ide to be smart for you to parse to autocomplete and therefore it's going to be more prone to error you're going to have to do the build before you can often see that there's an issue that's going to slow down the feedback cycle by using a statically typed language you allow the ID to be smarter for you and help give you these issues before you have to spend the time to reveal brings a number of performance and memory concerns if it was going to be specifically on Android as well so that might limit this consistency that we talked about for example the standard runtime for groovy is quite large the dynamic nature means that the garbage collector and android would be running quite frequently which could cause a poor user experience and close friends to drop wouldn't be great to have consistency between our build scripts plugins and the deliverable code well I think that we can get that by using column with all type i'm sure you've heard a thing or two about it but there's been a few our talks already about Colin here the conference but for those of you who haven't got a chance to hear about it i'll walk through a few of the advantages of it it's built by the folks at jetbrains the people behind IntelliJ and most of the android studio work and it's completely in its built completely in the open and it's designed with mobile first in mind with Android developers being a really large target audience for them they reach their 10 milestone somewhat recently so we have a stable I and many of the top apps are already starting to integrate or explore integration since the first time I gave this stock the Gradle team has also announced official support for cotton and build scripts as well while it's still in its infancy the dedication from the team and the official announcement means that going forward will see it treated as a first class citizen because it's designed to work with android mobile first in mind the bytecode that's generated by colin is a hundred percent compatible with the jvm six so it covers that fragmentation problem that i mentioned earlier you don't really need to convert your entire project to Kotlin to start using it you can use it right away because colin is fully interoperable with java you can intermix them in the same project the language has its own standard runtime and this library does need to be bundled with your application fortunately it's quite small coming in around 600 k last time I checked now if you were to contrast this to the iOS world which many of you may be familiar with as well Swift has a very similar setup you need a bundle Swift with your iOS application but it comes in around 10 megs for android it's pretty important especially if we're going to consider targeting emerging markets that we need to keep our appt binary small and fortunately Kotlin allows us to do that because colin is statically typed as i mentioned earlier and it keeps memory allocation in mind we don't have the same type of runtime overhead that we would be that we would have by using a dynamically typed language like Ruby this could be a large constraint on Android wear the GC would be making that more problematic lastly colin is a modern language with many awesome features that make development fun and you can use it on all of your android devices today but more importantly Colin helps us with many of the constraints that java introduced that java android both introduced by utilizing Collins type system for all safety it can help us reduce easy to avoid no corner error exceptions and make our code much more maintainable column gives us a great way to reduce the boilerplate code that's so synonymous with java it makes our code much more maintainable and approachable for other developers the Android API is rely primarily on an architecture of inheritance and although this works well for the teams at Google it puts the large larger burden on the app developer especially when many of us seek an architecture of composition there are also many api's that require proper ceremony to complete you have to call a number of methods in order just think about the steps required for toasting saving sequel light transactions or using the media recorder often you have to initialize do your work and then call a committer save and if you happen to miss one of those steps you're only going to discover that at one time lastly while java is too verbose in my opinion to define a maintainable build script I believe Colin is expressive and concise enough to compete with many aspects of groovy the preferred build script language of of Gradle while providing much-needed type safety to reduce errors and expedite the development of your tooling so we call it has it brings a lot of cool features to the table we have higher order functions and properties and mix-ins and there's a there's a lot of these and I'm only supposed to be up here for about 45 minutes so I'm just gonna go to a few of these today that i think will be really promising and help with your tooling so one of the most common exceptions and job development is the null pointer exception infamously known as the billion-dollar mistake unfortunately job doesn't have a first clapper class representation of something that may or may not be in all and we've seen many libraries and tooling try to address this in the past with band-aids on top of java by having run time-based checks for all it makes the code much more susceptible even when we're using those in all checks and having the potential value of null requires defensive programming which leads to let much less maintainable code as well so here's our first example to show Collins variable assignments you'll notice that Scotland uses a syntax that reverses the type a name ordering for variable declaration in this case we'll get a compile-time exception on that second line as we're not allowed to sign a sign all 2 VAR a however in this next example you'll note the ? along with the Declaration this indicates to Colin that the value maybe not all and we'll take care of checking that once we try to utilize the variable though we will see a compilation error as we needed to explicitly check for null before using you may notice the two different ways of declaring the variable here with bar and valve and to clarify Scotland uses bar to indicate that it's immutable variable well it uses Val to indicate indicate that it's an immutable value in this last example of no ability we can see a few different formats to check for null the first line of code you'll note the ? and use again with that is declared any further method calls on that object will return all if the parent object is not and this removes the need for us to do the nested if no checks in Java in the second line of code we follow a slightly different format of utilizing all we specify a default value using a single expression if else and in this last example we take advantage of the Elvis operator to simplify the syntax of the previous examples let's move on to another cool feature of Colin class properties in this example will define a class called user and specify a member variable for the name using the syntax we put the member in line with the class name is one approach although we could specify it below in the class as well which may be more familiar some of you although this looks like a standard Java field this is a synthetic property this means that the getters and setters are automatically generated for us and that's what's being used near the bottom with a slide that definitely helps clean up some of that boilerplate code we can however override the default generated getters and setters to specify custom log check by declaring a get a set method below the plot property definition you'll notice that we change the syntax for the property declaration here as well from the previous slide this is just another way of handling that in addition to using properties to clean up boilerplate code college offers a concept called the data class this is designed to be a lightweight pojo and all and do all of those things than standard pojo and java would normally need to take care of advising by adding the data keyword in the Declaration we get this behavior will automatically generate an equals and hashcode method for us so we no longer need to define that it will also create the two-string method with all of the constructor parameters that we defined lastly it will generate the copy method for us with default parameters so that you don't have to implement builders to copy and create immutable pojos throughout your code base data classes do have many limits as well for example they cannot extend another class or be abstract so i definitely recommend looking up the restrictions of this in the cotton documentation to decide if it's right for you let's move on to another example function literals or lambdas are a great way to make code more readable and have come to be expected from Modern Languages today java 6 doesn't have support for these but by using a framework like retro lambda that rewrites the bytecode from a lambda java 7 or a job at lambda to a single abstract method is a great way for us to get that in android today lucky for us we get it out of the box with Colin in this example we see it a few different syntactical ways to write them they will infer the type from the definition so we can reference the variables directly in the first example in a second with the old with only a single parameter we can refer to it as the standard it notation similar to groovy or many other languages and we can store the function literal in variables such that we can access it later when needed expanding on the function literal concept call it also provides us with higher order functions or functions that take functions as parameters or return them this is a very powerful technique to write clean readable code will get to see some more powerful examples of this in real-world use cases for cleaning up android and Gradle code as soon as we understand the last concept required that last concept that i want to talk about his extension functions calling gives you the ability to add methods to existing types and this is very powerful and similar to other languages like C sharp and it's a great way to replace the utility health at java has known to become we have a utah class representing interactions with an object that's out of your control the syntax requires that you just define the type . method name and the code interacts with that class as if it was owned by that class please note that you cannot override existing methods of a class with a functioning with an extension function another thing to note is that Colin only gives you access to the method that you defined in a class where you define the function extension if you wanted to use it in other classes you would need to explicitly imported from the class where you had to find it i mentioned earlier that function that extension functions were a great way to wrote avoid that you tell Helen Java but also mentioned that cotton is completely interoperable with java so what is this actually doing its generating a class with a static method that intercepts calls to the object in Colin but in Java you can back you can call that generated static you told directly Colin will assign a default name to the file based on the file name but you can specify something custom by using the annotation here file jvm name with the string for the file you wanted to group multiple of these extension functions in one you told class instead of having one generated per you could use this other annotation and declare the name and use the jvm multi file class annotation to do that this can be really powerful and android here's the traditional way of saving an object into shared preferences in Java you can see that it requires us to admit the preference editor put the object into the reference editor and then call apply and this is prone for error as it requires the ceremony to befall the exact followed exactly and if we don't then we don't save the value that we expect so how can we make this better here's that same functionality but using the last three concepts that we talked about using and Colin extension functions higher-order functions and function literals we add method edit to the shared preference object that takes a function literal that is defined as another extension function of the editor class this can be confusing at first but it's incredibly powerful and it allows any function literal past n to behave as if it was a method on the shared preferences editor object this allows us to use the code in a type-safe way knowing that the string is saved without having to worry about referencing the correct editor a caveat to note though is that since colin is java 6 compatible using higher order functions imposes certain certain runtime penalties each function is an object and it captures a closure these variables that are accessed in the body of the function so now we have memory allocations both for the function object and for the classes and the virtual calls to introduce runtime overhead as well but by adding the inline keyword and Colin to the function declaration we're telling the cotton compiler to compile the code in line as if we had to find it the very first way that i showed in Java which is while prone day error from a maintainability perspective much more performance for the machine so now our bytecode between the cotton version and the java version is identical remember when I said that Colin doesn't add runtime overhead well this is one of those features that really allows for that these cotton features give us a powerful ability to start creating a dsl there's a school proof-of-concept library called and co-written by the jetbrains team that allows you to clearly described android layouts using purely Collins without having to use XML xml at all by utilizing higher-order functions you can write a clean android layout dsl you may also notice that the syntax is starting to look quite similar to groovy so maybe now I've sold you on some of the benefits of colin is a language and you can see how it could be useful for work in your Android app but introducing that without further fragmentation to this to your code minutes you might have column in your app and mixing of mix of groovy and java your build tools that's up to three languages jvm languages just to be thinking about and humans aren't really that great context switching the matter really what you said what you think about yourself studies show that were not great at it so this overhead is going to reduce developer productivity maybe we can use Colin by bringing it to the next level in Gradle we could use in the build tool as well and i'm going to walk through some small examples of many use case of a use case many of us have had how to load api key information so that we can sign outgoing request to a web server and have been quite a few talks and blog posts and sample projects to teach us using cotton in an android specifically so from now on I'll just be focusing primarily on inside of cradle course to use Scotland we need to install it it's quite simple to install using Gradle we had a bill time dependency and apply the plug-in and then we include the standard library and runtime we can intermix . Katy files and the java files and the groovy files also to know be sure to install the intelligence or Android studio Colin plug-in it'll make your life a little bit easier can even help facilitate adding these dependencies and it has provided at java to Kotlin converter may not produce the most idiomatic Colin but it's definitely a great start this get scotland in our runtime code let's take a moment to make our build script even better using Colin as well the column Gradle support the cotton support in Braille scripts specifically is still a work in progress at the moment the Gradle team first unveiled Colin support for build scripts that great also met a few months ago but the benefits of cotton in the IDE will now be much easier for us to write and maintain these build scripts i know i'm really excited for autocomplete in cradle at this point the integration is somewhat limited though and it requires some workarounds here's an example that I created that's a subset of the larger example in the cradle repo for Colin and I have that link from the slides when those get posted you'll see that but if you look carefully at that previous example you'll notice that there are a couple things that were a little bit off there's a few lines just didn't look quite right that's because to make Colin work in an idiomatic way that most of us are familiar with from groovy and what most Android developers are used to in general I to add all of these extension functions to get it to work some things that I did hear created a block for the android tag so that we could use the Android dsl reference we wanted named access to the release build since it statically typed in groovy when you type your bill type release brackets that's actually internally resolving that in doing a look up with defined by name if we want that static compilation we have to use an extension function to explicitly declare build type it's not awesome but that's one of the workarounds that need to be done we also needed to access the default product flavor object directly if we were just use the default config that groovy provides us or that Gradle provides us it returns the abstract class so we'd have to do an instance of check and cast into something different which would be pretty gross so this allows us to get around that a little bit as well also in standard groovy when using the Android build tools you'll notice that you can set the min SDK and the compile-time sdk just using an integer well under the hood that's actually converting that into an API level object so we also created a couple extension functions to facilitate being able to take an integer and convert it into that you can definitely see that it's a proof-of-concept however it goes to show that the entire Internet can be used in column and we can dig into some examples now that we've moved past the script a little bit into work Kotlin shines without having to have these type of workarounds and that's in the plugins so as your your build scale and you want to share different logic between the different apps that you have you start building plugins it's colin and those can be very productive so here's a common scenario that a lot of Android engineers would be familiar with developer would want to sign an outgoing request with the consumer key and secret for authentication on the back end in this example we define the key in secret and then we use them with a generic sdk let's focus on that API key part specifically one obvious improvement that we can do to protect nice the code here is to have different API keys for different cell types of flavors for example due to analytics you may want a different consumer key and secret used for the developer release and the production release this wasn't an SDK but your own web service you also want to find this staging and production credentials this way potentially as well more interestingly what if you wanted to push this to an open source repo like github or allow third-party developers or contractors to work on your source code and you didn't want to expose confidential information ideally we'd have a proper separation of concerns and we have these keys provided to the application during the build process from a secure location on the CIA machine this would meet the previous concern and give us the confidence that when the developer pushed it open source repo that they didn't accidentally leaked information this is an example of where the Gradle tooling can really shine what we have here is the android Gradle plug-in dsl that allows us to add a constant to the generated build config class that's accessible in the Android source code were able to define different keys and secrets for various built types and flavors both and the syntax is very straightforward you just declare the type followed by the name and the value to be accessed so now we have the keys provided to Gradle to the class that's broadly accessible in our Android source code although this allows us to provide different keys for different build types meeting one of our previous requirements we still haven't been able to achieve our other goal of separating the API keys from the main repository so let's take a look at some other techniques that we can use with Gradle to help us their rail provides a number of mechanisms to provider inject values into the build process there's the Gradle properties or sometimes referred to as the project properties of Dash P this lives in various locations starting in the local project defined as the Gradle . properties file but also including the user's home in the home / . Gradle great about properties that lives outside of your repo there's also the standard standard system variables set for running that running on the terminal with dash D lastly you can always load your own custom property file and then use those values and rest of your build lifecycle and practice the choice varies from team to team it's largely driven by your own teams policies working process and structure what CI system you use what your onboarding process like for new and new engineers and other minor constraints once we have the property accessible this get prop function uses both the Gradle properties and the system variables and that's the order of precedence and how they're resolved you can have your development key for your dad builds but when it comes to the CI build you can have your system variable set by build engineer DevOps to overwrite that to avoid accidental check ends and this could protect confidential information for your organization and here so we could use that get proper function in the build-up Gradle whatever that has been set to inject that into the bill can fit class now we've met the capability to have both of our requirements that we mentioned earlier we have the separation of concerns and we're being able to inject that into the different types however if you have multiple keys it can be tedious to keep track of all the different environment variables required to setup a new development environment or spin up a new CI box you might want to create a custom properties file and leave the Gradle that properties checked in for in sensitive information like the artifact ID version number other things like that and then you may need to file another reason you might want a properties file like this is if you use their party SDKs that rely on these for pulling out client ID or information like that simply you just wanna onboard new engineers with your own Gradle plug-in and simplify that process as you scale out your team so if you wanted to do that we added to the . get ignore and then we'll go ahead and we'll we'll show some code for generating some custom property files from that let's create a custom task that can be defined build Gradle we get all the values we need and then we write them into the file for the build you a job engineer that's not very familiar with groovy without put stream will be of interest to you hear an extension to the file class implemented by groovy that just wraps opening a file and reading the output stream conceptually it's very similar to the cotton extension functions function extensions groovy like Scotland also does not have checked exceptions so there's no need for a try-catch here so now all you need to do is run this task once for whenever you have a new environment a new developer additional keys if you add a custom property to the . getting more file you can push this code to a public repo as well without concern your team probably has more than one app though maybe for consistency you want to share some of this code you can make sure every app is set up in the same way even better you want to read this process for other external apps so let's make this more consistent for all your apps through building a great plugin the Gradle plug-in has three basic ingredients that I'm going to be talking about today and the first is the task typically used to represent an action triggered from the command line or another task you can also extend the project object for various things some examples of providing values from the build-up cradle or a function to the bill . Gradle this is the land object that you normally see in your build.gradle files lastly the plug-in itself is used to bind the previous components that we just talked about into the Gradle lifecycle and this is generally the business logic of your plugin that we need to talk about a very simple way to create a custom task is by extending the default task class functions annotated with that task action will be called when the task is executed create file function here contains the logic that we wrote values into the custom property file with some generalization to allow for reusability this task requires key and output file to be provided so that the plug-in consumer supplies their own lists of the keys and the path to the file that they want to write because this code will sit outside of the bill . Gradle we could have written in java let's do a simple example to demonstrate why I think groovier Kotlin would be preferable to java in this example this is what it looks like in Java as you can see it's a lot more ugly than the groovy version that we just looked at includes additional try-catch all checks and while java developers acclimate overtime to seeing that and kinda get out and looking at the business logic it actively discourages many new developers from approaching the code base especially when they're coming from different languages how many of you have opened up an objective-c file and had a hard time looking past all the brackets that's the exact same feeling that non java developers get when they look at java code like this unfortunately it's a barrier for entry and I believe Colin can help us out with that for dramatic effect I'll show you what it looks like if we just commented out all that ceremonial code all that boilerplate and this is about as concise as the group aversion and as you can see it's much easier to follow along what's going on now that we've followed the small rabbit hole down let's get back on track with our plug-in example to continue along with the task another important part of it is the defined inputs and outputs and put it the Gradle annotation that marks the field is an input task to be completed and output file is another Gradle annotation that's declared in an output of the task for this file there particularly important for incremental building for the great land for the Gradle clean task to empower proper caching and fast builds for the consumers of this plugin to make it easier for plug-in consumers to configure the task will provide an extension extension is a simple class that allows the plug-in consumer to provide the certain data required to run the plugin for example it's a great little so it's primarily inside of the Gradle plug-in dsl so this is what you're used to and an example of this is a using a pogo or a groovy version of a POJO and this gives us the functionality to create that lambda now these data members at compile time will be provided with getters and setters similar to the synthetic properties and Colin to make it more idiomatic will provide will also provide the key file to shortcut assignment to file you can add the get proper function here in the extensions so the function can be available to any project that applies our plug-in and lastly the plug-in itself that will help us find it integrate these components into our build lifecycle first we want to add our extension into the project object by using the extensions properly property this allows us to access the provided data by the plug-in consumer and allows them to use its syntax and they're built the plug in class interacts a lot with the project object and the Gradle provides a configuration function in the project object to allow for a more concise syntax by inferring the project object will be used in the following closure you can see the second line here product extensions for more concise example this can be inferred to simply can be inferred to simply as extensions with the configure closure which performs exactly like the first example another important part of the plugins is to make the task available to the project the after evaluate closure means that if you want the block of code to be called once all the initialization phase of Gradle has been completed let's say that we only want to add the task if the keys have actually been assigned and that is we do in the after evaluating closure to allow the plug-in consumers setting it in their bill . Gradle here we can see how one would use that plug that plug in your build.gradle script so there you have it a greater plugin in groovy simplifying your use of the web api keys now let's see what it would look like if we try to convert that into Colin here's the syntax that you should already be familiar with from the earlier introduction that I gave to the language we have two fields key that our list and file that is knowledgeable now we don't need it to be knowledgeable per se but for this demo I want to make it knowledgeable to show you how to deal with the interoperability of java api is that are by nature knowledgeable so Colin needs to be able to interact with that API know that that's inaudible coming in please pay attention to the first line the open here declares that this class is not final by default all classes and Colin are final and that'll be an issue when it comes to building this in Gradle because the task needs to explicitly be extended from the Gradle and provides a proxy and we need to market is open such a great all can inherit from it that its own logic is that version of create file function when translated line-by-line similar to groovy Colin does not have checked exceptions so any uncaught exception will just be elevated to the caller here we have another version that's a bit more idiomatic we've replaced the for loop with a for each and function literal but what's more interesting here is this last line here we're using the double bang operator remember how key file was knowledgeable well what we're saying here with the double bang operator is that Keith key file isn't all just throw the null pointer exception and that's another way to deal with multiple objects and job in with multiple objects coming from java here's our version of the pojo as the Gradle extension and this uses the data classroom Colin now we're looking at the plug in class similar to before we want to add the extension to the project and again we want to use the after evaluate here to allow the extension to be set in the build-up cradle well this is cleaner than the java example that I showed earlier at this stage it still looks quite verbose and I'd love to further improve on that some examples the fight to get my name with the holder you're looking that up that's just not going to autocomplete so can we do to simplify this by utilizing a couple extension functions we can assign a configure function to the project in the first line extensions and in extensions on the second line one will be able to make the code alot more concise and comfortable to those coming from groovy so here's the example of how it looks like before and after we use extension functions to clean it up you can see in the second example how we move towards a more declarative and groovy like syntax so now we have the final version of our plug-in Colin just like with the groovy version we add extension the after evaluation is done to create a task to create a file based on the extension date that was supplied declarative concise and familiar groovy developers but it's consistent with the cotton that is potentially already in your Android app if you use panko or similar patterns in your Android app all of your code can start to look like this as well I believe this reduces the context switching the overhead and it allows for faster move between different layers of the stack and I've run into a large case of developers that have a little bit of anxiety and hopping into the build tool incoming from android apps and I hope that something like this can start to make that a little more approachable we've talked about a lot of info here today there's some great resources on the web to help you dig deeper into the language first is the official docs there a great learning resource with a ton of info I'd recommend starting their the column Cohens are a great way to learn and play with Colin your browser it's an interactive ide echoes that cool plugin that i showed earlier it's open source you can dig into that it's kinda cold replace xml layouts I wouldn't necessarily using that in production i know that some apps are but it's kinda cool to see how that evolves is also the official Gradle repo that has examples of using cotton and build scripts now there's another talk given by jeff gordon actually last year door to have that dives a lot deeper and using Colin and android development i recommend watching that there's also been a lot of other great Colin talks coming out of the android seen recently if you wanted more information on using that in android lastly this sample Gradle plug-in is open-source this one that we bought today and Scotland version lives in this repo on github these are all clickable links from the slides will be shared the more people use and contribute to Colin the faster we can all have a modern language for our day jobs since Google may take awhile to officially sanction cotton cotton for android if they ever do it's up to us in the community to drive the best practices forward while google owns Android Open Source ecosystem and we are all responsible for making it better can take some questions now and if you don't want to say them out loud out then I'm happy to talk afterwards as well thank you for your time today very much time we got one question from the apps and that's out we're cuddling has support for lint in Android studio right now on the landing tooling is a very telling in general is an awesome i'm jake today introduced and support in 104 it's somewhat recent one of three so it'sit's reason but i don't think there's a lot of out-of-the-box left tooling for the things in common that you might want to be checking for so just be the android lengths that you don't know whether any questions from the audience surprised no one's asking me about the downsides of college you know maybe you could do something whether I well I mean it'sit's not the first party tooling that by the Android team so it's definitely running a little slower all times are slower they're still think eNOS in the IDE if you're using an alternative build system like fuck you're gonna have some issues getting it running it's definitely a fast-moving environment so the tooling will get there but it's definitely a work in progress so we see something that you would you try to absolutely will absolutely guys in the corner no I mean for us we've had multiple teams in uber that have been been investigating it using it in testing different things for a little while I know there's been plenty of other teams pinterest has some of their code written in it I no squares worked in column a little bit on some of their stuff it's definitely up-and-coming and it's going to be a great way to put in your apps but it's definitely since it's still evolving is an ecosystem the tools coming up around it it's something to be thoughtful about the migration okay thank you time please give him a hand and remember to rate decision
B1 中級 GOTO 2016--用Kotlin和Gradle實現更好的Android開發--Ty Smith。 (GOTO 2016 • Better Android Development with Kotlin & Gradle • Ty Smith) 151 12 colin 發佈於 2021 年 01 月 14 日 更多分享 分享 收藏 回報 影片單字