Android "com.android.internal.util.Predicate" deprecated - android

I just change my compile sdk version from 27 to 28 , after that am getting an issue because of deprication
com.android.internal.util.Predicate
as google developer forum say i changed it to "java.util.function.Predicate " but that time apply() is not working.
Is there any alternate function for apply()

see the Java SE documentation ...it uses a type parameter & a functional interface:
Interface Predicate<T>
Type Parameters: T - the type of the input to the predicate
Functional Interface: This is a functional interface and can therefore be used as the assignment target for a lambda expression or method reference.
as well as the warning in the Android SDK documentation:
This must not be used outside frameworks/base/test-runner.
for example:
Predicate<Integer> greaterThanTen = (i) -> i > 10;
Predicate<Integer> lesserThanTwenty = (i) -> i < 20;
boolean result = greaterThanTen.and(lesserThanTwenty).test(15);
rather complex methods assigned to the functional interface might provide more sense - because else, this is a quite complicated way of formulating this (without improving the readability too much):
boolean result = 15 > 10 && 15 < 20;

Related

Why is there no ClosedRange IN ClosedRange Operator in Kotlin?

Let val a, b, x, y: LocalDate.
Then a..b in x..y is no valid expression: ClosedRange in ClosedRange is undefined.
However, (a..b).toRange() in (x..y).toRange() does work since Range in Range is defined.
Except when b < a or y < x since ranges can't be negative.
Please note that i'm developing for Android, which is where the .toRange() originates: androidx.core/core-ktx
3 Questions arise
Is this an oversight of the android / kotlin team?
Is this a deliberate decision? (e.g. because of some unintuitive behavior)
in case it's a deliberate decision: how to best circumvent it?
ClosedRange is part of the Kotlin standard library. Range is part of Android's SDK. These two libraries are made by different companies and were made with different goals in mind, so you can't necessarily call it an oversight. Maybe the Kotlin developers decided the meaning of a range being in another range might be ambiguous, and the Android developers didn't. Or maybe the Kotlin developers have a higher criteria for what functions are useful enough to include in the standard library.
One difference between the two classes is that the Android Range class forbids a range with the start value higher than the lower, but Kotlin ClosedRange allows it. This makes the concept of a ClosedRange containing another more ambiguous than with Ranges. What would it mean for a negative-direction ClosedRange to be in another ClosedRange? It's empty, but it has a span.
I'm not sure what you mean by circumventing it. You can define your own extension function for ClosedRange if you want, with behavior that depends on how you want to interpret the meaning of an empty range being contained.
operator fun <T: Comparable<T>> ClosedRange<in T>.contains(other: ClosedRange<out T>): Boolean =
other.start in this && other.endInclusive in this
// or
operator fun <T: Comparable<T>> ClosedRange<in T>.contains(other: ClosedRange<out T>): Boolean =
other.isEmpty() || (other.start in this && other.endInclusive in this)
// or
operator fun <T: Comparable<T>> ClosedRange<in T>.contains(other: ClosedRange<out T>): Boolean =
(other.isEmpty() && (other.start in this || other.endInclusive in this)) ||
(other.start in this && other.endInclusive in this)
Disclaimer: I'm not an Android developer and have no experience with androidx.core, so take my answer with a pinch of salt.
So assuming that you can do a..b to create a ClosedRange (which is something not available by default in the Kotlin stdlib, but maybe core-ktx defines its own extension for that), according to the Kotlin documentation, x in y gets translated to y.contains(x). Now, ClosedRange defines some contains methods, but none of them accepts another ClosedRange as a parameter, hence your error.
Now, apparently the Android stdlib defines its own concept of Range, which is unrelated to Kotlin's ClosedRange (as one does not extend the other). However, core-ktx defines a function to transform a ClosedRange to a Range, and that function is .toRange(). In addition to that, Range defines a contains(Range) method, hence why the second example compiles correctly.
So to summarise: Kotlin doesn't allow (1) to create ranges of dates by default, and (2) to check if one range is fully included in another range. However, you can easily overcome (1) by creating your own function to create a ClosedRange for dates (by creating a rangeTo extension function), and (2) by creating your own contains(Range) function.
Coming back to why a..b works when using core-ktx, I can't find a satisfactory answer. That library contains a rangeTo extension function to create a range out of any Comparable (and LocalDate is-a Comparable), but that function returns a Range, not a ClosedRange, so I'm not sure why a..b in x..y doesn't work in the first place.

Android Studio 4.2.2 - Why debbuger doesn't evaluate parameter in a inner funcion?

Android Studio 4.2.2 evaluates a local and global variable, but doesn't evaluate parameter funcion when is inside a inner function.
Until the previous version this worked perfectly.
fun a(p:param) {
fun b(){
var v = p+1 // Here
}
}
Suppose that one try to evaluate the parameter p in the line with comment
// Here with Alt F8
The message in evaluate window is
Cannot find the local variable 'p' with type
This hurts a lot because it forces you to replicate the parameter as a local variable in each routine to be visible in the debugger.
var p = p
Has anyone noticed this? Is there any workaround?
Notice that Variables windows display a parameter with $ prefix, but it also doesn't work in evaluate window.
I've posted this issue in JetBrains.
First things first:
Is there any workaround?
Yes, bind the parameter p to a local variable inside b:
fun a(p: Param) {
fun b() {
val p = p
var v = p + 1
}
}
and it will all work as expected.
The root cause is slightly more convoluted.
Kotlin grew up on a language tool chain tied very closely to the IntelliJ language plug-in for Kotlin. The original JVM compiler was a code generator that consumed the data structures of semantic information used by the IntelliJ language plug-in for diagnostics, quick fixes, and so on.
This architecture was very good for providing language support to an IDE, but less so for building a fast batch compiler.
With Kotlin 1.5, the "IR backend" was enabled as the default code generator for JVM. It uses a more traditional compilation approach of gradually translating an abstract syntax tree (AST) to progressively simpler intermediate languages before outputting JVM byte code.
With this change, a number of new compilation strategies were implemented. In particular, in the old strategy, local functions were treated as lambdas bound to a local variable. Their free variables were recorded in the state of the allocated Function object at the declaration site. When the local function is called, it translates to a call to invoke on that function object. End of story.
In the new approach, local functions are lifted into private static functions on the same class as the outer function. Free variables in the local function are closed by parameters to that lifted function, and instead of recording them at the declaration site in a lambda object, they are passed at the call site as arguments.
In your example. the p is free in the inner function b, so an additional parameter $p is added to b.
While this works for "release builds", the surrounding tooling has not caught up until recently. The "Evaluate Expression..." mechanism has been hit particularly hard, as it's quite sensitive to the layout and shape of the resulting JVM byte code.
In this specific case, it was a matter of adjusting the mechanism in the debugger that maps free variables of the fragment to local variables at the breakpoint. With this change aimed at 2022.3, you should hopefully stop noticing this specific bug, and a host of other improvements as a new and revised version of the evaluation mechanism ships.

Is there an annotation that denotes a max Android API version?

The annotation #RequiresApi is helpful for requiring that the annotated element is only called on the given API level or higher. However, there does not appear to be a corresponding annotation for requiring that the annotated element is only called on the given API or lower.
For example, given something like:
#RequiresMaxApi(28) // or #DeprecatedSinceAndroid(29)
fun doSomethingWithExternalStorage() {
val dir = Environment.getExternalStorageDirectory() // This is deprecated in API 29
// ...
}
Calling doSomethingWithExternalStorage() from code that does not include a check like:
if (VERSION.SDK_INT < 29) {
doSomethingWithExternalStorage()
}
Without the above API check, doSomethingWithExternalStorage() would display a lint error/warning, similar to how #RequiresApi does.
From my understanding, this is also similar to how #DeprecatedSinceKotlin works.
Is there an existing annotation that meets these requirements, or is there another way to achieve the desired result?

Does Kotlin guarantee that a range check doesn't instantiate a Range?

In my Android app, I wrote
return x >= rangeStart && x <= rangeEnd
IntelliJ has an inspection that wants me to change this to
return x in rangeStart..rangeEnd
however, since this code is on the critical path of high-volume event handling, I can accept the transformation only if I know for sure that the second form won't create any garbage. Is there such a guarantee in Kotlin?
You can check the bytecode generated by the Kotlin compiler yourself by searching actions and typing in "Show Kotlin Bytecode", or from the menu via Tools -> Kotlin -> Show Kotlin Bytecode.
Optimizing range checks on primitives (Int, Double, etc) is a pretty trivial thing to do, so you'll find that the Kotlin compiler always does the optimization for you with these types. If you have just a few of these on your critical code path, you can check that it happens by hand to feel safe about using ranges.
The documentation is brief about this, but it does say:
Range is defined for any comparable type, but for integral primitive types it has an optimized implementation.
Example from here
if (i in 1..10) { // equivalent of 1 <= i && i <= 10
println(i)
}
I think it's language "Sugar" and it's equals!

Kotlin Extension Functions suddenly require api level 24

I just noticed this lint error:
Call requires API Level 24 (current min is 19) java.util.map#foreach
when I use the extension function forEach on a MutableMap in Kotlin.
This didn't happen when I wrote the line, but its there now.
And I'm not seeing this error on my other machine.
What you are using is not kotlin.collections.MutableMap.forEach.
What you are using seems to be Map.forEach in Java 8.
Refer to this article:
http://blog.danlew.net/2017/03/16/kotlin-puzzler-whose-line-is-it-anyways/
This seems to be a common mistake.
Java 8 is well-supported from Android API level 24.
For short, do not use forEach like map.forEach { t, u -> Log.i("tag", t + u) } (this is using Java 8 API, which does not work for Android API level <= 23).
Use it like map.forEach { (t, u) -> Log.i("tag", t + u) } (this is using Kotlin API).
(Not two parameters. Just one parameter that is a pair.)
This also happens in a list even tho I'm using I need to use:
list.iterator().forEach {}
the key is use iterator() before forEach.
Ran into this because the map a dependency provided was a Java 8 map, so the forEach was linted as the Java 8 version, no matter how I grouped my parameters in the lambda signature (one, two -> vs (one, two) ->). Best solution I could find was using an explicit import with an alias (import kotlin.collections.forEach as kForEach). The alias keeps optimize imports from removing the explicit import.
Map.forEach is supported in Java 8 and its support in Android started from API 24

Categories

Resources