1

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.

reixa
  • 6,903
  • 6
  • 49
  • 68
  • 1
    "The navigation inside APP2" -- `startActivityForResult()` is not designed for this sort of a situation. It is designed for a case where you are starting an activity that does something (e.g., presents a list of options for the user) and returns a result, without navigating elsewhere. You may wish to consider modifying APP2 to use a single-activity architecture, where you use multiple fragments for your different steps instead of multiple activities. – CommonsWare Feb 13 '19 at 13:47

1 Answers1

1

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:

  1. 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().

  1. 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()`.

  1. 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.

David Wasser
  • 93,459
  • 16
  • 209
  • 274
  • 1
    This is the most accurate answer but ended using CommonsWare´s comment approach. Thanks both! – reixa Feb 19 '19 at 09:13