How can I use button in one activity to do something in second activity? - android

I got a question. I have two activities in my app. In first one, when I click the button, I need something to happen in the second one. How can I do it? If that button would be in the second activity I would just do it by:
button.setOnClickListener {}
But how can I do it when button is in the other activity? It's worth adding that code, that tells what should happen, must be in that second activity, just like it was in that "setOnClickListener". Sorry, I'm starting with Android development.

You could communicate between two activities via broadcast or intent.
But it make logic more complex.
So I suggest use two fragments instead two activities.
If you use two fragment in one activity, you can easy communicate between two fragments.
You can look more detailed information about fragment from this URL.
https://developer.android.com/guide/fragments

To achieve the intended flow you may try the below approach,
Start activity 2 on button click from activity 1.
On activity 2 place your code in onCreate so, once activity 2 loads up your code will fire up.
Activity 1:
button.setOnClickListener{
val intent = Intent(this, second::class.java)
startActivity(intent)
}
Activity 2:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
CallDefinedFunctionHere();
}

You cannot be sure that both activities are present at the same moment since the system might destroy inactive one therefore you cannot trigger any code from activity A inside activity B.
What you can do you can start activity B with an intent and some parameters describing what should happen inside activity B.
or
You can communicate by writing something down to a persistent storage (like SharedPreferences) and then when the other activity is resumed (active again) reading it, reacting to it and then removing it from the storage (to make sure you do not handle it twice).

You can pass data in the intent that opens the second activity.
// In first activity:
buttonX.setOnClickListner {
val intent = Intent(MySecondActivity::class.java).apply {
putExtra("wasFromButtonX", true)
}
startActivity(intent)
}
// In second activity:
fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val wasLaunchedFromButtonX = intent.getBooleanExtra("wasFromButtonX", false)
// Above line uses false as default, so it will only be true if you explicitly
// put the extra in the Intent that started this Activity.
if (wasLaunchedFromButtonX) {
// do alternate setup here
}
}
How to pass information between Activities is explained in the introductory documentation here.

Create a function in class where 2nd activity are defined like this.
public void refresh(){}
Now Call that in your 1st activity where you want to call 1st after any action.
button.setOnClickListener {((MainActivity) Objects.requireNonNull(getActivity())).refresh();}

Related

How to navigate to deeply nested screen composable from the Activity's onCreate in Jetpack Compose

Suppose I have a notification, that when clicked, launches my app's activity. It's a notification about a message, in a conversation, and so it launches the activity passing the conversationId as an argument. When the activity is launched by that intent from the notification, it should open MessagesScreen, which is a deeply nested screen in the app, passing to it conversationId.
What is the best way to do this in Compose? In the good old Fragments or Activities you just navigated straight to it, but with Compose is a little trickier. The path to the MessagesScreen is as follows:
SplashScreen (checks for authentication) -> HomeScreen (if authenticated) -> ConversationScreen -> MessagesScreen
I can't just navigate straight to MessagesScreen by having the compose's NavController be stored in the Activity, since I need to go through SplashScreen to check for authentication. Also, I don't know the Compose's implication of navigating to a deeply nested component from the Activity's onCreate().
What I currently do is have a field in my global ViewModel called notificationConversationId, that is set on my Activity's onCreate if it was passed by the notification's intent:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val conversationId = intent.getStringExtra("conversation_id") ?: ""
globalViewModel.notificationConversationId = conversationId
// ...
Then, in a LaunchedEffect in my HomeScreen I observe this field, and if it is not empty, I navigate to the MessagesScreen, and set it to an empty string, so the LaunchedEffect is not executed again.
val conversationId = globalViewModel.notificationConversationid
LaunchedEffect(conversationId) {
if (conversationId.isNotEmpty()) {
val path = getMessagespath(conversationId = conversationId)
globalViewModel.notificationConversationId = ""
navController.navigate(path)
}
}
It works, but it is horrendous. Is there a better way to accomplish this in Compose? Thanks in advance.

Android Kotlin - How execute an animation only when app opens?

I would like that animation on MainActivity to be exhibited only when the user opens the app, but remains static if the user comes from another Activity/Fragment (e.g. by using BottomNavigationMenu), so as not to pollute the window too much.
I think it can be solved by using onCreate, onStart, onResume but I am unable to set it properly (still learning).
The only answer I found is here: https://www.tutorialspoint.com/how-to-launch-activity-only-once-when-android-app-is-opened-for-the-first-time
but it is not what I want since I still would like the animation to be exhibited every time the app opens.
Thank you in advance.
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// execute animation here??
}
override fun onStart() {
super.onStart()
setContentView(R.layout.activity_main)
// logic part (buttons) is executed here??
}
Once the Main activity is loaded then you have to finish() from other Activity/Fragment then onResume() override method Main Activity will be called. Do not start Main activity every time if the user comes from another Activity/Fragment.
For fragments:
activity.finish()
For Activity:
finish()
Rather then:
Intent startIntent = new Intent(context, MainActivity.class);
startIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(startIntent);

How to return data to the calling activity in kotlin?

I am getting confused on how to return data back to the previous activity. Perhaps because of previous experience with old styles like windows forms in dot-net.
Scenario: my simple android app starts with the MainActivity, showing some values in some units, e.g. 'you are 1.86 m tall', and having a tools icon in the menu bar. Clicking this icon starts the ToolsActivity where the user may select some settings, like wether she prefers american or metric units, e.g. meter versus foot. When done, the user clicks the back arrow in the top bar to return to the MainActivity, that should show the values in the selected units.
This is how I store the current setting of the units system:
const val EXTRA_UNITSYSTEM = ".UNITSYSTEM"
class MainActivity : AppCompatActivity() {
var TheUnitSystem : String = "metric"
I found out how to use putExtra() in the intent to startActivity() in the MainActivity to start the ToolsActivity,:
override fun onOptionsItemSelected(item: MenuItem): Boolean {
return when (item.itemId) {
R.id.tools -> {
val intent = Intent(this, ToolsActivity::class.java)
intent.putExtra(EXTRA_UNITSYSTEM, TheUnitSystem)
startActivity(intent)
and getStringExtra() to get the current value of TheUnitSystem in the ToolsActivity so the radiobutton can be initialized to the current setting:
class ToolsActivity : AppCompatActivity() {
var TheUnitSystem: String = ""
override fun onCreate(savedInstanceState: Bundle?) {
...
this.TheUnitSystem = intent.getStringExtra(EXTRA_UNITSYSTEM)!!
This actually works, but leaves the problem of how to return the data, which is possibly changed to point at another units system, back to the MainActivity when the ToolsActivity ends (or stops, or finishes, or gets destroyed...)
Initially, my guess was that intents are used to go to another activity, and that it needs another intent to go back to the previous activity.
Another guess was that you use EXTRA data on the intent to get data to ToolsActivity, so somehow the EXTRA data is also to be used to get data back to the MainActivity.
Both guesses seem to be naive.
Then I found out about starting the ToolsActivity with startActivityForResults(), as this is designed to get a result back from the second activity. However, the stories that I kind of grasp are in java, and the stories from developer.android.com that use kotlin are much more abstract and seem to describe yet different methods.
Can someone point me at a basic kotlin example for returning a simple String back to MainActivity, preferably using startActivityForResults() ?
From programming in simple Windows apps, I would guess that it would be even simpler to use application global (static) data. If that were possible, we should not need EXTRA stuff and special ForResult() methods, so perhaps this is also a dead end street?
extra info:
What may make my simple project a bit special is that I don't have a button in the layout of the second activity for going back to the MainActivity. The second activity is started from clicking a MenuItem on the Toolbar widget, defined in the res/menu/menu_main.xml layout. The second activity is shown with a back arrow in the top bar which is not in the layout of the second activity. Advantage is that it is really a Settings screen. Disadvantage is that it is not a plain normal activity where you put a back button in the layout like in most coding examples.
You are on the right track, thinking about using startActivityForResults and I'm guessing all that is missing is connecting the original activity to receive results.
In the original activity you need to override onActivityResult like this:
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
// If you have multiple activities returning results then you should include unique request codes for each
if (requestCode == <pick a code>) {
// The result code from the activity started using startActivityForResults
if (resultCode == Activity.RESULT_OK) {
}
}
}
Then, in the activity you want to return information from, do something like this:
val intent = Intent()
intent.putExtra("ActivityResult", "<Data to return>")
setResult(RESULT_OK, intent)
finish()
This is one example, but they are all similar: Example

Kotlin: Load/initialize next activity in the background

I have an initialization activity in my app which displays the logo, then I show my next activity using
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) // Call the parent class function
setContentView(R.layout.activity_launcher)
// This starts a new co-routine
// it is important to do it this way, in order to show the UI _before_
// all the initialization happens, otherwise launcher is pointless
GlobalScope.launch {
...
[initialization]
...
startActivity(ActivityTwo)
}
}
The transition takes about three seconds because of all the code that is running inside onCreate belonging to ActivityTwo. Is there a way to "create" the second activity behind the scenes, and then show it. I don't mind if the app stays on the initialization screen for those 3 seconds, but the white transition looks really ugly.
onCreate method is actually creating your activity. You must be doing some heavy computation if your activity is janking while rendering. If you are not satisfied with the transition between the two activities, then apply an animation between them.

Best way to start one activity or another basing on a variable

I want to develop an application that, at the beginning, checks a variable's value and, basing on this value, starts the activity A or the activity B, something like this:
protectec void onCreate(...){
boolean b = checkVariable();
if(b){
startActivityA();
} else {
startActivityb();
}
}
What I'm doing
This is the method I have currently implemented:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_limitation);
varChecker = new VarChecker(this);
if(varChecker.getRemainingUses() <= 0){
limitReached();
} else if(varChecker.isFirstTime()){
firstTime();
} else {
startMainActivity();
}
}
This is an activity that must be shown the first time the application is executed. Else, depending on the getRemainingUses() result, it must start the activity A or the activity B automatically.
The question
Is there any way to do what I want, without the need of create a new Activity, specially to avoid the super.onCreate(savedInstanceState) and the setContentView(R.layout.activity_limitation)?
Is there any way to do what I want, without the need of creating a new
Activity, specially to avoid the super.onCreate(savedInstanceState)
and the setContentView(R.layout.activity_limitation)?
I had a similar problem some time ago. As far as I know, It's not possible to avoid calling super.onCreate(savedInstance) and setContentView(R.layout.activity_limitation). It's design of the Android activity.
I see the following possible solutions:
if you want to choose an appropriate activity by e.g. clicking a
button, then you just need to create a new Intent basing on a
variable and there's no problem.
if you want to choose an activity in
a different moment of the flow - e.g. during the application start you can:
create a single activity for two options, use fragments and switch between them
create "dummy" activity with an empty layout, create an intent and switch to an appropriate activity basing on a variable and finish "dummy" activity. Please note that this solution is a kind of workaround and it's worth to spend some time to figure out something better, but I'm not sure if there is a recommended solution for such use cases.

Categories

Resources