Let's render a simple page with Ktor server and kotlinx.html: get("/users.html") { call.respondHtml { myLayout(title = "Users") { userList( users = db.users.value, ) } } } A reusable myLayout provides scaffolding, userList encapsulates the specific page content, and db.users is a StateFlow> from the persistence layer. I've been doing this over and over to create admin dashboard pages for a project. It works great right up until you leave it open for a minute or two, and its content becomes stale. Client-side frameworks exist within the ecosystem to "solve" this, such as Compose for HTML or…
Two months ago I gave my first ever live programming talk at KotlinConf. It was called "Talking to terminals (and how they talk back)", and you can watch it here. I've previously done slide-heavy talks which contained small demos or navigating through an existing codebase. Since this talk was starting from nothing, I decided to just write all the code from nothing. This meant spending the majority of the time in the IDE, but also figuring out how to remember what I was supposed to be writing at each step. Making the wrong choice The exceedingly obvious solution to having a series of steps in…
I'm happy to announce that Retrofit, OkHttp, and Okio are moving to a new GitHub organization, and along with SQL Delight are all joining the Commonhaus Foundation. You can read their announcement of the move. This move is meant to reinforce our commitment to these projects' longevity and honor the fact that they've long since outgrown the stewardship of a single company. The transfer of these projects is already underway! Assets and infrastructure are still being moved, so please bear with us as we get everything back up and running. On behalf of myself, Jesse Wilson, and Alec Kazakova,…
Eight years ago we launched a library of Kotlin extensions for the Android platform, Android KTX. In the time since, the library became Core KTX, and numerous other KTX libraries were written for other AndroidX libraries. And while KTX's approach to adding Kotlin niceties was built on a strong technology foundation, we’ve made the difficult decision to begin winding down our KTX extension libraries1. That's right folks–toss another entry on the Killed By Google board! Despite the date this is no joke. However, mourn not, friends. The KTX libraries were killed because the adoption of Kotlin…
Many people rely on the Compose bill of materials (BOM) artifact to provide the complete set of Compose dependency versions. If we use Compose’s foundation 1.8.0 but a transitive dependency bumps foundation-layout, there’s a risk that these two versions are incompatible with each other despite otherwise being stable libraries. The Compose BOM will unify the versions so that all are guaranteed to work with each other. Since Compose comprises about 15 individual libraries, the Compose BOM provides us with only a single version that we have to manually change when upgrading. Nice and simple. But…
Did you know the versioning of AndroidX libraries and their stability guarantees are different from most libraries? Their betas and RCs are actually production-ready, and you should be using them! In a “normal” library, such as the ones I release, features are added and known bugs are fixed to produce a stable release which might be released as version 1.2.0. If any bugs are found in that release, they get fixed and put into a version 1.2.1. If new APIs are added, the next version becomes 1.3.0. This is basic semantic versioning. AndroidX does not do versioning this way. When a library has…
I used to use Bit.ly to put links into my presentations. Their service allowed you to customize the path portion of the link, so I was able to create links like bit.ly/ok-libs. If you were attending the talks live, watching the recording, or browsing the slides, the short URL was easy to type into a browser. Unfortunately, the path customization of Bit.ly is a global namespace. Short and memorable paths became increasingly hard to find. Ten years ago I bought the jakes.link URL to solve this problem. Bit.ly let you point custom domains at their service, and each then gets its own path…
It doesn't take long for a project to spawn multiple jobs in their GitHub Actions. Parallelization can lead to huge speedups for PRs. Job grouping makes it easier to conditionally enable or disable multiple steps. Each time you add a new job, however, you have to mark it as required in branch protection to prevent failing PRs from accidentally merging. Being a clever person, you might create a final job which lists all the other jobs as required, and then mark that as the single required job. jobs: # … final-status: needs: - build - unit-tests - emulator-tests - screenshot-tests # ……
JNI allows managed code inside the JVM or ART to call into native code. Java methods can be declared as native, and then a corresponding C function1 can be written and automatically wired together when the native library is loaded. Native code lacks mechanisms like packages and overloads, so a special format is used to encode the Java method signature. A Java method defined as: package com.example; class Things { static native long createThing(String name, int count); } Requires a matching C declaration which looks like: jlong Java_com_example_Things_createThing( JNIEnv *env, jclass type,…
When Espresso was made public a decade ago, one of its banner features was the "idling resource" concept. This monitored the main thread and any background thread pools to prevent your test from progressing until the app became idle. Waiting until idle generally increased the stability of tests since at that point the UI should be stable. We released RxIdler and okhttp-idling-resource for monitoring RxJava schedulers and OkHttp's dispatcher, respectively. Today I am deprecating both libraries. In the years since their release, I have become disillusioned with the idling resource mechanism–and…
You want to be using the latest JDK for development. Don't use Gradle toolchains, they'll needlessly force you to use old JDKs. You can still target and test on old JVM versions but develop with the latest and greatest. Java and the JDK are literally built for this. Locally this hasn't been a problem. Homebrew (or your favorite equivalent) will keep your default JDK at the latest. Keeping my GitHub actions up-to-date, however, frequently slips my mind. I find projects using 19 or 20 simply because I haven't touched the CI build in the two years since 19 or 20 was the latest. We're already…
There was a time when I used Maven heavily, but today all the libraries I work on build with Gradle. Even though I'm publishing with Gradle, consumers can use Gradle, Maven, Bazel, jars in libs/ (but please don't), or anything else. That's a huge JVM ecosystem win! In general, I don't have to think about what build system someone is using. I'm not here to debate subjective pros and cons of one versus any other. There is one notable exception, however. Maven's dependency resolution strategy is objectively bonkers. And if we want to support Maven consumers, we need to think about it. If you…
The last post featured some Kotlin code inadvertently targeting a new Java API when the build JDK was bumped to 21. This can be solved with the -Xjdk-release Kotlin compiler flag, or by using Gradle toolchains to build with an old JDK. If you read the Gradle docs… Using Java toolchains is a preferred way to target a language version …or the Android docs… We recommend that you always specify the Java toolchain …you wouldn't be blamed for thinking Java toolchains are the way to go! However, Java toolchains are rarely a good idea. Let's look at why. Bad docs Last week I released a new version of…
Yesterday, our Android app crashed with a weird NoSuchMethodError. java.lang.NoSuchMethodError: No interface method removeFirst()Ljava/lang/Object; in class Ljava/util/List; or its super classes (declaration of 'java.util.List' appears in /apex/com.android.art/javalib/core-oj.jar) at app.cash.redwood.lazylayout.widget.LazyListUpdateProcessor.onEndChanges(SourceFile:165) at app.cash.redwood.lazylayout.view.ViewLazyList.onEndChanges(SourceFile:210) at app.cash.redwood.protocol.widget.ProtocolBridge.sendChanges(SourceFile:125) at…
Given an array of integers ([1, 2, 3, 1, 3, 1]), find the elements which are duplicated. No, we're not interviewing. I'm trying to prevent a user from specifying a reserved value twice. Elsewhere in the file I already have duplicate detection for object tags. val dupes: MapInt, ListWidget>> = widgets.groupBy(Widget::tag) .filterValues { it.size > 1 } I can do the same technique for the integer array with an identity function and grabbing the resulting keys. val dupes: SetInt> = ints.groupBy { it } .filterValues { it.size > 1 } .keys This prints [1, 3]. So… done? Yes! But no, using the map…
Given a list of users, extract their names and join them into a comma-separated list. Kotlin's extension functions on collections make this trivial. users.map { it.name }.joinToString() Writing this in IntelliJ IDEA produces a "weak warning" offering advice. Call chain on collection type may be simplified An intention action will refactor the code for you to a more efficient form. users.joinToString() { it.name } Mapping the user to their name now occurs during construction of the joined string rather than as a discrete operation. The additional iterator and intermediate collection produced…
jlink is a JDK tool to create bespoke, minimal JREs for your applications. Let's try it with a "Hello, world!" program: class Main { public static void main(String... args) { System.out.println("Hello, world!"); } } My laptop is an M1 Mac and I have downloaded the Azul Zulu JDK 19 build for it. With the JDK I can both compile Java and then run the resulting program. $ mkdir out $ zulu19.30.11-ca-jdk19.0.1-macosx_aarch64/bin/javac -d out in/Main.java $ zulu19.30.11-ca-jdk19.0.1-macosx_aarch64/bin/java -cp out Main Hello, world! Azul Zulu also provides a JRE that I can use to run compiled…
Three years ago I gave the talk "What's new in Java 19: The end of Kotlin?" which forecasted what a future Java language would look like in September 2022 when Java 19 was released. Check your calendars, folks. It's September 2022 right now and Java 19 was released today! As expected my predictions were not perfect, but I'm pretty happy with the results. Let's check in with each feature and see how my predictions fared report-card style1. Local methods This feature allows for methods to be declared inside of other methods making them effectively private to that method. public static boolean…
In the past, when a new version of Java was released, I would add that version to our open source project's CI builds. strategy: matrix: java-version: - 8 - 9 ⋮ - 17 + - 18 This ensures that each project can be built and its tests pass on every major version. But this makes no sense! No user is building these projects on different versions. No user is building these projects at all. Consumers are using the pre-built .jar which we ship to Maven Central built on a single version. Testing on every version, however, is something extremely valuable. Thankfully, Gradle toolchains let us retain this…
Read at the source
Your visit, your choice.
Optional Google Analytics helps us understand visits. Microsoft Clarity records masked interactions to improve the site. Optional tools stay off unless you choose them. Privacy details.