Migrating from kotlin-android-extensions to newer view binding - kotlin

So if you are getting anything like below
> Configure project :app
Warning: The 'kotlin-android-extensions' Gradle plugin is deprecated.
This probably means which means that using Kotlin synthetics for view binding is no longer supported / deprecated.
So below is the answer where you can clearly get understanding on how to get / identify your ViewBinding class related to your views.

In order to migrate to the newer way of binding you need to first remove the kotlin synthetics plugin which could have been added as below :
apply plugin: 'kotlin-android-extensions'
OR
plugins {
...
id 'kotlin-android-extensions'
}
after removing synthetic plugin from app gradle you need to remove the imports which could like either of below :
activity /fragment view : import
kotlinx.android.synthetic.main.<your_activity_view>.*
normal views :
import kotlinx.android.synthetic.main.<your_layout_view>.view.*
Now begins actual migration
You need to add below inside your app gradle
android {
...
buildFeatures {
viewBinding true
}
}
After this you need to add a binding property where your view is to be bound.
Below is an example
:
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
val view = binding.root
setContentView(view)
binding.myTextView.text = "my text" //say your text view id is like : my_text_view"
}
Note : if your activity layout is activity_main.xml then your binding should be ActivityMainBinding
here you will find view binding example for fragment
here is official migration doc from google

Related

How to solve error with View Binding in Kotlin

Here I'm getting this error
package lk.ac.kln.mit.stu.mobileapplicationdevelopment.activities
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.View.inflate
import androidx.navigation.findNavController
import androidx.navigation.fragment.NavHostFragment
import lk.ac.kln.mit.stu.mobileapplicationdevelopment.R
class ShoppingActivity : AppCompatActivity() {
val binding by lazy{
ActivityShoppingBinding.inflate(layoutInflater)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_shopping)
setContentView(binding.root)
val navController = findNavController(R.id.shoppingHostFragment)
binding.bottomNavigation.setupWithNavContoller(navController)
}
}
Anyone know the reason to fail this code?
I tried adding below lines to the gradel as well
buildFeatures {
viewBinding true
}
You can better use this, this way the binding can be set in the onCreate as before this it can not build UI components.
var binding: ActivityShoppingBinding? = null
override fun onCreate(savedInstanceState: Bundle?) {
binding = ActivityShoppingBinding.inflate(layoutInflater)
binding?.let {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_shopping)
setContentView(binding.root)
val navController = findNavController(R.id.shoppingHostFragment)
binding.bottomNavigation.setupWithNavContoller(navController)
}
}
ActivityShoppingBinding is in red because it's not recognised by the IDE - usually this means you haven't imported it, so it doesn't know what it is. And you don't have an import line for that class, so that's probably your problem!
The easiest fix is just to put your cursor over the error and do Alt+Enter (or whatever) or click the lightbulb icon that appears, and the IDE will offer to import it for you. Once that binding class is imported it should work fine.
Also you're calling setContentView twice - that's pointless (you're inflating a layout then throwing it away immediately) and it can introduce bugs if you accidentally set things on a layout that isn't being displayed. You should only be calling it once, with binding.root in this case.
You might want to look at the recommended way of initialising view binding in Activities (and the Fragments section too if you're using them). Avoid using lazy for UI stuff, since it can only be assigned once you can run into issues (mostly with Fragments, but the example in that link uses lateinit too)

How to access `JavaToolchainSpec` from within custom Gradle task

According to "Toolchains for plugin authors" it should be possible to access the configured JavaToolchainSpec from within a custom task. I try to use this approach within a custom plugin which creates a task based on the presence of the JavaPlugin and queries the configured languageVersion property. Here is a minimal example.
build.gradle
plugins {
id 'application'
id 'com.example.myplugin'
}
...
java {
toolchain {
languageVersion.set(JavaLanguageVersion.of(17))
}
}
MyPlugin.kt
class MyPlugin : Plugin<Project> {
override fun apply(target: Project) {
target.plugins.withType<JavaPlugin> {
target.tasks.create<MyTask>("mytask")
}
}
}
MyTask.kt
abstract class MyTask : DefaultTask() {
init {
val extension = project.extensions.getByType<JavaPluginExtension>();
val languageVersion = extension.toolchain.languageVersion.get();
...
}
}
Once Gradle creates MyTask and the languageVersion property is queried, the build fails with the following error.
Cannot query the value of property 'languageVersion' because it has no value available.
My guess is that I am accessing the extension too early and it has not set its values at this time. My question now is if there is a way to wire up the configured properties (ideally with lazy mechanisms) with the task.
apparently you have to configure the toolchain object in the java plugin extension to be able to use JavaToolchainService, using something like:
java {
toolchain {
languageVersion = JavaLanguageVersion.of(11)
}
}
if you don't do that Gradle will defaults to the current JVM and the whole toolchain API will be unavailable (leaving you with the error you reported)

ArrowKT - #optics annotation not generating code

How do you setup the Arrow dependencies for #optics annotation to actually work? No companion objects are generated for the data classes annotated with #optics.
If I'm not mistaken, this is an annotation processor, so it should be imported using kapt, however the documentation uses it as compile.
For arrow 0.10.0
apply plugin: 'kotlin-kapt'
def arrow_version = "0.10.1-SNAPSHOT"
dependencies {
implementation "io.arrow-kt:arrow-optics:$arrow_version"
implementation "io.arrow-kt:arrow-syntax:$arrow_version"
kapt "io.arrow-kt:arrow-meta:$arrow_version" // <-- this is the kapt plugin
}
then:
#optics data class Street(val number: Int, val name: String) {
companion object {} // <-- this is required
}
Everything is explained in the documentation, I don't know how I missed it
https://arrow-kt.io/docs/

Add Framework to Module in IntelliJ Plugin

I'm trying to create an IntelliJ Plugin to automatically create a project type. I've gotten as far as making a custom ModuleBuilder with an area for inserting a Group ID and Artifact ID.
When the project is created, I want it to immediately come with gradle support, as well as a filled out build.gradle file and other stuff.
Does anyone know how to do this?
Thanks!
class SpigotKtWizard : ModuleBuilder() {
override fun setupRootModel(modifiableRootModel: ModifiableRootModel?) {}
override fun getModuleType(): ModuleType<*> {
return SpigotKtModuleType.instance
}
override fun createWizardSteps(wizardContext: WizardContext, modulesProvider: ModulesProvider): Array<ModuleWizardStep> {
return arrayOf(BuildOptionsStep())
}
override fun createProject(name: String?, path: String?): Project? {
val project = super.createProject(name, path) ?: return null
setupModule()
val d = project.baseDir.createChildData(this, "Test")
File(d.path).writeText("Testing boyyyy")
return project
}}
What I have so far.
If you're creating a Gradle project, it's much better to use a different API - GradleFrameworkSupportProvider. Then the user will choose Gradle in the new project wizard, and your framework in the list of frameworks to add. As an example, you can refer to the implementation in the Kotlin plugin.

Kotlin all-open compiler plugin doesn't work

I use Realm and it requires open keyword to it's model classes.
Following https://blog.jetbrains.com/kotlin/2016/12/kotlin-1-0-6-is-here/,
I tried to use all-open compiler plugin to remove the open keyword from Realm model classes.
First, I added all-open compiler plugin and set the package name of annotation
buildscript {
dependencies {
classpath "org.jetbrains.kotlin:kotlin-allopen:$kotlin_version"
}
}
apply plugin: "kotlin-allopen"
allOpen {
annotation("com.mycompany.myapp.annotation")
}
Second, I generated annotation
package com.mycompany.myapp.annotation
annotation class AllOpenAnnotation
Finally, I added the annotation to Realm model class
#AllOpenAnnotation
class Model {
var id: Int = -1,
var title: String = "",
var desc: String? = null
}: RealmObject()
But the error: cannot inherit from final Model error occurs.
Is there something that I did wrong?
You need to add the name of the annotation to the path in your config file:
allOpen {
annotation("com.mycompany.myapp.annotation.AllOpenAnnotation")
}