I recently started learning Android development in Kotlin. I did follow this guide and everything went good.
Now I'm trying to merge the content of those two guides:
https://developer.android.com/training/contacts-provider/retrieve-details.html#kotlin
and
https://developer.android.com/guide/components/fragments#Example
in order to display the details of a Contact using Fragments. I'm having trouble to launch an activity in the onItemClick method (the guide uses a ListView):
override fun onItemClick(parent: AdapterView<*>, view: View?, position: Int, id: Long) {
// Get the Cursor
val cursor: Cursor? = (parent.adapter as? CursorAdapter)?.cursor?.apply {
// Move to the selected contact
moveToPosition(position)
// Get the _ID value
contactId = getLong(Companion.CONTACT_ID_INDEX)
// Get the selected LOOKUP KEY
//contactKey = getString(CONTACT_KEY_INDEX)
mContactKey = getString(Companion.CONTACT_KEY_INDEX)
// Create the contact's content Uri
contactUri = ContactsContract.Contacts.getLookupUri(contactId, mContactKey)
/*
* You can use contactUri as the content URI for retrieving
* the details for a contact.
*/
}
val intent = Intent().apply{
setClass(activity,DetailsActivity::class.java)
putExtra("contactID",contactId)
putExtra("mContackKey",mContactKey)
putExtra("contactUri",contactUri)
}
startActivity(intent)
}
If I create the Intent to start the activity as displayed in the guide, I get the compiler error "Inferred type is FragmentActivity?, but context was expected".
I changed then the Intent to either one of the following:
val intent = Intent().apply{
setClass(requireContext(),DetailsActivity::class.java)
putExtra("contactID",contactId)
putExtra("mContackKey",mContactKey)
putExtra("contactUri",contactUri)
}
startActivity(intent)
or
val intent = Intent().apply{
context?.let { setClass(it,DetailsActivity::class.java) }
putExtra("contactID",contactId)
putExtra("mContackKey",mContactKey)
putExtra("contactUri",contactUri)
}
startActivity(intent)
whit this, I do not get the compiler error, but in the Logcat I see the notice "W/ActivityThread: handleWindowVisibility: no activity for token android.os.BinderProxy#9dc9013"
Can you please point me to the correct way to instantiate an activity from the onClick method of a ListView inside a Fragment ? Thank you!
On a related note: do you recommend those guides or is their content obsolete ?
Edit: the full fragment class is here
Try below code for opening new activity from fragment :
activity?.let{
val intent = Intent (it, DetailsActivity::class.java)
intent.putExtra("contactID",contactId);
intent.putExtra("mContackKey",mContactKey);
intent.putExtra("contactUri",contactUri);
it.startActivity(intent)
}
startActivity() is a function in the Context class (of which Activity is a subclass), not of the Fragment class.
So you can make a direct bare call to startActivity() from within the code of a subclass of Context (as any Activity implementation is), but when you are calling it from a Fragment, you have to call it on a context: context.startActivity().
The Fragment.context property is nullable, so you can use requireContext().startActivity(). It won't be null when responding to clicks, so this is safe.
Related
I'm learning the Activity Results API that replace the onActivityResult. I understand the concept and basic usage, but not sure what's the proper way to setup an intent that takes multiple input extras.
For example, I want to put two Boolean flags and one String to the intent, in the old way, I could do
Val intent = Intent(this, AnotherActivity::java.class)
intent.putExtra(key1, false)
intent.putExtra(key2, true)
intent.putExtra(key3, someString)
But how do I do this in createIntent method? And what would the input type for this custom ActivityResultContract?
One way I can see is using Intent as input type, like class CustomActivityContract : ActivityResultContract<Intent, Unit>(). But that doesn't feel right to me.
Any suggestion is appreciated!
You don't call createIntent() directly. Instead, pass your intent to the ActivityResultLauncher.launch() method.
val launcher = registerForActivityResult(StartActivityForResult()) { result ->
// handle result
}
launcher.launch(
Intent(this, AnotherActivity::class.java)
.putExtra(key1, false)
.putExtra(key2, true)
.putExtra(key3, someString)
)
I'm trying to make a simple debug activity that allows me to start any activity of my project at runtime.
As of right now, I've implemented a RecyclerView which gets its data from a list, in such fashion:
val activitiesList = ArrayList<Activity>()
activitiesList.add(FrameHomeActivity())
activitiesList.add(LeaderHomeActivity())
activitiesList.add(LoginActivity())
...
but this relies on me having to manually update this list when adding a new activity.
I've already managed to attach a clickListener to the RecyclerView, so that each activity can start successfully when an item is touched.
Is there a way to get all the activities in the project "dynamically", so that I don't have to update this code each time a new activity is added?
You don't call constructor of an Activity instead you fire an Intent . You get the Activity from PackageManager then you start it by name.
val activities = packageManager
.getPackageInfo(packageName, PackageManager.GET_ACTIVITIES).activities
val nameList= activities.map { it.name }
nameList here is List<String> it will contains fully qualified name of your Activity classes .
You can use this name to create an Intent to start the activity from adapter.
fun onClickItem(context:Context, activityName:String){
try {
val c = Class.forName(activityName)
val intent = Intent(context, c)
context.startActivity(intent)
} catch (ex: Exception) {
}
}
You can get a list of all activities using this code
getActivity()
.getPackageManager()
.getPackageInfo(getActivity().getPackageName(), PackageManager.GET_ACTIVITIES)
.activities
Edit - getActivity() can be replaced by this when calling from activity else when calling from fragment getActivity() will be required.
I have a screen consisting list of Results. Clicking on each of the result takes me to different item but with the same Activity Name(TestResultActivityDetails).
How can I launch each Result as different Activity Launcher?
Is there any option to use index on list items to launch Activity?
val intent = Intent(TestResultActivityDetails::class.java)
startActivity(intent)
Here, TestResultActivityDetails::class.java is the activity name which is shared with all the list of Results.
To pass data to an Activity you need to use Intent extras. Your posted code would become as this:
val intent = Intent(TestResultActivityDetails::class.java).apply {
/* You pass data as extras, with a key and the actual value.
* KEY VALUE */
putExtras("clickedIndex", index)
}
startActivity(intent)
Then, in TestResultActivityDetails you would do:
override fun onCreate(saveInstance: Bundle?) {
...
/* You get your data back from the Intent extras, using previous key.
* KEY FALLBACK if not found */
val index = intent.extras?.getInt("clickedIndex") ?: -1
}
fun kullaniciOlustur2(view: View){
val intent = Intent(applicationContext,KullaniciOlustur2::class.java)
intent.putExtra("input",makeUsername.text.toString())
intent.putExtra("input2",makeUserphone.text.toString())
startActivity(intent)
}
Mainactivity2 starts here..before this, I was using
val intent = intent
val received: String = intent.getStringExtra("input")
makeUsername.text = received
But this method doesn't work anymore.
I tried using getIntent() but couldn't get anything
val intent = getIntent()
Try this code
Activity 1
val intent = Intent(FirstActivity.this,SecondActivity::class.java) //not application context
intent.putExtra("input",makeUsername.text.toString())
intent.putExtra("input2",makeUserphone.text.toString())
startActivity(intent)
Activity 2
inside onCreate() method use
val stringOne = getIntent().getStringExtra("input")
Or more cleaner way is
val extras = getIntent().getExtras()
if (null != extras) {
val value = extras.getString("input")
//The key argument here must match that used in the other activity
}
and please check similar answers in Java, you may be able to get the Idea here already told in another answer.
I also Use Anko to remove this kind of boilerplate code
I recommend using Kotlin Anko, there are plenty of methods that will help you to remove this boilerplate code
check Anko Intents here
Use Below Code:
The Code is same as Java .Just difference is kotlin do not have
1. No semicolon at the end.
2. to call another activity kotlin use ::
ex.KotlinActivity::class.java
startActivity(Intent(this, KotlinActivity::class.java).putExtra("DataTrasfer", ""))
To Get Value:
intent.getStringExtra("DataTrasfer")
I have read the artical https://github.com/Kotlin/anko/wiki/Anko-Commons-%E2%80%93-Intents
The Code A is to open a send email activity, I hope to replace it with org.jetbrains.anko.startActivity, how can I do? Thanks!
Code A
fun sendFeedbackByEmail(mContext: Context) {
val data = Intent(Intent.ACTION_SENDTO)
data.data = Uri.parse("mailto:" + mContext.getString(R.string.FeedbackEmailAddress))
data.putExtra(Intent.EXTRA_SUBJECT, mContext.getString(R.string.FeedbackEmailSubject))
data.putExtra(Intent.EXTRA_TEXT, mContext.getString(R.string.FeedbackEmailFirstContent))
mContext.startActivity(data)
}
You should not try to replace with the startActivity function. There is function available in Anko. It goes like this
email(email, [subject], [text])
Arguments in square brackets ([]) are optional. Methods return true if the intent was sent.
You can call it like
email("youremail#yourdomain.com","Your Subject","Your Text")
Right now they don't have feature where you can send same email to multiple email id. You have to make another call.
Anki is achieving is by writing extension over Context and Fragment classes. So this function is available for both Activity and Function