I am trying to start an acitvity through Anko context using kotlin, But would like to use flags
override fun createView(ui: AnkoContext<MyActivity>) = with (ui) {
verticalLayout {
// load something
button ("Back") {
onClick {
// goes back to the previous activity
startActivity<PreviousActivity>()
}
}
}
}
I am raising an activity like so,
startActivity<PreviousActivity>()
How can I add the flags to reorder the activity to top
This did not work, get a type mismatch error
startActivity(intentFor<PreviousActivity>("id" to 5).singleTop())
https://github.com/Kotlin/anko/wiki/Anko-Commons-%E2%80%93-Intents
I think singleTop() is what you're looking for
startActivity(intentFor<SomeOtherActivity>("id" to 5).singleTop())
I solved it using so,
getContext().startActivity(intentFor<PreviousActivity>().addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT))
I use the following code to start an activity with FLAGS
val intent = Intent(this#home_paciente,LoginActivity::class.java)
intent.flags = Intent.FLAG_ACTIVITY_REORDER_TO_FRONT
startActivity(intent)
finish()
The part of
this#home_paciente
is the context of the activity so you put this#activity_name or replace with applicationContext and
LoginActivity::class.java
is the new activity to launch
Related
I have these Activities, each one has its own navigation tree and a default (main) Fragment:
class MainActivity: Activity
class ActivityA: Activity
class ActivityB: Activity
In the fragment in MainActivity I have several activity launchers. When I call these launchers from an onClickListener (for example), things work as expected, I navigate to the destination Activity, I do what I have to do there, I finish the activity from its fragment:
activity.setResult(Activity.RESULT_OK)
activity.finish()
And finally I get the callback in the activity launcher from where the activity was launched.
But, when I launch an activity from another launcher, the callback will not be triggered.
Here it is a simple code to explain the problem:
The MainFragment of the MainActivity:
class MainFragment: Fragment {
val activityALauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
launchActivityB() // The callback in activityBLauncher will NOT be triggered after ActivityB is finished
}
val activityBLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
}
fun launchActivityA() {
val intent = Intent(activity, A::class.java)
activityALauncher.launch(intent)
}
fun launchActivityB() {
val intent = Intent(activity, B::class.java)
activityBLauncher.launch(intent)
}
// For example is called in onClickListener
fun someRandomFun() {
launchActivityB() // The callback in activityBLauncher will be triggered after ActivityB is finished
}
}
This is how ActivityA is finished from MainFragmentA:
class MainFragmentA: Fragment {
...
activity.setResult(Activity.RESULT_OK)
activity.finish()
...
}
This is how ActivityB is finished from MainFragmentB:
class MainFragmentB: Fragment {
...
activity.setResult(Activity.RESULT_OK)
activity.finish()
...
}
Any solution to this?
EDIT
For each registerForActivityResult we will get a callback in onActivityResult at the host activity MainActivity.
Usually, after onActivityResult in host activity, then the callback in registerForActivityResult will be triggered, this seems to be by design.
But in this particular case I never get the callback in registerForActivityResult but I still get in onActivityResult
this worked for me add this in your gradle
implementation 'androidx.activity:activity-ktx:1.2.0-alpha04'
implementation 'androidx.fragment:fragment-ktx:1.3.0-alpha04'
this is what I want to achieve:
I'm in Activity A with couple options to choose from (buttons)
after clicking any of them, I want to be taken to Activity B
Activity B should contain a constant part (audio) and a Fragment with image and text, depending on the button you choose in Activity A.
Is it achievable? I tried to both startActivity and getSupportFragmentManager (etc.) as my onClick method but with no use, maybe there's another way?
In activity B create a method (static in java, companion in kotlin) to create an intent:
companion object {
const val ARG_FRAGMENT_TO_LOAD = "argFragment"
fun newIntent(context:Context, fragmentTagToLoad:String): Intent {
return Intent(context, ActivityB::class.java).apply {
putString(ARG_FRAGMENT_TO_LOAD, fragmentTagToLoad)
})
}
}
Then, in activity A you can use this intent to start activity B.
myButton?.setOnClickListener {
startActivity(ActivityB.newIntent(this, SomeFragmentToLoad.ARG_TAG))
}
Then, again in activity B you will receive this argument in the intent, so that you can handle it. It is typically done inside onCreate():
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val fragmentTagToLoad = intent.getStringExtra(ARG_FRAGMENT_TO_LOAD) ?: ""
if(fragmentToLoad.isNotEmpty() {
// Use fragment manager to load fragment into container.
}
...
}
Finally, in activity B you can use the argument to load the desired fragment using a (usually support) fragment manager.
Of course you should define ARG_TAG as a String constant inside SomeFragmentToLoad.
In my application i want use Fragment and Activity and i want startActivity from this fragment and i should send data with startActivity
I write below codes, but when running application show null in activity!
Fragment codes :
homeDashboard_giftInfoLayout.setOnClickListener {
val intent = Intent(requireContext(), DashboardChargeWalletActivity::class.java)
intent.putExtra(USER_WALLET_PRICE, response.user.wallet.credit)
intent.putExtra(USER_CHARGED_VALUE, 0)
startActivity(intent)
}
Activity codes :
userWallet = intent?.getStringExtra(USER_WALLET_PRICE).toString()
userWallet.let {
//User wallet
dashboardChargeWallet_userWallet.text =
"${getString(R.string.walletInventory)}: $userWallet ${getString(R.string.toman)}"
}
when click on button for startActivity i show this response.user.wallet.credit into toast.
But into activity show me null !
I used Kotlin for language.
How can i fix it?
this line:
intent.putExtra(USER_WALLET_PRICE, response.user.wallet.credit)
I suspect that response.user.wallet.credit isn't a string. So the below line:
userWallet = intent?.getStringExtra(USER_WALLET_PRICE).toString()
won't find a string extra with USER_WALLET_PRICE key. Check what type response.user.wallet.credit is, int? long? serializable? and make sure you get it by the same type
you need to use intent like this from a fragment.
homeDashboard_giftInfoLayout.setOnClickListener {
val intent = Intent(activity, DashboardChargeWalletActivity::class.java)
intent.putExtra(USER_WALLET_PRICE, response.user.wallet.credit)
intent.putExtra(USER_CHARGED_VALUE, 0)
startActivity(intent);
}
also you can use requireActivity
val intent=Intent(requireActivity(),DashboardChargeWalletActivity::class.java)
Hopefully this will work for you.
try this, it may help
Intent intent = new Intent(getActivity(), LoadActivity.class);
intent.putExtra(USER_WALLET_PRICE, response.user.wallet.credit)
intent.putExtra(USER_CHARGED_VALUE, 0)
startActivity(intent);
I have several activities with launchMode SingleInstance. On log out i want to finish all activities and open launchScreen.
val intent = Intent(context, LauncherActivity::class.java)
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
(context as AppCompatActivity).finishAffinity()
context.startActivity(intent)
However if i press back at Launcher activity i am forwarded to previously launched activities with singleInstance mode
UPDATE 11/1/2018:
I've tested multiple approach to deal with it such as event propagation, intent flags, counting activity instances, etc. There is some weird scenarios such as starting multiple singleInstance activities sequentially. In this case, middle activities doesn't start at all (onCreate method isn't called) and after pressing back button, they'll be started. Therefore no one of the prior approaches works! As the issue is a bit strange, I tried to solve it using a bit strange way.
We maintain the logout state in a singleton object called LogoutHandler. It cooperates with a class LogoutAwareActivity which is inherited by all activities except LoginActivity because it should not be affected by logout mechanism. When the logout occurs, a flag is set in the LogoutHandler until the last child of LogoutAwareActivity has finished then clears the flag.
Here is an implementation of that:
LogoutHandler:
import java.util.*
object LogoutHandler {
private var isLogout = false
private var timerWatchDog: TimerWatchDog? = null
fun isLogout() = isLogout
fun onActivityDestroyed() {
if (isLogout) {
timerWatchDog?.refresh(Runnable {
isLogout = false
timerWatchDog = null
})
}
}
fun logout() {
isLogout = true
timerWatchDog = TimerWatchDog(500)
}
private class TimerWatchDog(private val delay: Long) : Runnable {
private var timer: Timer? = null
private var runnable: Runnable? = null
fun refresh(runnable: Runnable) {
this.runnable = runnable
timer?.cancel()
val timerTask = object : TimerTask() {
override fun run() {
Thread(this#TimerWatchDog).start()
}
}
timer = Timer()
timer?.schedule(timerTask, delay)
}
override fun run() {
runnable?.run()
}
}
}
LogoutAwareActivity:
import android.support.v7.app.AppCompatActivity
abstract class LogoutAwareActivity : AppCompatActivity() {
override fun onResume() {
super.onResume()
if (LogoutHandler.isLogout()) {
finish()
}
}
override fun onDestroy() {
super.onDestroy()
LoginHandler.onActivityDestroyed()
}
}
A concrete Activity:
class ActivityA : LogoutAwareActivity() {
// ...
}
Another concrete Activity:
class ActivityB : LogoutAwareActivity() {
// ...
}
Your logout function:
fun logout() {
val intent = Intent(context, LoginActivity::class.java)
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
LogoutHandler.logout()
context.startActivity(intent)
}
Visual Result:
All of MainActivity, ActivityA, ActivityB and ActivityC are single instance.
Traversing between activities by pressing back button:
Going to LoginActivity then pressing back button:
Before launching splash screen add this line
ActivityCompat.finishAffinity(this)
I dont know what exactly you were trying to do but i got a feeling you could redesign your app differently to do it better.
Anyway to your question - I guess you can check onStart of the activities if the user has logged off, and if he did start a single instance launcher activity and close these activities with finish().
In my experience extending the Application class is the simpler and most effective way to store limited amount of data which needs to be shared among all the activities.
In your case you can create a class holding your login data and store its instance in your custom Application object, where it can be reached by all activities. They can check for login availability at start, subscribe for changes and get notified when they need to finish. The Application object itself can subscribe for changes and start the login activity if needed.
I have several activities with launchMode SingleInstance. On log out i want to finish all activities and open launchScreen.
Here is one way:
Have all the activities extend a custom BaseActivity.
You can use LocalBroadcastManager to send local broadcast (within your app), when the logout button is clicked.
Inside the base activity you can implement the listener. You can call finish() inside the listener.
So when user clicks the logout button, you send the local broadcast to all the activities open. Since all your activities extend the common BaseActivity, the listener gets called and the activities finish.
After sending the broadcast, you can open the intended LauncherActivity.
See How to use LocalBroadcastManager?
for more.
P.S: You can un-register the listener in onDestroy. Since activity is still present, onDestroy won't have been called. And if it has already been destroyed then you have one less activity to worry about.
I am trying to call a new activity from my current one dynamically. So I created an object class that taking activity, class, and bundle as optional.
object ActivityHelper {
fun start(context: Context, activity: Class<out BaseCompatActivity>, extras: Bundle? = null) {
val intent = Intent(context, activity)
extras?.let {
intent.putExtras(extras)
} ?: run {
intent.putExtra("flag", context.javaClass.getSimpleName())
}
context.startActivity(intent)
}
}
after that, I am calling this from all activities like this
ActivityHelper.start(this, Activity::class.java, extras)
But I noticed it makes the app loading time slower than before. Am I doing it correctly? or is it bad idea to start activity like this?
On the activity you are trying to load, hide views in layout by default. onResume you can delay and then set the view visibility to true. If your UI layout is complex or you are using some library for anim, it would take more time to start.