140

I want to start another activity on Android but I get this error:

Please specify constructor invocation; classifier 'Page2' does not have a companion object

after instantiating the Intent class. What should I do to correct the error? My code:

class MainActivity : AppCompatActivity() {

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

    fun buTestUpdateText2 (view: View) {
        val changePage = Intent(this, Page2) 
        // Error: "Please specify constructor invocation; 
        // classifier 'Page2' does not have a companion object"

        startActivity(changePage)
    }

}
Ryan M
  • 18,333
  • 31
  • 67
  • 74
J Adonai Dagdag
  • 1,835
  • 2
  • 10
  • 22
  • @BakaWaii that page does not exist anymore. – Scre Sep 26 '18 at 11:45
  • Had the same error while converting a java app over to Kotlin. Had to add dependencies. The IDE was actually warning me. But I also found the answers here https://stackoverflow.com/questions/34144392/kotlin-fooclass-java-unresolved-reference-java-error – JonR85 Dec 02 '21 at 23:55

19 Answers19

236

To start an Activity in java we wrote Intent(this, Page2.class), basically you have to define Context in first parameter and destination class in second parameter. According to Intent method in source code -

 public Intent(Context packageContext, Class<?> cls)

As you can see we have to pass Class<?> type in second parameter.

By writing Intent(this, Page2) we never specify we are going to pass class, we are trying to pass class type which is not acceptable.

Use ::class.java which is alternative of .class in kotlin. Use below code to start your Activity

Intent(this, Page2::class.java)

Example -

// start your activity by passing the intent
startActivity(Intent(this, Page2::class.java).apply {
    // you can add values(if any) to pass to the next class or avoid using `.apply`
    putExtra("keyIdentifier", value)
})
Rahul
  • 10,457
  • 4
  • 35
  • 55
  • 8
    Any idea why they changed it to `::class.java` instead of `.class` ? The Kotlin approach is unusually complicated, compared to Java. – Mr-IDE Nov 06 '19 at 17:43
  • 7
    @Mr-IDE `class` returns a Kotlin `KClass`, but Android expects a Java `Class<...>`, hence the `.java` property. – kirbyfan64sos Apr 15 '20 at 00:45
57

Simply you can start an Activity in KOTLIN by using this simple method,

val intent = Intent(this, SecondActivity::class.java)
intent.putExtra("key", value)
startActivity(intent)
Gowtham Subramaniam
  • 3,358
  • 2
  • 19
  • 31
35

To start a new Activity ,

startActivity(Intent(this@CurrentClassName,RequiredClassName::class.java)

So change your code to :

class MainActivity : AppCompatActivity() {

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

    fun buTestUpdateText2 (view: View) {
        startActivity(Intent(this@MainActivity,ClassName::class.java))

        // Also like this 

        val intent = Intent(this@MainActivity,ClassName::class.java)
        startActivity(intent)
    }
leoelstin
  • 3,058
  • 1
  • 14
  • 11
15

You have to give the second argument of class type. You can also have it a little bit more tidy like below.

startActivity(Intent(this, Page2::class.java).apply {
    putExtra("extra_1", value1)
    putExtra("extra_2", value2)
    putExtra("extra_3", value3)
})
Adib Faramarzi
  • 3,798
  • 3
  • 29
  • 44
15

You can generally simplify the specification of the parameter BlahActivity::class.java by defining an inline reified generic function.

inline fun <reified T: Activity> Context.createIntent() =
    Intent(this, T::class.java)

Because that lets you do

startActivity(createIntent<Page2>()) 

Or even simpler

inline fun <reified T: Activity> Activity.startActivity() {
    startActivity(createIntent<T>()) 
} 

So it's now

startActivity<Page2>() 
EpicPandaForce
  • 79,669
  • 27
  • 256
  • 428
  • As newbie to kotlin, how would you plant a variable number (or none) of putExtra()'s with that? – Scre Sep 26 '18 at 11:53
  • 1
    You could set up `inline fun Context.createIntent(vararg extras: Pair) = Intent(this, T::class.java).apply { putExtras(bundleOf(*extras)) }` instead of what I said and it'll work (assuming you have `bundleOf` from android-ktx or anko) – EpicPandaForce Sep 26 '18 at 12:15
10

Try this

val intent = Intent(this, Page2::class.java)
startActivity(intent)
Boris
  • 358
  • 2
  • 6
9

Well, I found these 2 ways to be the simplest of all outcomes:

Way #1:

accoun_btn.setOnClickListener {
            startActivity(Intent(this@MainActivity, SecondActivity::class.java))
        }

Way#2: (In a generic way)

    accoun_btn.setOnClickListener {
        startActivity<SecondActivity>(this)
    }

    private inline fun <reified T> startActivity(context: Context) {
            startActivity(Intent(context, T::class.java))
        }

sample

A S M Sayem
  • 2,010
  • 2
  • 21
  • 28
7

This is my main activity where i take the username and password from edit text and setting to the intent

class MainActivity : AppCompatActivity() {
val userName = null
val password = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
button.setOnClickListener {
    val intent = Intent(this@MainActivity,SecondActivity::class.java);
    var userName = username.text.toString()
    var password = password_field.text.toString()
    intent.putExtra("Username", userName)
    intent.putExtra("Password", password)
    startActivity(intent);
 }
}

This is my second activity where i have to receive values from the main activity

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_second)
var strUser: String = intent.getStringExtra("Username")
var strPassword: String = intent.getStringExtra("Password")
user_name.setText("Seelan")
passwor_print.setText("Seelan")
}
Bharat Vasoya
  • 351
  • 4
  • 7
6

This is because your Page2 class doesn't have a companion object which is similar to static in Java so to use your class. To pass your class as an argument to Intent, you will have to do something like this

val changePage = Intent(this, Page2::class.java)
Alf Moh
  • 7,159
  • 5
  • 41
  • 50
4

From activity to activity

val intent = Intent(this, YourActivity::class.java)
startActivity(intent)

From fragment to activity

val intent = Intent(activity, YourActivity::class.java)
startActivity(intent)
Masum
  • 4,879
  • 2
  • 23
  • 28
3

another simple way of navigating to another activity is

Intent(this, CodeActivity::class.java).apply {
                    startActivity(this)
                }
Mohamed AbdelraZek
  • 2,503
  • 4
  • 25
  • 36
  • 1
    Pls do consider of explaining your code and how it would help, so that others can get benefited from this. – Amit Verma Jul 13 '20 at 09:17
3
fun Context.launchActivity(
    cls: Class<*>,
    flags: Int = 0,
    intentTransformer: Intent.() -> Unit = {}
) {
    val intent = Intent(this, cls).apply {
        addFlags(flags)
        intentTransformer()
    }
    this.startActivity(intent)
}
Prateek
  • 189
  • 1
  • 6
  • 4
    Code dumps without any explanation are rarely helpful. Stack Overflow is about learning, not providing snippets to blindly copy and paste. Please [edit] your question and explain how it works better than what the OP provided. See [answer]. – ChrisGPT was on strike Mar 18 '21 at 01:50
  • For me it worked like a glove, Let me try to explain. When creating functions like this, you are using advanced and beneficial kotlin techniques, the name of this technique is extension Functions. I will give an example below: – AllanRibas Feb 02 '22 at 06:21
2

How about this to consider encapsulation?

For example:


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

        val title = intent.getStringExtra(EXTRA_TITLE) ?: EXTRA_TITLE_DEFAULT

        supportFragmentManager.beginTransaction()
            .add(R.id.frame_layout_fragment, ContentsFragment.newInstance())
            .commit()
    }

    // Omit...

    companion object {

        private const val EXTRA_TITLE = "extra_title"
        private const val EXTRA_TITLE_DEFAULT = "No title"

        fun newIntent(context: Context, title: String): Intent {
            val intent = Intent(context, ContentsActivity::class.java)
            intent.putExtra(EXTRA_TITLE, title)
            return intent
        }
    }
libliboom
  • 532
  • 5
  • 17
1
val intentAct: Intent = Intent(this@YourCurrentActivity, TagentActivity::class.java)
startActivity(intentAct)
Suraj Rao
  • 29,388
  • 11
  • 94
  • 103
Ashish Patel
  • 21
  • 1
  • 6
1

I had a similar issue, I started to write my application in Kotlin, after I rewrote one of my activities I wanted to see if there are any issues, the problem was that I was not sure how to send an intent from java file to kotlin file.

In this case I created a static function in kotlin (companion object), this function is getting a context (from the current activity) and returning the new intent while using the current context ("java" context) while using the kotlin class ("::class.java").

Here is my code:

 //this code will be in the kotlin activity - SearchActivity
 companion object {

    fun newIntent(context: Context): Intent {
        return Intent(context, SearchActivity::class.java)
    }
}

    //this is how you call SearchActivity from MainActivity.java
Intent searchIntent = SearchActivity.Companion.newIntent(this);
startActivity(searchIntent);
Anton Makov
  • 825
  • 2
  • 9
  • 25
  • If you add `@JvmStatic` to your `newIntent` method you can call it from java without the `Companion` part. – Wirling Dec 18 '19 at 08:02
1

extension Functions

fun Activity.showToast(message: String, toastLength: Int){
    //LENGTH_SHORT = 0;
    //LENGTH_LONG = 1;
    Toast.makeText(this, message, toastLength).show()
}

fun Fragment.showToast(message: String, toastLength: Int){
    //LENGTH_SHORT = 0;
    //LENGTH_LONG = 1;
    Toast.makeText(requireContext(), message, toastLength).show()
}

fun Context.launchActivity(
    cls: Class<*>,
    flags: Int = 0,
    intentTransformer: Intent.() -> Unit = {}
) {
    val intent = Intent(this, cls).apply {
        addFlags(flags)
        intentTransformer()
    }
    this.startActivity(intent)
}

in an activity call

showToast("message to be shown", 1)

in a fragment call

showToast("message to be shown", 1)

start activity from any place

 launchActivity(MainActivity::class.java, Intent.FLAG_ACTIVITY_NEW_TASK)

Kotlin Extension function

AllanRibas
  • 678
  • 5
  • 14
0

Details

  • Android Studio 3.1.4
  • Kotlin version: 1.2.60

Step 1. Application()

Get link to the context of you application

class MY_APPLICATION_NAME: Application() {

    companion object {
        private lateinit var instance: MY_APPLICATION_NAME
        fun getAppContext(): Context = instance.applicationContext
    }

    override fun onCreate() {
        instance = this
        super.onCreate()
    }

}

Step 2. Add Router object

object Router {
    inline fun <reified T: Activity> start() {
         val context =  MY_APPLICATION_NAME.getAppContext()
         val intent = Intent(context, T::class.java)
         context.startActivity(intent)
    }
}

Usage

// You can start activity from any class: form Application, from any activity, from any fragment and other  
Router.start<ANY_ACTIVITY_CLASS>()
Vasily Bodnarchuk
  • 24,482
  • 9
  • 132
  • 127
0

Remember to add the activity you want to present, to your AndroidManifest.xml too :-) That was the issue for me.

Nicolai Harbo
  • 1,064
  • 12
  • 25
0

You can use both Kotlin and Java files in your application.

To switch between the two files, make sure you give them unique < action android:name="" in AndroidManifest.xml, like so:

            <activity android:name=".MainActivityKotlin">
                <intent-filter>
                    <action android:name="com.genechuang.basicfirebaseproject.KotlinActivity"/>
                    <category android:name="android.intent.category.DEFAULT" />
                    <action android:name="android.intent.action.MAIN" />
                    <category android:name="android.intent.category.LAUNCHER" />
                </intent-filter>
            </activity>
            <activity
                android:name="com.genechuang.basicfirebaseproject.MainActivityJava"
                android:label="MainActivityJava" >
                <intent-filter>
                    <action android:name="com.genechuang.basicfirebaseproject.JavaActivity" />
                    <category android:name="android.intent.category.DEFAULT" />
                </intent-filter>
            </activity>

Then in your MainActivity.kt (Kotlin file), to start an Activity written in Java, do this:

       val intent = Intent("com.genechuang.basicfirebaseproject.JavaActivity")
        startActivity(intent)

In your MainActivityJava.java (Java file), to start an Activity written in Kotlin, do this:

       Intent mIntent = new Intent("com.genechuang.basicfirebaseproject.KotlinActivity");
        startActivity(mIntent);
Gene
  • 10,819
  • 1
  • 66
  • 58