Open app with multiple inner Intents and wait for result - android

I´ve an app (APP1) which should open other app (APP2) and wait for the result. I´m doing it this way.
private fun startBridgeActivity(fileName: String, isProduction: Boolean) {
val intent = Intent(Intent.ACTION_MAIN)
when (isProduction) {
true -> {
intent.component = ComponentName(
"com.myapp",
"com.myapp.view.ui.ItemSelectionActivity"
)
}
else -> {
intent.component = ComponentName(
"com.myapp.dev",
"com.myapp.view.ui.ItemSelectionActivity"
)
}
}
try {
startActivityForResult(intent, REQUEST_CODE)
} catch (e: Exception) {
e.printStackTrace()
Toast.makeText(this#MainActivity, "This activity does not exist", Toast.LENGTH_LONG).show()
}
}
Then APP2 receives this intent and opens itself. The launch method on this APP2 it´s just the standard.
The navigation inside APP2 is as follows:
ReceiverActivity - Step1Activity - Step2Activity - LastActivity
I´ve tried setting the result and finishing LastActivity, but it doens't work. Also tried with finishAffinity and finishAndRemoveTasks but they also didn't work.
Then what I did was calling ReceiverActivity from LastActivity and setting there the result and finishing it. But that leaves me on the homescreen and the result wont get to APP1.
val receiverActivityIntent = Intent(this#LastActivity, ReceiverActivity::class.java)
receiverActivityIntent.putExtra("end", true)
TaskStackBuilder.create(this#ReceiverActivity)
.addParentStack(ReceiverActivity::class.java)
.addNextIntent(receiverActivityIntent)
.startActivities()
finish()
I readed some other SO answers where someone wrote that the Activity from APP1 would be added to the stack of APP2 and that might be why the app goes to the homescreen.
Any help will be appreciated.
Thanks.

Your app launches ItemSelectionActivity using startActivityForResult(). Your app will get the callback onActivityResult() when ItemSelectionActivity finishes. It will receive the results that ItemSelectionActivity sets when it calls setResult().
If ItemSelectionActivity needs to launch other activities before it can get the results to send back to your app, you can do this in a few possible ways:
Use FLAG_ACTIVITY_FORWARD_RESULT
When ItemSelectionActivity launches another Activity, it should set the flag Intent.FLAG_ACTIVITY_FORWARD_RESULT in the Intent and call startActvity() (do NOT call startActivityForResult(). The Activity that is being launched must then call setResult() with the results and that data will be passed back to your app. You are basically "forwarding" the request for a result from one Activity to the next. Since you seem to have several activities to go through before you get a result, you can continue to forward the responsibility from one Activity to the next Activity. The last one in the chain should then call setResult() and those results will be passed back to your app in onActivityResult().
Chain startActivityForResult() calls:
When ItemSelectionActivity launches another Activity, it should call startActvityForResult(). The Activity that is being launched must then call setResult() with the results and that data will be passed back to ItemSelefctionActivity in onActivityResult(). ItemSelectionActivity should then itself call setResult() with the data and finish(). The results will be passed back to your app. Since you seem to have several activities to go through before you get a result, you can continue to chain these calls so that each Activity launches the next Activity using starActivityForResult() and the called Activity needs to pass the results back usingsetResult()`.
Have LastActivity deliver the result to ItemSelectionActivity:
This is the solution that you have already tried to implement. LastActivity returns the result directly to ItemSelectionActivity. However, your implementation is broken. DO NOT USE TaskStackBuilder to accomplish this! TaskStackBuilder has a lot of side effects that destroy the Activity stack within the task. What you want to do instead is this:
val receiverActivityIntent = Intent(this#LastActivity, ReceiverActivity::class.java)
receiverActivityIntent.putExtra("end", true)
// add the results to the Intent
receiverActivityIntent.putExtra("results", results)
// Set the CLEAR_TOP and SINGLE_TOP flags (if necessary) to remove any
// activities that are on the stack between ReceiverActivity and LastActivity
receiverActivityIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP |
Intent.FLAG_ACTIVITY_SINGLE_TOP)
startActivity(receiverActivityIntent)
// Calling finish() here isn't necessary if you set the Intent flags
finish()
NOTE: My Kotlin syntax may not be 100% correct, but hopefully you get the idea.
With this solution, the results will be delivered to ReceiverActivity in onNewIntent(). You will need to override onNewIntent(), get the results from the passed Intent and then call setResult() with the results to pass them back to your app.

Related

onActivityResult called immediately on startActivityForResult

I am trying to get results from native activity in React Native Module. When I called startActivityForResult from my React Native Module, onActivityResult is called immediately even though the activity shows up but RESULT_CANCELED is immediately returned to onActivityResult().
I have followed the official guide from here
My Module code to start activity:
Activity currentActivity = getCurrentActivity();
if (currentActivity != null) {
Intent tgIntent = new Intent(currentActivity, SecondActivity.class);
tgIntent.setFlags(FLAG_ACTIVITY_NEW_TASK);
currentActivity.startActivityForResult(tgIntent, REQUEST_CODE_ENROLLMENT);
}
I tried both of following to set activity event listener but nothing changes
context.addActivityEventListener(activityEventListener);
context.addActivityEventListener(this);
Remove the "New Task" flag from the intent.
startActivityForResult must be under the same task as the calling activity.
According to documentation:
if the activity you are launching uses Intent#FLAG_ACTIVITY_NEW_TASK, it will not run in your task and thus you will immediately receive a cancel result.

Pending intent stays after leaving activity with back button

I'm using pending intent with notification to send a push to my device.
My pending intent contains fields that will be used in my MainActivity onCreate() method to handle navigation. After successful navigation to any point in my application I tapping on the back button until my app goes to the background. Right after that my activity instantly invokes onDestroy() for some reasons (using android emulator API 28). The problem is that after lifting up app to the foreground, PendingIntent still there and my app performs navigation again.
It's really strange. I always thought that intents with FLAG_ONE_SHOT could be used only once. I also tried to clear intent by myself but it didn't work out too.
My Intent construction
const val NAVIGATION_BUDNLE = "nav_bundle"
private fun createPendingIntent(): PendingIntent? {
val destination = resolveDestionation()
val intent = Intent(context.applicationContext, MainActivity::class.java).apply {
flags = FLAG_ACTIVITY_NEW_TASK or FLAG_ACTIVITY_CLEAR_TASK
putExtra(NAVIGATION_BUDNLE, destination)
}
return PendingIntent.getActivity(context, Random.nextInt(), intent, FLAG_ONE_SHOT)
}
At the end of the activity onCreate() method, I've got these lines to handle navigation.
intent?.extras?.get(NAVIGATION_BUNDLE)?.let {
navController.setGraph(R.navigation.nav_graph, it as Bundle)
clearCurrentIntent() // intent = null and intent?.extras?.remove(NAVIGATION_BUNDLE)
}
Ok, I've got it (great thanks to this answer)! So this behavior can happen if you leave your activity with back button press. In this cases your activity will call onDestroy() method without calling onSaveInstanceState() and you will receive same intent over and over again (while clicking back to quit your app, of course). All you need to do is check if your app was called from recent. To do that you can implement this check before your main activity reading your intent:
if (intent.flags and FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY == 0) {
intent?.extras?.get(NAVIGATION_BUNDLE)?.let {
navController.setGraph(R.navigation.nav_graph, it as Bundle)
}
}
Flag FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY will appear if your app is launched from recent and that's a very tiny workaround for this particular problem. If this flag presented just don't read your intent and that's it.

Android how to start activity without intent or backround

Suppose I have two activities A and B activity A which contains a button I want to start Activity B when I press Button without intent.
According the Oficial Documentation:
An intent is an abstract description of an operation to be performed. It can be used with startActivity to launch an Activity, broadcastIntent to send it to any interested BroadcastReceiver components, and startService(Intent) or bindService(Intent, ServiceConnection, int) to communicate with a background Service.
An Intent provides a facility for performing late runtime binding between the code in different applications. Its most significant use is in the launching of activities, where it can be thought of as the glue between activities. It is basically a passive data structure holding an abstract description of an action to be performed.
So you have to use it to open activities with no exceptions or workarounds, if you do that, you are ignoring the entire system architecture.
There is no way to start an activity from anotherone without an intent.
If the reason of not using Intent that you don't want the the user to re-enter the previous activity
You can use finish() to finish that activity intent after you done work with
if(currentUser == null){
startActivity(new Intent(MainActivity.this,StartActivity.class));
finish();
}
So user will be unable to back again
If you want to do some code while the activity is finishing
You can use onDestroy() override method, Sometimes it can also be called if the activity is being killed by the android itself so you can add
isFinishing() function
Inside onDestroy() method which checks whether the application is closing by the call finish() returning true or otherwise by anything else returning false then you can easily specify your code for each situation.
#Override
protected void onDestroy() {
super.onDestroy();
if(isFinishing()){
// Activity is being destroyed by the function `finish()`
// What to do...
}else{
// Activity is being destroyed anonymously without `finish()`
// What to do...
}
}
Put your activity inside a Fragment and start the fragment fromo the button.
These are the possible ways to start any Activity
1st
startActivity(new Intent(Activity_A.this, Activity_B.class));
2nd
Intent intent = new Intent(Activity_A.this, Activity_B.class);
startActivity(intent);
3rd
Intent intent = new Intent(Activity_A.this, Activity_B.class);
startActivityForResult(intent,code);

How can I not return to a previous activity after using startActivity?

Assuming I have three activities with Android Studio:
Act_A
Act_B
Act_C
The Act_A calls Act_B, and Act_B calls Act_C:
Intent intent = new Intent(Act_A.class,Act_B.class);
startActivity(intent);
...
Intent intent = new Intent(Act_B.class,Act_C.class);
startActivity(intent);
In Act_C a process is executed in which it should automatically be returned to Act_B, for which something similar is done:
Intent intent = new Intent(Act_C.class,Act_B.class);
startActivity(intent);
At this point, if the user presses the return button, it should be returned to Act_A, but it happens to be returned to Act_C, if you press once again the return button returns to Act_B.
My questions are:
Is there a way to "delete" the previous state so that it doesn't return to the previous activity or is there a way to modify it to return to the activity that I want?
The problem is that I have to return a value from Act_C to Act_B and I can not use finish(), something similar to the following:
In Act_C:
Intent intent = Act_B.newIntent(getActivity(),5);// return 5
startActivity(intent);
Thanks
You can call the finish() method of an Activity. It will get you back to Activity_B while you are in Activity_C
You can customize the back stack of your activity if you really need to, but in this case it seems that what you want is just to go back to B from C, instead of starting B from C.
In other words, in order to accomplish "In Act_C a process is executed in which it should automatically be returned to Act_B", do the following instead of startActivity():
super.onBackPressed();
This will return the app to Act_B. Then if the user presses the back button, they will return to Act_A as you specified.
Basically you can either call finish() on your activity, use the noHistory flag for the activity in your AndroidManifest.xml, or add the intent flag Intent.FLAG_ACTIVITY_NO_HISTORY to your intent.
This post should help you out: Removing an activity from the history stack
In Act_C a process is executed in which it should automatically be returned to Act_B
If you just want to return a value from a specific activity don't use startActivity(Intent), use startActivityForResult(Intent, int) and deal with the return values on the callback (OnActivityResult). Then overwrite the onFinish() method so that you can setResult() upon exit.
I can give you more context on this if you need.

android launched activity exit callback function

I am launching the android setting activity, from an android service.
Intent LaunchIntent = getPackageManager().getLaunchIntentForPackage("com.android.settings");
startActivity(LaunchIntent);
I am searching, how I can detect if the setting activity is closed,As I need some callback method.
If there is a callback method to know the settings or any other app like browsers,if launched in this method to know if the launched activity is exit its own.
Since settings and browsers are general code we can't put broadcast code in these activities.
Use startActivityForResult to launch the settings activity like so:
Intent LaunchIntent =
getPackageManager().getLaunchIntentForPackage("com.android.settings");
startActivityForResult(LaunchIntent, 42);
Usually, you would use a specific request code as the second argument, but in this case, you have no control over what the settings Activity could return as a result, and you only want to know when it finishes, so you can essentially make up a request code. It must be greater than 0, however. The docs state this here:
requestCode If >= 0, this code will be returned in onActivityResult() when the activity exits.
Then, you can override the onActivityResult method to handle what happens when the settings activity closes:
#Override
protected void onActivityResult (int requestCode, int resultCode, Intent data){
// Do whatever you would like to do
}
If you had used a specific request code when you started the Activity, this is where you would check if the result code exists, but since we aren't expecting any real result, the result code will likely be equal to RESULT_CANCELLED, but that's okay since you at least know that the Activity was cancelled.

Categories

Resources