可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I currently have a fragment in an overlay. This is for signing in to the service. In the phone app, each of the steps I want to show in the overlay are their own screens and activities. There are 3 parts of the sign-in process and each had their own activity that was called with startActivityForResult().
Now I want to do the same thing using fragments and an overlay. The overlay will show a fragment corresponding to each activity. The problem is that these fragments are hosted in an activity in the Honeycomb API. I can get the first fragment working, but then I need to startActivityForResult(), which isn't possible. Is there something along the lines of startFragmentForResult() where I can kick off a new fragment and when it's done have it return a result to the previous fragment?
回答1:
All of the Fragments live inside Activities. Starting a Fragment for a result doesn't make much sense, because the Activity that houses it always has access to it, and vice versa. If the Fragment needs to pass on a result, it can access its Activity and set its result and finish it. In the case of swapping Fragments in a single Activity, well the Activity is still accessible by both Fragments, and all your message passing can simply go through the Activity.
Just remember that you always have communication between a Fragment and its Activity. Starting for and finishing with a result is the mechanism for communication between Activities - The Activities can then delegate any necessary information to their Fragments.
回答2:
If you wish, there are some methods for communication between Fragments,
setTargetFragment(Fragment fragment, int requestCode)
getTargetFragment()
getTargetRequestCode()
You can callback using these.
Fragment invoker = getTargetFragment();
if(invoker != null) {
invoker.callPublicMethod();
}
回答3:
My 2 cents.
I switch beween fragments by swapping an old fragment with a new one using hide and show/add (existing/new). So this answer is for devs who use fragments like I do.
Then I use the onHiddenChanged
method to know that the old fragment got switched to back from the new one. See code below.
Before leaving the new fragment, I set a result in a global parameter to be queried by the old fragment. This is a very naive solution.
@Override
public void onHiddenChanged(boolean hidden) {
super.onHiddenChanged(hidden);
if (hidden) return;
Result result = Result.getAndReset();
if (result == Result.Refresh) {
refresh();
}
}
public enum Result {
Refresh;
private static Result RESULT;
public static void set(Result result) {
if (RESULT == Refresh) {
// Refresh already requested - no point in setting anything else;
return;
}
RESULT = result;
}
public static Result getAndReset() {
Result result = RESULT;
RESULT = null;
return result;
}
}
回答4:
In your fragment you can call getActivity(). This will give you access to the activity that created the fragment. From there you can call your customize method to set the values or to pass the values.
回答5:
There is an Android library - FlowR that allows you to start fragments for results.
Starting a fragment for result.
Flowr.open(RequestFragment.class)
.displayFragmentForResults(getFragmentId(), REQUEST_CODE);
Handling results in the calling fragment.
@Override
protected void onFragmentResults(int requestCode, int resultCode, Bundle data) {
super.onFragmentResults(requestCode, resultCode, data);
if (requestCode == REQUEST_CODE) {
if (resultCode == Activity.RESULT_OK) {
demoTextView.setText("Result OK");
} else {
demoTextView.setText("Result CANCELED");
}
}
}
Setting the result in the Fragment.
Flowr.closeWithResults(getResultsResponse(resultCode, resultData));
回答6:
The easiest way to pass data back is by setArgument(). For example, you have fragment1 which calls fragment2 which calls fragment3, fragment1 -> framgnet2 -> fargment3
In fragment1
public void navigateToFragment2() {
if (fragmentManager == null) return;
Fragment2 fragment = Fragment2.newInstance();
String tag = "Fragment 2 here";
fragmentManager.beginTransaction()
.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE)
.add(R.id.flContent, fragment, tag)
.addToBackStack(null)
.commitAllowingStateLoss();
}
In fragment2 we call fragment3 as usual
private void navigateToFragment3() {
if (fragmentManager == null) return;
Fragment3 fragment = new Fragment3();
fragmentManager.beginTransaction()
.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE)
.replace(R.id.flContent, fragment, tag)
.addToBackStack(null)
.commit();
}
When we finished our task in fragment3 now we call like this:
FragmentManager fragmentManager = getActivity().getSupportFragmentManager();
if (fragmentManager == null) return;
fragmentManager.popBackStack();
Bundle bundle = new Bundle();
bundle.putString("bundle_filter", "data");
fragmentManager.findFragmentByTag("Fragment 2 here").setArguments(bundle);
Now in fragment2 we can easily call arguments
@Override
public void onResume() {
super.onResume();
Bundle rgs = getArguments();
if (args != null)
String data = rgs.getString("bundle_filter");
}
回答7:
A solution using interfaces (and Kotlin). The core idea is to define a callback interface, implement it in your activity, then call it from your fragment.
First, create an interface ActionHandler
:
interface ActionHandler {
fun handleAction(actionCode: String, result: Int)
}
Next, call this from your child (in this case, your fragment):
companion object {
const val FRAGMENT_A_CLOSED = "com.example.fragment_a_closed"
}
fun closeFragment() {
try {
(activity as ActionHandler).handleAction(FRAGMENT_A_CLOSED, 1234)
} catch (e: ClassCastException) {
Timber.e("Calling activity can't get callback!")
}
dismiss()
}
Finally, implement this in your parent to receive the callback (in this case, your Activity):
class MainActivity: ActionHandler {
override fun handleAction(actionCode: String, result: Int) {
when {
actionCode == FragmentA.FRAGMENT_A_CLOSED -> {
doSomething(result)
}
actionCode == FragmentB.FRAGMENT_B_CLOSED -> {
doSomethingElse(result)
}
actionCode == FragmentC.FRAGMENT_C_CLOSED -> {
doAnotherThing(result)
}
}
}
回答8:
Another thing you could do depending on your architecture is use a shared ViewModel between the fragments. So in my case FragmentA is a form, and FragmentB is a item selection view where the user can search and select an item, storing it in the ViewModel. Then when I come back to FragmentA, the information is already stored !
回答9:
You can use EventBus. It simplifies communication between Activities, Fragments, Threads, Services, etc. Less code, better quality.