Communications Among Activities and Fragments

来源:互联网 发布:2015java面试宝典下载 编辑:程序博客网 时间:2024/06/05 06:53

NOTE: Here I intentionally give an reference rather than an instructive tuition. So if you find things obscure, you may need to find an more gentle guide firstly. If you find any mistakes or errors, please DO tell me and much obliged!

There are four forms of communications among activities and fragments:

  • Activity –> AnotherActivity
  • Activity –> Fragment
  • Fragment –> AnotherFragment
  • Fragment –> Activity

Every form (A–>B) has three communication ways (but maybe not all of them are effective):

  • A starts B
  • A tells B something
  • A expects B’s answer

Below I explain the setup for every communication among activities and fragments.


1. Activity –> AnotherActivity


You want to start AnotherActivity from Activity, you should do steps as follow:

  • Get AnotherActivity ready, including AnotherActivity.java, activity_another.xml, maybe something else.
  • Declare this AnotherActivity in manifest or you will not be able to use it.
// In manifest<activity android:name=".AnotherActivity"></activity>
  • You may want to add a trigger in Activity so you can intently start AnotherActivity when you intentionally to do so.
  • To wire up Activity and AnotherActivity, you gonna need an Intent:
// In ActivityIntent intent = new Intent(Activity.this, AnotherActivity.class);
  • Finally, start AnotherActivity with the intent:
startActivity(intent);

You may want to carry a msg for AnotherActivity when you start it so ActivityActivity can act according to your msg. This can be achieved via intent. This is a little bit tricky but you can handle it:

  • Set up a newIntent() method in AnotherActivity.java (Cause after all, it is AnotherActivity who is using this msg, so it is better to store the msg in the space of AnotherActivity)
// In AnotherActivityprivate static final String EXTRA_MSG = "KEY_NAME";... ...public static Intent newIntent(Context packageContext, String msg) {Intent intent = new Intent(packageContext, AnotherActivity.class); intent.putExtra(EXTRA_MSG, msg); return intent;}
  • In Activity, you still need an Intent to start AnotherAcitivity, only now you get the Intent through static method AnotherActivity.newIntent(Context, String):
// In Activiy... ...// Method we just define in AnotherActivity:Intent intent = AnotherActivity.newIntent(Activity.this, msg);startActivity(intent);
  • Now the msg has been passed through Intent to the space of AnotherActivity, AnotherActivity can retrieve this msg through methods as follow:
// In AnotherActivityprivate String mMsg;... ...mMsg = getIntent.getStringExtra(EXTRA_MSG);

Sometime, you need to know how did it go with AnotherActivity, you need a feedback from it. At this time, you need to call method startActivityForResult(Intent, int) instead of startActivity(Intent) to make clear that you want a result from AnotherActivity:

  • Specify your intention to get a result from child activity – AnotherActivity, by calling startActivityForResult(Intent, int), You also need a result code (an int) to mark your result in case there are more than one results come back.
// In Activity// NOTE the request code is private// which means you are not gonna to use it beyond Activity.private static final int REQUEST_CODE_ANOTHER = 0;... ... startActivityForResult(intent, REQUEST_CODE_ANOTHER);
  • In this case you have to response to the parent activity’s request for a results. Typically, you can call these two methods in child activity:
public final void setResult(int resultCode);// orpublic final void setResult(int resultCode, Intent data);
  • Also, AnotherAcitivity may response Activity in different ways: YES, NO, CANCEL, or something like that. So you need different result code for different response. There are some predefined constants: Activity.RESULT_OK, Activity.RESULT_CANCELED.
  • (If you don’t specifically give a result for Activity, aka, you don’t explicitly call setResult(int) or setResult(int, Intent), the OS still will give Activity a default result)
  • If AnotherActivity have more to say to Activity, it can stash the data in an intent and return to Activity:
// A private String to idenfity the answer:private static final String EXTRA_ANSWER_ANOTHER = "answer";... ... // A private method to stash the answer to an intent and// call setResult(int, Intent) to set the result:private void setAnswer(String answer){   Intent data = new Intent();   data.putExtra(EXTRA_ANSWER_ANOTHER, answer);   setResult(RESULT_OK, data);}// A static method for Activity to reture the answer:public static String returnAnswer(Intent result){return result.getStringExtra(EXTRA_ANSWER_ANOTHER);}
  • If a Activity has start a AnotherActivity and expect for a result, the OS will take care of most of the works and make sure it will get one. To handle the results returned by its child activity, you override method onActivityResult(int requestCode, int resultCode, Intent data):
private String mAnswer;... ...@overrideprotected void onActivityResult(int requestCode, int resultCode, Intent data){// Check the data to be certain it is what you expect:if (resultCode != Activity.RESULT_OK)return;if (requestCode == REQUEST_CODE_ANOTHER) {if (data == null) return;}// This is a very brilliant way to do it:mAnswer = AnotherActivity.returnAnswer(data);}

So, you get what you’re expecting…


2. Activity –> Fragment

A fragment is a “widget” comprising your whole layout, you can handle the fragment independently, but a fragment’s visibility is dependent on Activity. Fragment add extra flexibility for UI design and handling.


You want to start a Fragment from an Activity (a.k.a adding this fragment to the view of Activity).

  • Get Fragment ready,including TheFragment.java, fragment_the.xml, or something else.
  • Prepare a container in Activity’s layout, or you have nowhere to put the view of TheFragment.
  • Prepare the view of TheFragment by override Fragment.onCreate(Bundle) and Fragment.onCreateView(inflater, container, saveInstanceState):
@Override    public void onCreate(@Nullable Bundle savedInstanceState) {        super.onCreate(savedInstanceState);    }@Nullable@Overridepublic View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {        return super.onCreateView(inflater, container, savedInstanceState);    }
  • For Activity to manage Fragment, it will need a FragmentManager, which manages all the Fragments.
FragmentManager fm = getSupportFragmentManager();Fragment fragment = fm.findFragmentById(R.id.fragment_container);      if (fragment == null) {          fragment = new TheFragment();          fm.beginTransaction()                  .add(R.id.fragment_container, fragment)                  .commit();        }

Sometime you want to pass an argument to the Fragment from Activity, this can be done via a Fragment Argument. Because it is the Fragment who need the argument, we better stash this argument in the space of Fragment rather than of Activity.

Every Fragment has a Bundle object attached to it, which works just like Intent, which contains key-value pairs.

  • First you prepare a Bundle in Fragment to set the argument. Conventionally, we define a method which accept the msg you want to delivery as argument:
private static final String ARG_UUID = "ARG_FRAGMENT";... ...public static TheFragment newInstance (UUID id){Bundle args = new Bundle();args.putSerializable(ARG_UUID, id);TheFragment fragment = new TheFragment();// Call Fragment.setArgments(Bundle) to set arguments for this Fragment:fragment.setArguments(args);return fragment;}
  • In Activity, you call newInstance(UUID) we just defined above to pass the msg you want to deliever to the Bundle of TheFragment:
FragmentManager fm = getSupportFragmentManager();Fragment fragment = fm.findFragmentById(R.id.fragment_container);      if (fragment == null) {// Here you use the static method we just defined// in TheFragment and stash the msg in the Bundle of // TheFragment & return the instance of Fragment.         fragment = TheFragment.newInstance(id);          fm.beginTransaction()                  .add(R.id.fragment_container, fragment)                  .commit();        }
  • Now you can retrieve the msg in the Fragment by simply calling getArguments():
UUID id = getArguments().getSerializable(ARG_UUID);

Sometimes, Activity expects to get a results from the Fragment it starts. But a Fragment can receive a result from an Activity, but it CANNOT have its own result. Only activities have results. For Fragments, they do NOT have setResults() method.

Fragment can return a value by calling its parent’s setResult() method:

// In TheFragment:public void returnResult(){// getActivity return the hosting Activity// using hosting Activity its own setResults()getActivity().setResults(Activity.RESULT_OK, null);}

3. Fragment –> AnotherFragment

(To be clear, here we talk about fragments hosted by same Activity)
Fragments are attached to Activity and managed by FragmentManager, so if OneFragment wants to start AnotherFragment, it would need a FragmentManager.

// TODO


4. Fragment –> Activity

Now you want to start an Activity from a Fragment which works nearly the same as starting AnotherActivity from an Activity, it is simply as follows:

// In Fragment, you prepare an Intent// and call startActivity()Intent intent = new Intent(getActivity(), TargetActivity.class);startActivity(intent);

You may also want to deliver some msg for TargetActivity. You can achieve this by:

  • Define newIntent(String msg) method in TargetActivity
// In TargetActivity:private static final String EXTRA_MSG = "EXTRA_MSG";... ...public static Intent newIntent(Context packageContext, String msg){Intent intent = new Intent(packageContext, TargetActivity.class);intent.putExtra(EXTRA_MSG, msg);return intent;} 
  • Call newIntent(String) method in Fragment
// In Fragment:Intent = TargetActivity.newIntent(getActivity(), msg);startActivity(intent);
  • Retrieve msg by calling getIntent().getExtra(…)
// In TargetActivity:String msg = getIntent().getStringExtra(EXTRA_MSG);

What if fragment expects some answers from AnotherActivity?

This would work just like an Activity expects AnotherActivity’s response, only you call Fragment.startActivityForResult(…) instead of Activity.startActivityForResult(…). To retrieve answers, you override Fragment.onActivityResult(…) instead of Activity.onActivityResult(…).

Here I simply list the setup you need for this purpose:

  • In Fragment, you would need an Intent to start AnotherActivity, within this Intent, you probably stash some msg for AnotherActivity:
// In Fragmentprivate static final int REQUEST_CODE = 1;... ...Intent intent = AnotherActivity.newIntent(getActivity(), String msg);startActivityForResult(intent, REQUEST_CODE);
  • Then in AnotherActivity, you need to set the answer via setResult(). To handle more than one result, you may be need to set resultCode to identify different answers.
  • Back in Fragment, you can retrieve the answer via override Fragment.onActivityResults(int requestCode, int resultCode, Intent data):
// In Fragmentpublic void onActivityResult(        int requestCode, int resultCode, Intent data){        // Handle different results}

Thanks for watching.

Should you have any questions, please leave a msg below.