hope you are well.
I am writing to find more strategies to debugging View Binding in Kotlin. For context, I am progressing through the following course on Udemy. I am currently stuck on module 142. The content pertains to creating a custom toolbar for a given activity.
Before showing the associated code, here are the Gradle Files.
Project:Gradle
// Top-level build file where you can add configuration options common to all sub-projects/modules.
plugins {
id 'com.android.application' version '7.3.1' apply false
id 'com.android.library' version '7.3.1' apply false
id 'org.jetbrains.kotlin.android' version '1.7.20' apply false
}
Module:Gradle
plugins {
id 'com.android.application'
id 'org.jetbrains.kotlin.android'
}
android {
namespace //anonymized package name
compileSdk 33
defaultConfig {
applicationId //anonymized package name
minSdk 21
targetSdk 33
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
}
buildFeatures{
viewBinding true
}
}
dependencies {
implementation 'androidx.core:core-ktx:1.9.0'
implementation 'androidx.appcompat:appcompat:1.6.0'
implementation 'com.google.android.material:material:1.7.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
}
The Main Activity is very simple - its only interactive element is a button that launches another activity, so I will show the activity it launches. The destination activity is the only other activity in the project so far. The problem occurs early on.
Activity Class
package anonymized package name
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.view.Menu
import android.view.MenuItem
import /*anonymized package name*/.databinding.ActivityExerciseBinding
class ExerciseActivity : AppCompatActivity() {
private lateinit var bindExercise:ActivityExerciseBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
bindExercise = ActivityExerciseBinding.inflate(layoutInflater)
val view = bindExercise.root
setContentView(view)
setSupportActionBar(bindExercise.toolbarExercise).apply {
supportActionBar?.setDisplayHomeAsUpEnabled(true)
supportActionBar?.setHomeAsUpIndicator(R.drawable.ic_back_btn)
supportActionBar?.show()
}
bindExercise.toolbarExercise.setNavigationOnClickListener{
onBackPressedDispatcher.onBackPressed()
}
}
override fun onStart() {
super.onStart()
Log.i("TAG_BIND","$bindExercise")
}
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
menuInflater.inflate(R.menu.menus, menu)
return true
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
return when(item.itemId){
R.id.action_back -> {onBackPressedDispatcher.onBackPressed(); return true}
else -> super.onOptionsItemSelected(item)
}
}
}
Activity Layout
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ExerciseActivity">
<androidx.appcompat.widget.Toolbar
android:id="#+id/toolbarExercise"
android:layout_width="match_parent"
android:layout_height="?android:attr/actionBarSize"
android:theme="#style/ToolbarTheme"
tools:text="label here" />
<TextView
android:id="#+id/tvTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/app_name"
android:layout_below="#id/toolbarExercise"
android:textSize="22sp"/>
</RelativeLayout>
Theme in Reference
<resources>
<--! ... -->
<style name="ToolbarTheme" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
<item name="android:textColor">#color/toolbar_color_control_normal</item>
<item name="android:background">#color/teal_200</item>
<item name="android:text">#string/app_name</item>
</style>
</resources>
The error is simple. At this line of code in the ExerciseActivity.OnStart() method, the line of code that writes to the log, produces this error:
// Line of Code
Log.i("TAG_BIND","$bindExercise")
// Resulting Error at Runtime
kotlin.UninitializedPropertyAccessException: lateinit property bindExercise has not been initialized
Rather, it seems to me that bindExercise is never initialized, even though it is the second line of code in the onCreate() method.
I have tried each of the following strategies to overcome the error:
Refactor Activity Name (Class and Layout)
Invalidate Caches: Clear VCS Caches and Indexes, File System and Local History
Restart IDE
Create New Empty Activity and Map Methods/Properties Manually
Update Module:Gradle implementation androidx:appcompat from 1.5.1 to 1.6.0
The only thing I have not tried is destroying the project and starting from scratch. This seems like a terrible practice in general; starting over like that is like crumbling up an acceptable report because your auditor can't distinguish the kerning on your choice font.
Does anyone have any suggestions on how to debug this?
Thank you.
Related
`I have an error on:
``
package com.example.movietime
import android.content.Intent
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import com.example.movietime.databinding.ActivityRegisterBinding
import com.google.firebase.ktx.Firebase
class RegisterActivity : AppCompatActivity() {
DatabaseReference database = FirebaseDatabase.getInstance().getReference(); // also here with all sentence
// binding
private lateinit var binding: ActivityRegisterBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityRegisterBinding.inflate(layoutInflater)
setContentView(binding.root)
// move to login after click
binding.submitButton.setOnClickListener {
startActivity(Intent(this, LoginActiivty::class.java))
}
}
}
building grade(:app)
plugins {
id 'com.android.application'
id 'org.jetbrains.kotlin.android'
id 'com.google.gms.google-services'
}
android {
namespace 'com.example.movietime'
compileSdk 33
defaultConfig {
applicationId "com.example.movietime"
minSdk 21
targetSdk 33
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildFeatures {
viewBinding true
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
}
}
dependencies {
implementation 'com.google.firebase:firebase-database-ktx'
implementation 'androidx.core:core-ktx:1.9.0'
implementation 'androidx.appcompat:appcompat:1.5.1'
implementation 'com.google.android.material:material:1.7.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
implementation platform('com.google.firebase:firebase-bom:30.0.1')
implementation 'com.google.firebase:firebase-analytics-ktx'
implementation 'com.google.firebase:firebase-auth-ktx'
implementation 'com.google.firebase:firebase-firestore-ktx'
implementation 'com.google.firebase:firebase-firestore'
implementation platform('com.google.firebase:firebase-bom:31.0.2')
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
}
build grade(project)
buildscript {
repositories {
// Check that you have the following line (if not, add it):
google() // Google's Maven repository
}
dependencies {
classpath 'com.android.tools.build:gradle:7.3.1'
classpath 'com.google.gms:google-services:4.3.14'
}
}
// Top-level build file where you can add configuration options common to all sub-projects/modules.
plugins {
id 'com.android.application' version '7.3.1' apply false
id 'com.android.library' version '7.3.1' apply false
id 'org.jetbrains.kotlin.android' version '1.7.20' apply false
}
``
`I'm kind of lost already,
tried this
Unresolved reference:database for Firebase Realtime database in my Kotlin program
but it didnt help either.
any suggestion will be welcome!
Unresolved reference:database for Firebase Realtime database in my Kotlin program
Reconnection the firebase to project and import from begging.`
I actually answered that question but in your case, the problem isn't related to the import but to the name of the class. So you're getting the following error:
Unsolved reference: Databaserefernce
Because there is no class that is called Databaserefernce but DatabaseReference. See the capital R? To solve this, please change the type of the variable to DatabaseReference, add the corresponding import and the error will go away.
Besides that, the way you're initializing the variable is not correct. That's how you do it in Java. In Kotlin you should do it like this:
val db = FirebaseDatabase.getInstance().reference
It seems that my Android Studio is not recognizing the 'androidx.core:core-ktx:1.2.0' package. Android Studio version: 3.6.1
My gradle.properties:
android.useAndroidX=true
# Automatically convert third-party libraries to use AndroidX
android.enableJetifier=true
# Kotlin code style for this project: "official" or "obsolete":
kotlin.code.style=official
My app module build.gradle:
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
android {
compileSdkVersion 29
defaultConfig {
applicationId "cz.nn.example.myapplication"
minSdkVersion 25
targetSdkVersion 29
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_1_8.toString()
targetCompatibility = JavaVersion.VERSION_1_8.toString()
}
kotlinOptions {
jvmTarget = "1.8"
}
}
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'androidx.core:core-ktx:1.2.0'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
}
When I try to use extension functions like:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val manager = systemService<NotificationManager>()
SharedPreferences.edit {
}
}
}
functions systemService<NotificationManager>() and edit are not recognized. What am I doing wrong?
TL;DR
You are using them wrongly
First of all SharedPreferences.edit() extension function is not static and needs an instance of SharedPreferences to be used on. Try this:
val prefs = getSharedPreferences("com.example.yourapp", Context.MODE_PRIVATE)
prefs.edit { putString("myString", "myValue") }
Secondly, the method is called getSystemService, not systemService. So, this will work:
val manager = getSystemService<NotificationManager>()
I've been messing around with Jetpack Compose recently and I had gone through the basic tutorial here. Then I started looking at the Jetnewssample project they have. Now I'm ready to start working on my own project but now when I create a new project in the same parent directory as the Jetnewssample project, (which is working fine) Android Studio can no longer import androidx.ui.core.Text or androidx.ui.core.setContent. I can import other classes from the same location but now I just get an unresolved reference error. This is a new project set to start with an Empty Compose Activity. Here is the code:
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.compose.Composable
import androidx.ui.core.Text
import androidx.ui.core.setContent
import androidx.ui.material.MaterialTheme
import androidx.ui.tooling.preview.Preview
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
MaterialTheme {
Greeting("Android")
}
}
}
}
#Composable
fun Greeting(name: String) {
Text(text = "Hello $name!")
}
#Preview
#Composable
fun DefaultPreview() {
MaterialTheme {
Greeting("Android")
}
}
Here's the module's gradle build file:
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
android {
compileSdkVersion 29
buildToolsVersion "29.0.2"
defaultConfig {
applicationId "com.franklin.sanctified"
minSdkVersion 21
targetSdkVersion 29
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility = 1.8
targetCompatibility = 1.8
}
kotlinOptions {
jvmTarget = '1.8'
}
buildFeatures {
compose true
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'androidx.core:core-ktx:1.1.0'
implementation 'androidx.ui:ui-layout:0.1.0-dev03'
implementation 'androidx.ui:ui-material:0.1.0-dev03'
implementation 'androidx.ui:ui-tooling:0.1.0-dev03'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
}
Update on :May-2021
Add below dependencies in app level Gradle or kts file for set content{ .. }
implementation("androidx.activity:activity-compose:1.3.0-alpha07")
Those seem to be in ui-framework for dev03. Try adding that dependency to your lineup:
implementation "androidx.ui:ui-framework:0.1.0-dev03"
In my case the problem was that I was missing activities integration for compose. setContent is an extension function on ComponentActivity class, defined in package androidx.activity.compose
Just import:
implementation 'androidx.activity:activity-compose:1.4.0'
I'm using androidx navigation architecture along with Kotlin 1.2.71 in Android studio 3.2.1. My fragment code is:
package com.dell.andnav.fragments
import android.os.Bundle
import android.support.v4.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Button
import androidx.navigation.fragment.findNavController
import com.dell.andnav.R
import kotlinx.android.synthetic.main.fragment_welcome.*
/**
* A simple [Fragment] subclass.
* Use the [WelcomeFragment.newInstance] factory method to
* create an instance of this fragment.
*
*/
class WelcomeFragment : Fragment() {
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_welcome, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
detailButton.setOnClickListener {
findNavController().navigate(R.id.action_welcomeFragment_to_detailsFragment)
}
}
companion object {
#JvmStatic
fun newInstance() = WelcomeFragment()
}
}
And layout code is:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/frameLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".fragments.WelcomeFragment">
<Button
android:id="#+id/detailButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/to_detail_fragment"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</android.support.constraint.ConstraintLayout>
My build.gradle is:
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
apply plugin: 'androidx.navigation.safeargs'
android {
compileSdkVersion 28
defaultConfig {
applicationId "com.dell.andnav"
minSdkVersion 21
targetSdkVersion 28
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
androidExtensions {
experimental = true
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
def nav_version = "1.0.0-alpha07"
implementation fileTree(dir: 'libs', include: ['*.jar'])
// implementation 'com.android.support:appcompat-v7:28.0.0'
implementation 'com.android.support.constraint:constraint-layout:1.1.3'
// implementation 'com.android.support:support-v4:28.0.0'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
implementation 'androidx.lifecycle:lifecycle-extensions:2.0.0'
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
implementation 'androidx.multidex:multidex:2.0.0'
implementation 'androidx.appcompat:appcompat:1.0.2'
implementation "android.arch.navigation:navigation-fragment-ktx:$nav_version"
implementation "android.arch.navigation:navigation-ui-ktx:$nav_version"
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
}
repositories {
mavenCentral()
}
When I try to run my code, I get below error:
Unresolved reference. None of the following candidates is applicable because of receiver type mismatch:
public val Activity.detailButton: Button! defined in kotlinx.android.synthetic.main.fragment_welcome
public val Dialog.detailButton: Button! defined in kotlinx.android.synthetic.main.fragment_welcome
public val android.app.Fragment.detailButton: Button! defined in kotlinx.android.synthetic.main.fragment_welcome
public val androidx.fragment.app.Fragment.detailButton: Button! defined in kotlinx.android.synthetic.main.fragment_welcome
public val LayoutContainer.detailButton: Button! defined in kotlinx.android.synthetic.main.fragment_welcome
How can I resolve that error?
Button you are accessing is inside your fragement but your are accessing it directly. You should access it via parent view like we do with java rootview.findViewById() so use
view.detailButton.setOnClickListener {
findNavController().navigate(R.id.action_welcomeFragment_to_detailsFragment)
}
I have faced the same problem with my adapter class and finally problem solved by adding the following code to build.gradle(Module: app) file of the project.
apply plugin: 'org.jetbrains.kotlin.android.extensions'
androidExtensions {
experimental = true
}
Since this new version of Kotlin, the Android Extensions have incorporated some new interesting features like caches in any class
I had this issue and figured out that the root cause was play-services with versions 17.x.x
My fix
Change
google_android_gms_version
in
implementation "com.google.android.gms:play-services-location:$google_android_gms_version"
implementation "com.google.android.gms:play-services-gcm:$google_android_gms_version"
from 17.x.x to 15.0.1
The reason is that play services 17.x.x has dependencies on Androidx
General way
Click the Gradle option in the extreme right panel,
Go to app -> help ->dependencies
Search androidx in the chart. Find out which library has it. Change or modify your gradle accordingly.
Those who can migrate to androidx, that well and good. If you have to keep it at appcompat, then follow the answer.
With androidx, you have to access with itemView
itemView.detailButton
import .view.* like below
import kotlinx.android.synthetic.main.fragment_welcome.view.*
instead of
import kotlinx.android.synthetic.main.fragment_welcome.*
I have two issues with this error.
I mixed receiver type in extension.
import android.widget.Toolbar
fun Toolbar.setMenuItem() : Boolean {
...
}
Then tried to apply this function to Toolbar in a layout. But in XML it was androidx.appcompat.widget.Toolbar.
This function led to the error:
private fun showProgress(view: View? = null) {
(view?.progressBar ?: progressBar)?.visibility = View.VISIBLE
}
Android Studio offered layouts that contained progressBar, and I chose one. But view?.progressBar continued to be red. Then I shortened a header:
private fun showProgress(view: View).
Only after that AS offered layouts. Then I again wrote: private fun showProgress(view: View? = null).
I've created a new Kotlin project in Android Studio, and I'm now trying to use the Fuel HTTP library in that project. However, when I try to use the functions like in the examples on the GitHub readme, I get two errors:
"None of the following functions can be called with the arguments supplied." - on the reference to responseString
"Cannot infer a type for this parameter. Please specify it explicitly." - on each of the arguments to the callback function
This is the code I am using:
package me.myname.morefueltesting
import android.support.v7.app.ActionBarActivity
import android.os.Bundle
import android.view.Menu
import android.view.MenuItem
import com.github.kittinunf.fuel.Fuel
public class MainActivity : ActionBarActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
/* First error /--Second errors--\
| | | |
\/\/\/\/\/\/\/ \/\/\/\ /\/\/\/\ /\/\/\ */
Fuel.get("http://httpbin.org/get").responseString({request, response, result ->
// Some callback code here
})
}
}
My build.gradle:
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
android {
compileSdkVersion 22
buildToolsVersion '22.0.1'
defaultConfig {
applicationId "me.myname.morefueltesting"
minSdkVersion 15
targetSdkVersion 22
versionCode 1
versionName "1.0"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
sourceSets {
main.java.srcDirs += 'src/main/kotlin'
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'com.android.support:appcompat-v7:22.1.0'
compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
compile 'com.github.kittinunf.fuel:fuel-rxjava:1.3.1'
compile 'com.github.kittinunf.fuel:fuel-android:1.3.1'
}
buildscript {
ext.kotlin_version = '1.0.3'
repositories {
mavenCentral()
}
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
repositories {
mavenCentral()
}
How can I resolve these errors?
There are several overloads of responseString the one you see used a lot in Readme has following signature:
fun responseString(
charset: Charset = Charsets.UTF_8,
handler: (Request, Response, Result<String, FuelError>) -> Unit): Request
As you can see the first parameter has a default value. Notice also that the second (and at the same last) argument is a lambda that has no default value. If you choose to use a default parameter value (charset) you need to also use default values for subsequent parameters or you'll need to use named arguments:
Fuel.get("http://httpbin.org/get").responseString(handler = {request, response, result ->
// Some callback code her
})
Because:
In Kotlin, there is a convention that if the last parameter to a
function is a function, that parameter can be specified outside of the
parentheses
You can also use the method as specified in Readme but without parentheses:
Fuel.get("http://httpbin.org/get").responseString {request, response, result ->
// Some callback code her
}
Got it - I was using an extremely old version of Android Studio (1.1 when latest is 2.1!). Updating Android Studio fixed all of the errors I mentioned, as well as some others that I encountered while tinkering where some built-in SDK functions were missing.