Debug reified Kotlin under SDK 25 - kotlin

I can not use the step by step tracing with reified functions, under Android SDK 25.
I create an emulator with SDK 29, everything is OK, i can put breakpoints and trace step by step.
I create an emulator with SDK 25, debug tracing is no longer available in reified function. I did the same test with a physical device running with Android 7.1.1, there is the same problème.
Under SDK 25 :
I put break points on line 13 and 18
When the debuger reachs the line 13, i press F7 (step in) or F8 or F5
The debuger jumps immediately to line 20 and never stop or enter the function test
1 class MainActivity : AppCompatActivity() {
2
3 private lateinit var appBarConfiguration: AppBarConfiguration
4 private lateinit var binding: ActivityMainBinding
5
6 override fun onCreate(savedInstanceState: Bundle?) {
7 super.onCreate(savedInstanceState)
8
9 binding = ActivityMainBinding.inflate(layoutInflater)
10 setContentView(binding.root)
11
12 binding.fab.setOnClickListener { view ->
13 test<String>("test") // Call the inline function
14 }
15 }
16
17 inline fun <reified T : Any> test(value: T): Boolean {
18 return true
19 }
20 } // Debuger jumps here
This peace of code is made for test, i got the same issue with more complex code.
Thank you.

Related

Viewmodel SavedStateHandle data lost after process death

I am trying to use savedStateHandle in my ViewModel and test it. My simple case is that I'm just storing an Int value in the SavedStateHandle and trying to get it again after the process death. But its not working at all. I am using the following dependency
implementation 'androidx.activity:activity-ktx:1.2.0-alpha08'
implementation "androidx.fragment:fragment-ktx:1.3.0-alpha08"
Below is my Fragment which is having one button and one TextView. When I click the button, number 5 is stored in the savedStateHandle of the ViewModel and then the same was observed via the getLiveData method of the savedStateHandle and the number is displayed in the TextView. So, after process death, it should correctly restore the value of 5 and display it in the text view. Following is my fragment code
class FirstFragment : Fragment() {
private val viewModel by lazy{
ViewModelProvider(this).get(FirstFragmentVM::class.java)
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_first, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
button_first.setOnClickListener {
viewModel.rememberNumber(5)
}
observeViewModel()
}
private fun observeViewModel(){
viewModel.rememberedNumber.observe(viewLifecycleOwner){
textview_first.text = it.toString()
}
}
}
and the following is my ViewModel code
#ExperimentalCoroutinesApi
#FlowPreview
class FirstFragmentVM(savedStateHandle: SavedStateHandle) : ViewModel() {
companion object{
private const val KEY_NUMBER_TO_REMEMBER="number:to:remember"
}
private val savedState=savedStateHandle
val rememberedNumber=savedState.getLiveData<Int>(KEY_NUMBER_TO_REMEMBER)
fun rememberNumber(number:Int){
savedState.set(KEY_NUMBER_TO_REMEMBER,number)
}
}
When run this app and click the button, the number 5 is stored in the savedStateHandle and its displaying "5" correcly in the text view. But when I put the app in the background and kill the process using adb and then restart the process from the recent screen, the entire app is restarted and its not showing the remembered number in the textView. Instead, its showing "Hello" which I set in the layout xml. I am killing the process as follows
adb shell
am kill <package name>
Anyone kindly help me why its not at all working for me? What am I doing wrong here?
Finally, I found the reason. The app restarts if we kill the app process after launching it directly from the IDE. Instead, If I close the app by swiping it from recents, launch it from the app drawer and then killing it via adb works and restores the state of the app perfectly.

IntelliJ IDEA - Kotlin: Unresolved reference: eq method

Am using IntelliJ IDEA 2019.1.2 (Ultimate Edition) with Kotlin (kotlinc-jvm 1.3.31) on macOS Mojave 10.14.5.
When I created a Kotlin JVM project and added a Kotlin file entitled "Nullability.kt" with the following code (extension function with a main() method):
fun List<Int>.allNonZero() = all { it > 0 }
fun main() {
val list1 = listOf(1, 2, 3)
list1.allNonZero() eq true
}
IntelliJ IDEA highlights "eq" in red and it states:
Kotlin: Unresolved reference: eq
How to resolve this from within IntelliJ IDEA?
Found it, inside the Coursera course, Kotlin has a Playground where the code is hidden but you can expand it and view it by clicking on the + sign.
infix fun <T> T.eq(other: T) {
if (this == other) println("OK")
else println("Error: $this != $other")
}

I am using android studio and the mainactivity class is .kt type. I keep having this error: Expecting member declaration

I am using android studio and I have some issues with this piece of code. Could someone tell me what I am doing wrong?
The system keeps telling me "Expecting member declaration."
This is the code
class MainActivity: AppCompatActivity() {
class TextView totalTextView; //This is where I am having the error
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
setSupportActionBar(toolbar)
I am assuming you are trying to create a totalTextView variable. In kotlin you can declare a variable like this
lateinit var totalTextView : TotalTextView
This is not right way to create or define object of TextView.
1 > var totalTextView : TextView ? = null
1 > lateint var totalTextView : TextView
In kotlin, No need to define id of ViewGroup items , avoid to define the instance of view item when you are using kotlin

How to mock a private function in android test with MockK?

I can't seem to mock private functions in android tests. I'm also using the all-open plugin for pre-P testing. On non-android tests it runs with no problems. I figured it should work on android too, because it's marked on MockK-android. Is this not implemented or am I missing something obvious?
androidTestImplementation "io.mockk:mockk-android:1.8.7"
#OpenForTesting
class A {
fun publicFun() = privateFun()
private fun privateFun() {}
protected fun protectedFun() {}
}
#Test
fun privateFunctionMock() {
val spy = spyk<A>()
val mock = mockk<A>()
val a = A()
val functions = a::class.functions // size -> 6
val spyFunctions = spy::class.functions // size -> 5
val mockFunctions = mock::class.functions // size -> 5
every { spy["privateFun"]() } returns Unit
a.publicFun()
}
Fails with Exception, because the private function is missing.
io.mockk.MockKException: can't find function privateFun() for dynamic call
Subclassing is employed to create mocks and spies for pre-P android instrumented tests. That means basically private methods are skipped because it is not possible to inherit them. That way counters are not counting private methods.
InternalPlatformDsl.dynamicSet(autoBannerViewPagerMock, "mBannerList", list)
every { autoBannerViewPagerMock.invoke("loadCoverImage") withArguments listOf(any<Int>(), any<Int>(), any<ImageView>(), any<stMetaBanner>()) } returns Unit

Kotlin IllegalAccessError with += and -= for delegated Interface

I've defined this class:
class NeverNullMap<K, V>(private val backing: MutableMap<K, V> = mutableMapOf(), val default: () -> V): MutableMap<K, V> by backing {
override operator fun get(key: K): V = backing.getOrPut(key, default)
}
And I can use it perfectly fine like this:
fun main(args: Array<String>) {
val myMap = NeverNullMap<String, Int> {0}
println(myMap["test"])
myMap["test"] = myMap["test"] + 10
println(myMap["test"])
}
as expected the output is:
0
10
But when I try to change it to:
fun main(args: Array<String>) {
val myMap = NeverNullMap<String, Int> {0}
println(myMap["test"])
myMap["test"] += 10
println(myMap["test"])
}
I get:
Exception in thread "main" java.lang.IllegalAccessError: tried to access method kotlin.collections.MapsKt__MapsKt.set(Ljava/util/Map;Ljava/lang/Object;Ljava/lang/Object;)V from class Day08Kt
at Day08Kt.main(Day08.kt:10)
Why is this happening?
Edit:
Digging a bit into decompiled code both get compiled to completly diffrent code.
In the working version without the += it gets compiled to:
Map var2 = (Map)myMap;
String var3 = "test";
Integer var4 = ((Number)myMap.get("test")).intValue() + 10;
var2.put(var3, var4);
The non working version gets compiled to:
MapsKt.set(myMap, "test", ((Number)myMap.get("test")).intValue() + 10);
So it calles this function: https://github.com/JetBrains/kotlin/blob/1.2.0/libraries/stdlib/src/kotlin/collections/Maps.kt#L175
I still have no idea why that produces the Error, just why the first version behaves diffrently.
Edit: YouTrack link to the report
Edit: yes, this is a bug, it has been merged with KT-14227:
Incorrect code is generated when using MutableMap.set with plusAssign operator
After compilation (or decompilation, in this case), MapsKt.set is turned into a private method:
#InlineOnly
private static final void set(#NotNull Map $receiver, Object key, Object value) {
Intrinsics.checkParameterIsNotNull($receiver, "$receiver");
$receiver.put(key, value);
}
This explains the IllegalAccessError.
Now, as to why it is private, I'm only speculating, but I feel like it may be due to this:
#usbpc102 pointed out that #InlineOnly is indeed the reason for the method being private.
#InlineOnly specifies that the method should never be called directly:
Specifies that this function should not be called directly without inlining
so I feel like this is a case where the call to set should have been inlined, but it was not.
Had the call been inlined, you would have ended up with compiled code that is practically identical to the working version, since the method only contains a call to put.
I suspect this is due to a compiler bug.