There are many ways to realize communication between two fragments, such as: EventBus: it is easy to use, but it uses reflection principle, has a little delay, and is not convenient for others to maintain; Static static variables: Easy to use. However, each static variable occupies a chunk of memory. The Android system has a limited amount of memory allocated to each App (63M). Broadcast Receiver: Android Broadcast is limited. Except for system Broadcast, use other Broadcast as little as possible. In addition, there will be delays in broadcasting; Interface: Interface is a common method of communication between fragments. The communication between two fragments can be realized by using a main Activity as a communication bridge (Google official statement: two fragments should never communicate directly). The interface approach is recommended. However, the traditional interface approach can cause some problems. If the main Activity implements a communication callback interface with multiple fragments, its code structure will look like this: Step 1: Define the interface
[java] view plain copy
public interface Fragment1CallBack {
void buttonClick1();
}
Step 2: Fragment calls the interface
[java] view plain copy
public class Fragment1 extends Fragment {
private TextView tv; private Button btn; private Fragment1CallBack fragment1CallBack; @Nullable @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_layout,null); tv = (TextView) view.findViewById(R.id.textView); btn = (Button) view.findViewById(R.id.button); Btn.setonclicklistener (new view.onClickListener () {@override public void onClick(View v) {// Call interface method fragment1CallBack.buttonClick1(); }}); tv.setText(this.getClass().getSimpleName()); return view; } @Override public void onAttach(Context context) { super.onAttach(context); Try {fragment1CallBack = (fragment1CallBack) context; } catch (ClassCastException e) { throw new ClassCastException(context.toString() + " must implement Fragment1CallBack"); }}Copy the code
}
Step 3: The Activity implements the interface callback
[java] view plain copy
public class MainActivity extends AppCompatActivity implements RadioGroup.OnCheckedChangeListener,
Fragment1CallBack,
Fragment2CallBack,
Fragment3CallBack,
Fragment4CallBack{
private ViewPager viewpager; private RadioGroup radioGroup; private MyPagerAdapter adapter; private List<Fragment> fragments = new ArrayList<>(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); viewpager = (ViewPager) findViewById(R.id.viewpager); radioGroup = (RadioGroup) findViewById(R.id.radioGroup); radioGroup.setOnCheckedChangeListener(this); fragments.add(new Fragment1()); fragments.add(new Fragment2()); fragments.add(new Fragment3()); adapter = new MyPagerAdapter(getSupportFragmentManager(), fragments); viewpager.setAdapter(adapter); viewpager.setCurrentItem(0,false); viewpager.setOffscreenPageLimit(3); viewpager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() { @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { } @Override public void onPageSelected(int position) { } @Override public void onPageScrollStateChanged(int state) { } }); } @Override public void onCheckedChanged(RadioGroup group, @IdRes int checkedId) { switch (checkedId){ case R.id.radio1: viewpager.setCurrentItem(0); break; case R.id.radio2: viewpager.setCurrentItem(1); break; case R.id.radio3: viewpager.setCurrentItem(2); break; }} @override public void buttonClick1() {// Fragment2 callback} @override public void buttonClick2() {// Fragment2 callback} @override public void buttonClick3() {// Fragmentclick4 () {@override public void buttonClick4() {// Fragment4 ()}Copy the code
}
The above traditional method is fine if there are few callback interfaces, but if there are many interfaces, then you need to implement a lot of interface methods in the Activity class declaration, which is particularly tedious.
In order to solve this tedious operation, we use object-oriented thinking, the interface is abstracted into an object, an interface contains functions (function name, return value, parameters, not implemented function body). Therefore, we can define the following classes: Function class (the base class of the interface abstract class) :
[java] view plain copy
public abstract class Function {
public String mFunctionName;
public Function(String functionName){
this.mFunctionName = functionName;
}
Copy the code
} FunctionNoParamNoResault class (no parameters, no return value interface abstract class) : [Java] View plain Copy
public abstract class FunctionNoParamNoResault extends Function{ public FunctionNoParamNoResault(String functionName){ super(functionName); } public abstract void function(); } FunctionWithParamAndResult class (abstract class and returns a value interface) : [Java] view plain copy
public abstract class FunctionWithParamAndResult
extends Function{ public FunctionWithParamAndResult(String functionName){ super(functionName); } public abstract Result function(Param pram); } FunctionWithParamOnly class (with parameters and no return value interface abstract class) :
[java] view plain copy
public abstract class FunctionWithParamOnly extends Function{
public FunctionWithParamOnly(String functionName){
super(functionName);
}
public abstract void function(Param pram);
}
FunctionWithResultOnly class (interface abstract class with no parameters and return values) :
[java] view plain copy
public abstract class FunctionWithResultOnly extends Function{
public FunctionWithResultOnly(String functionName){
super(functionName);
}
public abstract Result function();
}
After defining all the interface abstract classes, we define an interface management class to manage the invocation of corresponding function methods.
FunctionManager class (managing and calling different methods) :
[java] view plain copy
public class FunctionManager {
private static FunctionManager instance;
private HashMap<String,FunctionNoParamNoResault> mFunctionNoParamNoResault;
private HashMap<String,FunctionWithParamOnly> mFunctionWithParamOnly;
private HashMap<String,FunctionWithResultOnly> mFunctionWithResultOnly;
private HashMap<String,FunctionWithParamAndResult> mFunctionWithParamAndResult;
private FunctionManager() { mFunctionNoParamNoResault = new HashMap<>(); mFunctionWithParamOnly = new HashMap<>(); mFunctionWithResultOnly = new HashMap<>(); mFunctionWithParamAndResult = new HashMap<>(); } public static FunctionManager getInstance(){ if(instance == null){ instance = new FunctionManager(); } return instance; } /** * add interface method * @param function * @return */ public FunctionManager addFunction(FunctionNoParamNoResault function){ mFunctionNoParamNoResault.put(function.mFunctionName,function); return this; } /** * invokeFunc(String funcName){if(textutils.isempty (funcName) == true){ return; } if(mFunctionNoParamNoResault ! = null){ FunctionNoParamNoResault f = mFunctionNoParamNoResault.get(funcName); if(f ! = null){ f.function(); } if (f == null){ try { throw new FunctionException("Has no this function" + funcName); } catch (FunctionException e) { e.printStackTrace(); }}}} /** * Add interface method with no parameters and return value * @param function * @return */ public FunctionManager addFunction(FunctionWithResultOnly) function){ mFunctionWithResultOnly.put(function.mFunctionName,function); return this; } @param funcName */ public <Result> Result invokeFunc(String funcName,Class<Result> CLZ){ if(TextUtils.isEmpty(funcName) == true){ return null; } if(mFunctionWithResultOnly ! = null){ FunctionWithResultOnly f = mFunctionWithResultOnly.get(funcName); if(f ! = null){ if(clz ! = null){ return clz.cast(f.function()); } else { return (Result) f.function(); } }else { try { throw new FunctionException("Has no this function" + funcName); } catch (FunctionException e) { e.printStackTrace(); } } } return null; } / * * * add a reference the return value of the interface methods * @ param function * @ return * / public FunctionManager addFunction (FunctionWithParamAndResult function){ mFunctionWithParamAndResult.put(function.mFunctionName,function); return this; } @param funcName */ public <Result, param > Result invokeFunc(String funcName,Class<Result> CLZ ,Param data){ if(TextUtils.isEmpty(funcName) == true){ return null; } if(mFunctionWithParamAndResult ! = null){ FunctionWithParamAndResult f = mFunctionWithParamAndResult.get(funcName); if(f ! = null){ if(clz ! = null){ return clz.cast(f.function(data)); } else { return (Result) f.function(data); } }else { try { throw new FunctionException("Has no this function" + funcName); } catch (FunctionException e) { e.printStackTrace(); } } } return null; } @param function @return */ public FunctionManager addFunction(FunctionWithParamOnly function){ mFunctionWithParamOnly.put(function.mFunctionName,function); return this; } @param funcName */ public < param > void invokeFunc(String funcName, param data){ if(TextUtils.isEmpty(funcName) == true){ return ; } if(mFunctionWithParamOnly ! = null){ FunctionWithParamOnly f = mFunctionWithParamOnly.get(funcName); if(f ! = null){ f.function(data); }else { try { throw new FunctionException("Has no this function" + funcName); } catch (FunctionException e) { e.printStackTrace(); } } } return ; }Copy the code
}
Then, define a base class for the Fragment that uses the callback interface.
BaseFragment class:
[java] view plain copy
public class BaseFragment extends Fragment{
protected FunctionManager mFunctionManager; private MainActivity mBaseActivity; /** * Add FunctionManager * @param FunctionManager */ public void setmFunctionManager(FunctionManager functionManager){ this.mFunctionManager = functionManager; } @override public void onAttach(context context) {Override public void onAttach(context context) { super.onAttach(context); if(context instanceof MainActivity){ mBaseActivity = (MainActivity) context; mBaseActivity.setFuctionsForFragment(getTag()); }}Copy the code
}
In a specific Fragment class, call the interface. Such as:
Class Fragment3 (calling interface methods with arguments and return values) :
[java] view plain copy
public class Fragment3 extends BaseFragment{ private TextView tv; private Button btn; Public static final String INTERFACE_PARAM_RESULT = fragment1.class.getName () + “PR”;
@Nullable @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_layout,null); tv = (TextView) view.findViewById(R.id.textView); tv.setText(this.getClass().getSimpleName()); btn = (Button) view.findViewById(R.id.button); Btn.setonclicklistener (new view.onClickListener () {@override public void onClick(View v) {String STR = MFunctionManager. InvokeFunc (INTERFACE_PARAM_RESULT, String class, "I am transmission String"); Toast.makeText(getActivity(),str,Toast.LENGTH_SHORT).show(); }}); return view; }Copy the code
}
Add an interface to MainActivity and implement the interface method:
MainActivity class:
[java] view plain copy
public class MainActivity extends AppCompatActivity implements RadioGroup.OnCheckedChangeListener{
private ViewPager viewpager; private RadioGroup radioGroup; private MyPagerAdapter adapter; private List<Fragment> fragments = new ArrayList<>(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); viewpager = (ViewPager) findViewById(R.id.viewpager); radioGroup = (RadioGroup) findViewById(R.id.radioGroup); radioGroup.setOnCheckedChangeListener(this); fragments.add(new Fragment1()); fragments.add(new Fragment2()); fragments.add(new Fragment3()); fragments.add(new Fragment4()); adapter = new MyPagerAdapter(getSupportFragmentManager(), fragments); viewpager.setAdapter(adapter); viewpager.setCurrentItem(0,false); viewpager.setOffscreenPageLimit(4); viewpager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() { @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { } @Override public void onPageSelected(int position) { } @Override public void onPageScrollStateChanged(int state) { } }); } @Override public void onCheckedChanged(RadioGroup group, @IdRes int checkedId) { switch (checkedId){ case R.id.radio1: viewpager.setCurrentItem(0); break; case R.id.radio2: viewpager.setCurrentItem(1); break; case R.id.radio3: viewpager.setCurrentItem(2); break; case R.id.radio4: viewpager.setCurrentItem(3); break; }} public void setFuctionsForFragment(String tag){FragmentManager FM = getSupportFragmentManager(); BaseFragment fragment = (BaseFragment) fm.findFragmentByTag(tag); FunctionManager functionManager = FunctionManager.getInstance(); fragment.setmFunctionManager(functionManager.addFunction(new FunctionNoParamNoResault(Fragment1.INTERFACE) { @Override Public void function() {toast.maketext (mainactivity.this," toast.length_short ", toast.length_short).show(); } }).addFunction(new FunctionWithResultOnly<String>(Fragment2.INTERFACE_RESULT) { @Override public String function() { // return "I Love U"; } }).addFunction(new FunctionWithParamAndResult<String,String>(Fragment3.INTERFACE_PARAM_RESULT) { @Override public String function(String pram) {return pram; } }).addFunction(new FunctionWithParamOnly<String>(Fragment4.INTERFACE_PARAM) { @Override public void function(String Toast.maketext (mainactivity.this," successfully called interface with arguments and no return value: "+ pram, toast.length_short).show(); }})); }Copy the code
}