27

I'm experiencing a pretty strange thing in Kotlin. I have

var myClipboard = getSystemService(CLIPBOARD_SERVICE) as ClipboardManager?
var myClip: ClipData? = ClipData.newPlainText( /* my code */ )

As a var variable, I should be able to reassign his value, but when I do

myClipboard?.primaryClip = myClip

It gives me the error

Val cannot be reassigned

The strangest things is that I'm using this code by weeks and it always worked. It stopped working today when I updated to API 29

This is my build.gradle android{}

    android {
    compileSdkVersion 29
    defaultConfig {
        applicationId "com.arfmann.pushnotes"
        minSdkVersion 23
        targetSdkVersion 29
        versionCode 16
        versionName "1.6"
        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled true
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
}
Arfmann
  • 684
  • 9
  • 30
  • 1
    `myClip` is a `var`, `myClipboard` is a `var`. You are trying to set `myClipboard?.primaryClip`, which is neither of those. Still, your syntax should work. Try switching it to `myClipboard?.setPrimaryClip()` and see what you get. – CommonsWare Jul 20 '19 at 21:32
  • 2
    The error is referring to `primaryClip` and not `myClipboard`. – forpas Jul 20 '19 at 21:33

3 Answers3

39

As seen in the ClipboardManager documentation, getPrimaryClip returns a ClipData? (i.e., a nullable ClipData) while setPrimaryClip() takes a ClipData - a non-null ClipData.

Kotlin does not support var property access when the types are different (and nullability is an important part of Kotlin typing) therefore Kotlin can only give you effectively the val equivalent when you call primaryClip.

The nullability annotation on setPrimaryClip was added in API 29, which is why the behavior is different once you upgrade your compileSdkVersion.

To set the primary clip, you must explicitly use setPrimaryClip() with a non-null ClipData or, on API 28+, use clearPrimaryClip() to completely clear the primary clip.

ianhanniballake
  • 191,609
  • 30
  • 470
  • 443
10

Use it like this

val clipboard = ctx.getSystemService(CLIPBOARD_SERVICE) as ClipboardManager
val clip = ClipData.newPlainText("Beacon infos", it.toJson())
clipboard.setPrimaryClip(clip)
Saurabh Yadav
  • 121
  • 1
  • 4
0

Here is the working copy,

    val myClipboard = getSystemService(CLIPBOARD_SERVICE) as ClipboardManager?
    val myClip: ClipData? = ClipData.newPlainText("", "")

    myClipboard?.primaryClip = myClip

Hope this can help you

Suresh Maidaragi
  • 2,173
  • 18
  • 25