34

Follow this tutorial: Android - Start Another Activity if I made MainActivity.java button OnClick attribute has the sendMessage() method.

But if I made MainActivity.kt button OnClick attribute has nothing to show, just a none.

Is this an Android Studio 3 bug or I missed something for Kotlin?

Java mainActivity:

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    /** Called when the user taps the Send button */
    public void sendMessage(View view) {
        // Do something in response to button
    }

}

Kotlin mainActivity:

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
    }

    /** Called when the user taps the Send button  */
    fun sendMessage(view: View) {
        // Do something in response to button
    }
}

OnClick attribute

XML layout (Java and Kotlin project are the same)

    <?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:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="ir.bigbang.vahid.myapplication.MainActivity">

    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Button"
        tools:layout_editor_absoluteX="148dp"
        tools:layout_editor_absoluteY="81dp" />
</android.support.constraint.ConstraintLayout>
Roham Rafii
  • 2,929
  • 7
  • 35
  • 49
Vahid
  • 3,352
  • 2
  • 34
  • 42
  • 1
    Can you post your layout file in XML? But I don't recommend you set `onClick` on layout file because you are putting programming logic on a view file. With kotlin-android-extensions, you can access the view by id, there is no point setting it in layout. – Joshua Oct 27 '17 at 09:12
  • @Joshua, layout added. – Vahid Oct 27 '17 at 09:54

6 Answers6

47

It seems like the designer does not support Kotlin yet. Here are some solution:

XML (Not Recommended)

Add the following line to your Button tag. This is exactly what the designer will do.

android:onClick="sendMessage"

Old Fashion

No need to add anything.

val button = findViewById<Button>(R.id.Button)
button.setOnClickListener {

}

kotlin-android-extensions (Recommended)

Add apply plugin: "kotlin-android-extensions" to your build.gradle

// button is the Button id
button.setOnClickListener {

}
Joshua
  • 5,901
  • 2
  • 32
  • 52
  • I added 'apply plugin: "kotlin-android-extensions"' to my build.gradle, at the very bottom. But where do you add the "// button is the Button id button.setOnClickListener { }" part then? There is an error in the Getting started manual if you ask me. – Freek Jan 18 '18 at 10:55
  • 8
    Ok, I did it via the XML (android:onClick="sendMessage"), that worked. But why is this not recommended? – Freek Jan 18 '18 at 11:45
  • 4
    @Freek In my opinion, XML should only about how to view is layout. The programming logic should be in the code instead. When other reads your code, they will not know listener is added in XML. Also, when you reuse the XML, you have to ensure the function must be present in both activities. Writing listeners in XML does not have any benefits over the other ways. So it is not recommended. – Joshua Aug 06 '18 at 02:35
  • 1
    The recommended here is deprecated – Liam Baron Jan 12 '21 at 21:46
6

Your code will like this:

button.setOnClickListener(){
            Toast.makeText(this@MainActivity, "Its toast!", Toast.LENGTH_SHORT).show();
        }

Here import will:

import kotlinx.android.synthetic.main. activity_main.*

Here "button" is the id of that Button in .xml file. Here the advantage is no need to create Button object in your java class.

Md. Sajedul Karim
  • 6,749
  • 3
  • 61
  • 87
  • 3
    This is a more natural Kotlin way, plus not having to get a button object is cool – Vishnoo Rath Mar 09 '18 at 10:41
  • "import kotlinx.android.synthetic.main. activity_main.*" - stroke have error, " import kotlinx.android.synthetic.main.activity_main.*" - without error – Fortran Feb 21 '20 at 12:42
4

Once defined the sendMessage class as :

/** Called when the user taps the Send button  */
fun sendMessage(view: View) {
    setContentView(R.layout.activity_second)
    // Do something in response to button
}

And also defined a second activity as:

class SecondActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_second)
    }
}

I added the SendMessage to the OnClick function: enter image description here

And then it worked.

Zioalex
  • 3,441
  • 2
  • 33
  • 30
2

You can easily define this inside the XML itself. But using the android:onClick attribute is still a little expensive.

Instead you could consider using the Kotlin Android Extensions and synthetic properties:

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)
    button.setOnClickListener {
        // Do something in response to button
    }
}
tynn
  • 38,113
  • 8
  • 108
  • 143
  • I know this way. I was curious that why in Kotlin that attribute didn't access to activity methods. – Vahid Oct 27 '17 at 10:00
  • And here I was wondering @Vahid, how you even notices this. I'd assume the `ClassPath` is not setup correctly. Now you've got me curious as well. – tynn Oct 27 '17 at 10:08
  • as @Joshua says It should be relative to Android Studio designer. – Vahid Oct 27 '17 at 10:12
1

Button OnClick implementation it's can be done by some ways in Android

some of the possible ways are below in sample:

1>Using OnClickListener as a interface Here we implement our main activity with OnClicklistener and override the function onClick

override fun onClick(v: View?) {
        when (v?.id){
            (R.id.btn1) -> {
                toastmsg("Button1");
            }

            R.id.btn2 -> {
                toastmsg("Button2");
            }
        }
    }

2>And create a function and pass the OnClickListener with variable sample:

        findViewById<Button>(R.id.btn3).setOnClickListener(btnClick);

var btnClick =
        OnClickListener {
            Toast.makeText(this, "BtnClick", Toast.LENGTH_SHORT).show() ;
        }

3>Create OnClickListener in Oncreate()

  btn1=findViewById(R.id.btn1);
        btn1?.setOnClickListener {
            toastmsg("test button1");
        }

full sample Code of the example it contains all the possible implementation of the Button OnClickListener :

class MainActivity : AppCompatActivity() , OnClickListener{

    lateinit var tv1:TextView;
    lateinit var tv2:TextView;
    lateinit var tv3:TextView;

    var btn1: Button? =null;
    var btn2: Button? =null;
    var btn3: Button? =null;

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        btn1=findViewById(R.id.btn1);
        btn1?.setOnClickListener {
            toastmsg("test button1");
        }

        findViewById<Button>(R.id.btn2).setOnClickListener(this);

        findViewById<Button>(R.id.btn3).setOnClickListener(btnClick);

    }

    var btnClick =
        OnClickListener {
            Toast.makeText(this, "BtnClick", Toast.LENGTH_SHORT).show() ;
        }


    override fun onClick(v: View?) {
        when (v?.id){
            (R.id.btn1) -> {
                toastmsg("Button1");
            }

            R.id.btn2 -> {
                toastmsg("Button2");
            }
        }
    }

    private fun toastmsg(msg: String){
        Toast.makeText(this, "DaggerTest" + msg, Toast.LENGTH_SHORT).show();
    }
}
Suresh B B
  • 1,387
  • 11
  • 13
0

Here's the solution I came up with in the MainActivity.kt file.

override fun onCreate(savedInstanceState: Bundle?) {

    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)

    val button = findViewById<Button>(R.id.button)
    button.setOnClickListener {
        sendMessage()
    }
}

/** Called when the user taps the Send button  */
private fun sendMessage() {
    val editText = findViewById<EditText>(R.id.editText)
    val message = editText.text.toString()
    val intent = Intent(this, DisplayMessageActivity::class.java).apply 
    {
        putExtra(EXTRA_MESSAGE, message)
    }
    startActivity(intent)
}
John
  • 9
  • 2