today I started a new Android project with Kotlin support. But as soon as I launch it on my phone, it is disconnected from Wi-Fi (Application has INTERNET and ACCESS_NETWORK_STATE permissons but no socket code yet). Here is the code:
package org.arch.cast
import android.os.Bundle
import android.support.v7.app.AppCompatActivity
class MainActivity : AppCompatActivity() {
internal var dummy = 10
internal var channel = 20
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
}
After experimenting a bit I noticed that one of my variables wasn't marked as "not used" even though it was not used.
This is the only class the project contains right now, no other service or activity exists so nothing is referring channel variable anywhere in the project. I also added a dummy variable to show that it is marked as not used. I noticed that the problem was its name and it was actually not defining it but altering another variable from a library I didn't import. And since it was related to Wi-Fi, phone was disconnecting.
Sure everything works when I change the variable name but this should not be the solution, it is only a temporary workaround. So the question is, how can I prevent Kotlin from altering the variable and make it actually define it in my class?
Related
I am working on adding data persistence to an app using the Room library, based on this documentation. My database only has one column where a String corresponding to a user-selected radio button is to be placed. However, as soon as I attempt to insert a new object (in this case, an Attempt), it gives me the following error:
java.lang.ClassCastException: android.app.Application cannot be cast to com.example.mathreps.MathRepsApplication.
I believe this error comes from the following block of code within my Rating fragment:
private val dataViewModel: MathRepsViewModel by activityViewModels {
MathRepsViewModel.MathRepsViewModelFactory(
(activity?.application as MathRepsApplication).database
.attemptDao()
)
}
Which relates to a different class called MathRepsApplication
class MathRepsApplication: Application() {
val database: AttemptRoomDatabase by lazy {AttemptRoomDatabase.getDatabase(this)}
}
Since this problem most likely relates to multiple classes and packages, here is the link to the repository for the project.
My attempts to fix this have been unsuccessful, with them mostly consisting of heavily reviewing the database implementation and not much else, as I don't exactly know where to start.
I followed multiple tutorials on how to implement this new nonsense.
I removed
apply plugin: `kotlin-android-extensions`
from gradle, added:
android {
...
buildFeatures {
viewBinding true
}
}
and then in activity (not MainActivity but another one because it's the first one that creates error on rebuild):
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
totorials are showing that the views have to be used this way now:
binding.whatEverView
but I still have unresolved reference on those views.
Now I'm wondering if the correct class gets automatically imported which is:
import de.blaa.blaaaa.databinding.ActivityMainBinding
None of the tutorials are showing what actual class supposed to be imported so is this the correct one? What am I missing?
Check that the id of "whateEverView" doesn't have a leading underscore or something.
In my case, I found that my field had an id of "_what_ever_view" in the layout xml. Changing it to "what_ever_view" fixed it.
Not sure if the problem is limited to leading underscores, or even if it's a specific version of the plug-in, but it does appear to be a bug. In my case, the issue field appears totally valid during code editing (code completion knows about the field), but the "unresolved" issue appears during build time.
In Java, we have the package protected (default) modifier for classes, which allows us to have many classes in a single package but exposes only a few and keeps the logic encapsulated.
With Kotlin this doesn't seem to be the case. If I want a few classes to be visible to each other but no further, I have to use a private modifier which limits visibility to a single file.
So if you want 10 classes in a package but only one of them to be public, you'd have to have one huge file with all the classes in it (and private all over the place).
Is this normal practice or there is a way to achieve some similar modularity in Kotlin?
I don't understand: if they have the notion of a package, why did they get rid of package protected access?
Update: We might have package protected visibility after all
see the discussion here
Update: If you read through the discussion and still think this is a must-have feature for the language, please vote here
Kotlin, compared to Java, seems to rely on packages model to a lesser degree (e.g. directories structure is not bound to packages). Instead, Kotlin offers internal visibility, which is designed for modular project architecture. Using it, you can encapsulate a part of your code inside a separate module.
So, on top level declarations you can use
private to restrict visibility to the file
internal to restrict visibility to the module
At this point, there is no other option for visibility restriction.
As a workaround for me on android I've created #PackagePrivate annotation and lint checks to control access. Here you can find the project.
Lint checks are obviously not that strict as compiler checks and some setup needed to fail the build on errors. But android studio picks up lint checks automatically and shows error immediately while typing. Unfortunately I don't know a way to exclude annotated members from autocomplete.
Also, as lint is a purely compile-time tool, no checks at runtime performed.
As #hotkeys points out, you can use the internal keyword in a module or you can put all classes that would otherwise belong in a package inside a single file, but sticking several classes in a file may be a questionable design decision.
For me, the package visibility is helpful for its documenting value. I want to know what public interface some package is presenting to the rest of the project, hide factory implementation classes and so on.
So even if it's possible to access package-private classes and methods in Java, I still choose to use the package modifier.
For this I created a project with a single annotation:
package com.mycompany.libraries.kotlinannotations;
import static java.lang.annotation.ElementType.CONSTRUCTOR;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.SOURCE;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
#Documented
#Retention(SOURCE)
#Target({ TYPE, METHOD, CONSTRUCTOR })
/**
* Use in Kotlin code for documentation purposes.
*
* Whenever a Kotlin class or method is intended to be accesible at package level only.
*
*/
public #interface PackagePrivate {
}
Then I can use this annotation in any Kotlin project.
The second step, which I haven't done yet, is creating a PMD rule to enforce this with maven (or any other build tool for that matter) and also be able to see violations of the rule in my IDE with the pmd plugin.
There no is full Kotlin support in pmd at this moment but it seems to be expected at some point.
A near-replacement for package private visibility is available using the opt-in requirements feature (credit to pdvrieze on Kotlin discussions). This is the annotation syntax typically used to flag experimental features in an API.
To use it, create an annotation denoting package private declarations:
#RequiresOptIn(message = "Only to be used in MyPackage")
#Retention(AnnotationRetention.BINARY)
annotation class MyPackagePrivate
Then annotate any methods you want to be package private with it:
#MyPackagePrivate
fun aPackagePrivateMethod() {
// do something private within a package
}
In this way a warning will be generated on any method that calls the annotated method unless the calling method is itself annotated with the corresponding #OptIn annotation, here shown at class level:
#OptIn(MyPackagePrivate::class)
class AClassInThePackage {
fun userOfPackagePrivateMethod() {
aPackagePrivateMethod()
}
}
This, then, produces a similar effect to Java's package private, except that calling methods need to explicitly opt in to using a package private declaration.
If it is desired to generate an error rather than a warning, the level parameter of #RequiresOptIn can be specified:
#RequiresOptIn(level = RequiresOptIn.Level.ERROR, message = "Only to be used in MyPackage")
// annotation declaration as before
Package-based protection is pointless in Kotlin because packages themselves are unprotected
In Java, package was tied to directory structure. So if you put your classes in com\example\yoursecretengine, any attempt (deliberate or accidental) to add a rogue class there would be easily noticeable. This is the kind of security we've depended on.
Kotlin removes the ties between directory and package, so I can put my class in "my" directory (eg.src\java\pl\agent_l\illegalaccess) yet declare its package as com.example.yoursecretengine - and gain access to all the properties you've meant as package private.
In fact, a Kotlin project works perfectly without ANY package declarations. This only highlights that packages are "more what you'd call guidelines than actual rules". They're a convenience feature, useful only to unclutter namespace and nothing more.
Relevant quotes from kotlinlang:
unlike many other languages, Kotlin packages do not require files to have any specific locations w.r.t. itself; the connection between a file and its package is established only via a package header.
And:
an absence of a package header in a file means it belongs to the special root package.
TL;DR
These object : someClass{ } anonymous objects can't access itself via this (which results the outer object). How can I access it?
Longer explanation:
For my Fragment I need a PreDrawListener. I call this in onCreateView. When executing, I wanted to remove the listener afterwards. So the Java way of doing would suggest something like this
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
val treeObserver = layout.viewTreeObserver
treeObserver.addOnPreDrawListener(object : ViewTreeObserver.OnPreDrawListener {
override fun onPreDraw(): Boolean {
layout.viewTreeObserver.removeOnPreDrawListener(this)
...
}
}
The problem is, when taking a look at the removeOnPreDrawListener(this) the this object is not the listener but myFragment$onCreateView$1#f019bf0
Alternatively I could access this#MyFragment which returns the reference to the Fragment directly.
Still, none of these options seems to be my PreDrawListener. How can I access it from inside (if at all)?
I honestly don't see your problem.
this inside an anonymous refers to the class itself, but they never have names. You can't create an anonymous class with a name. To demo this, I wrote some sample code:
class TheClass{
fun run(){
val anon = object: Runnable {
override fun run() {}
}
println(anon::class.java.simpleName)
println(anon::class.java.name)
}
}
Which prints:
run$anon$1
com.package.TheClass$run$anon$1
Now, this is nice and all, but it still doesn't look like yours. But you see it matches the containing class, method, variable, and finally the dollar sign denoting that it's an anonymous inner class. That applies to the second, which is the full one. The first just prints the short name, which is the method, var name, and again the dollar sign that shows it's anonymous function.
If you're interested in why the dollar sign with a number appears, see this. T
Let's expand that and ditch the variable. Obviously, this is horrible code (and far from memory-efficient, but it's a demo so it doesn't matter):
class TheClass {
fun run(){
println(object: Runnable {
override fun run() { }
})
}
}
This prints, and matching your pattern:
com.package.TheClass$run$anon$1
You've seen the pattern; now you can start "decoding" the hash you got:
myFragment // inside myFragment
$onCreateView // Inside a function
$1 // There is an anonymous class with a specific identifier
#f019bf0 // This is standard everywhere; just look up Object.toString()
What I just tried to prove is: this does refer to the anonymous function you create. Anonymous functions are, well, anonymous. They don't have names. They use $number as identifiers. So if you have this code:
treeObserver.addOnPreDrawListener(object : ViewTreeObserver.OnPreDrawListener {
override fun onPreDraw(): Boolean {
layout.viewTreeObserver.removeOnPreDrawListener(this)
...
}
}
this will refer to the listener, even though printing the class may print stuff that looks confusing. If there's something that's broken, it's not because of this not referring to the listener (because it does)
Also, your code compiles fine. There's no type mismatch in there either. If it referred to a different object, it wouldn't work if you passed this to a method that requires a OnPreDrawListener.
You would get a different result with the same code in Java. This is because Kotlin compiles anonymous functions as Class$function$number, where as Java compiles it to Class$number. If it's in a nested class, it will appear as Outer$Inner$function$number in Kotlin, and Outer$Inner$number in Java.
It's a difference in the compiler that results in different names; Java excludes the function, where as Kotlin includes it. It's in the .class filename, so if you build your project and look at the file names in a file explorer for whatever OS you have (Do not look in IntelliJ. It will decompile the files for you. And remember, you're just looking for the name, which IntelliJ messes up by merging the .class files into a single one to match the original source)
Just as final meta, I do print the class instead of printing the object. Interfaces do not have an overridden toString method, which means it defaults to the one on Object, which returns getClass().getName() + "#" + Integer.toHexString(hashCode()); (original code can be found here). println(this) is the same as println(this.toString()), which calls the toString method in Object, which prints the class name. println(this) is the same as printing the object or printing the class
In the last year I've become a mobile developer and a functional programming admirer.
In each of the mobile arenas there are components with lifecycle methods that make up the meat of the app. The following will use Android and Kotlin as examples, but the same applies to iOS and Swift.
In Android, there are Activity's with lifecycle methods like onCreate(). You might also define a function, onButtonClicked(), which will do exactly what the name describes.
For the purposes of the question, let's say there's a variable defined in onCreate() that is used in a button click handler onButtonClickedPrintMessageLength() (This is usually the case - onCreate() is essentially Activity's setup method).
The example class would look like this:
class ExampleActivity: Activity() {
var savedStateMessage: String? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
savedStateMessage = "Hello World!"
}
fun onButtonClickedPrintMessageLength() {
System.out.println(savedStateMessage?.length)
}
}
Notice the declaration of savedStateMessage as a String? (nullable string) and the use of ?. (null safe call). These are required because the compiler cant guarantee that onCreate() will be called before onButtonClickedPrintMessageLength(). As developers though, we know that onCreate will always be called first* **.
My question is how can I tell the compiler about the guaranteed order of these methods and eliminate the null checking behavior?
* I suppose it's possible to new up our ExampleActivity and call onButtonClickedPrintMessageLength() directly, thus sidestepping the Android framework and lifecycle methods, but the compiler/JVM would likely run into an error before anything interesting happened.
** The guarantee that onCreate is called first is provided by the Android framework, which is an external source of truth and might break/function differently in the future. Seeing that all Android apps are based on this source of truth though, I believe it's safe to trust.
Although this won't answer your actual question, in Kotlin you can use lateinit to tell the compiler that you'll initialize a var at a later point in time:
lateinit var savedStateMessage: String
You'll get a very specific UninitializedPropertyAccessException if you try to use this variable before initializing it. This feature is useful in use cases like JUnit, where you'd usually initialize variables in #Before-annotated method, and Android Activitys, where you don't have access to the constructor and initialize stuff in onCreate().
As mentioned in another answer, lateinit is available as an option to defer initialization to a later point in a guaranteed lifecycle. An alternative is to use a delegate:
var savedStateMessage: String by Delegates.notNull()
Which is equivalent, in that it will report an error if you access the variable before initializing it.
In Swift this is where you would use an implicitly-unwrapped Optional:
class Example: CustomStringConvertible {
var savedStateMessage: String! // implicitly-unwrapped Optional<String>
var description: String { return savedStateMessage }
init() {
savedStateMessage = "Hello World!"
}
}
print(Example()) // => "Hello World!\n"
By using the operator ! at the end of String in the second line of the example you are promising that the variable will be set before it can be used. This is accomplished in the init method of the example. It's still an Optional but code can treat it as a String since it will be automatically unwrapped before each use. You must take care that the variable is never set to nil when it might be accessed or a runtime exception may be generated.