Tuesday, November 23, 2010

Activity Result: The Secret of Passing Information From a Child to a Parent

When an Activity closes or "stops" in Android, how do we pass information back to the parent that started this Activity? The trick is to use Activity Result following this 3-step design pattern:

Step 1: In the parent activity, start the child activity with startActivityForResult()
public class Parent extends Activity {
   private final void startChildOnClick() {
      Intent intent = new Intent(this, Child.class);
      intent.setAction(MyConstants.ACTION_START_CHILD);
      intent.putExtra("Parent Uid", Process.myUid());
      startActivityForResult(intent, 10);
   }
}

Step 2: In the parent activity, override onActivityResult():
public class Parent extends Activity {
   private final void startChildOnClick() {
      Intent intent = new Intent(this, Child.class);
      intent.setAction(MyConstants.ACTION_START_CHILD);
      intent.putExtra("Parent Uid", Process.myUid());
      startActivityForResult(intent, 10);
   }

   @Override
   protected final void onActivityResult(final int requestCode, 
                                         final int resultCode, 
                                         final Intent data) {
      // !!! Called before onRestart() if the parent was 
      // not destroyed!!!
      super.onActivityResult(requestCode, resultCode, data);
      if (requestCode == 10 && resultCode == 20) {
         if (data != null) {
            int cUid = data.getString("Child Uid");
            // Be careful to when to use the data passed 
            // from child
         }
      }
   }
}
It is very important to understand when onActivityResult() is called in the Activity lifecyle. If the parent activity was not destroyed before it is brought back to the foreground again, the calling sequence will be:
onStop() --> onActivityResult() --> onRestart() --> onStart() --> onResume()
Here, a good design pattern for processing data passed from the child is to delay processing to after onStart() by handing off the data to a Handler.

Step 3: In the child activity, override finish():
public class Child extends Activity {
   @Override
   public final void finish() {
      Intent intent = new intent(this, Parent.class);
      intent.putExtra("Child Uid", Process.myUid());
      // Android will pass the result set here to the parent
      setResult(20, intent);
      super.finish(); // Must be called last!!
   }
}
Note that the child must call call super.finish() as the very last statement in the block.
That's it. Happy hacking!

* Updated on December 01, 2010.

No comments:

Post a Comment