自从fragment出现以来,很多app都开始使用fragment做界面,由于fragment的生命周期比activity丰富,如果管理不好fragment,就是增加开发难度,如果对fragment的生命周期管理到位就会事半功倍,按我的理解,fragment的生命周期其实就是activity生命周期的加强版,很多生命周期的方法和activity生命周期的方法是一个效果的,如果你的应用design不是android的那种design,很多都是自定义的,那么你可以尝试使用只有一个activity的编码(其实一般来说,在普通的开发中并没有什么卵用,但如果你使用插件技术吧fragment做出插件,界面跳转无需什么,可以增加删除,那意义就重大了)。
如何管理fragment的回退栈
一般的,你会想到使用popbackstack,其实popbackstack只是fragment的事务回退操作,注意了是事务,fragment的事务回退包括了fragment状态的回退,事务处理在处理自定义的复杂fragment跳转就会变得很繁琐,甚至不明白会应为不明白他的原理而研究他的源码!
在这里,我用的方法是hide,show,remove等方法对fragment经常自定义的管理。
假设你要启动一个fragment,那么将它实例化后add进来,add之前要对所有的fragment都做hide处理,不然底部会出现上一个fragment的背景,甚至能够点击。
假如你按了返回键,回到上一个fragment,那么从fragmentManger里面获取fragmentList(请勿对它操作,不然会出问题),注意了,这个fragmentList的顺序不一定跟你add的顺序一致,而且部分fragment销毁掉的,在这个list里面会空,对于没有顺序的fragmentList,我们需要对fragment设置Tag标记fragment是第几个add进去的,按返回键的时候,枚举一次fragmentList,按照tag,取到上一个界面的fragment,然后remove当前fragment,show出上一个fragment。
如何像activity那样finish掉指定界面?
如果你拿到他的实例,直接remove掉,如果你只有fragment的Class,那么枚举fragmentList,判断className相同后删除。
如果给fragment添加载入退出动画
抛开fragment动画,你一定会知道app中不一定全部activity载入动画是相同的,那么这个一个让fragmentOnlySupport一定也要能知道不同fragment对应不同的动画,此时,如何给fragment设置对应的动画?还是给fragment设置Tag,上面讲到fragment设置加载的index,那么index和动画一起加起来,可以用json作为字符串,把index和对应的动画都绑定在一起。
创建实体与之对应:
public class FragmentTagVo {
public FragmentTagVo(){};
public FragmentTagVo(int index, String animType) {
this.index = index;
this.animType = animType;
}
public String animType;
public int index;
public static FragmentTagVo build(String json) {
FragmentTagVo tagVo = new FragmentTagVo();
try {
JSONObject jsonObject = new JSONObject(json);
tagVo.index = jsonObject.getInt("index");
tagVo.animType = jsonObject.getString("animType");
} catch (Exception e) {
e.printStackTrace();
}
return tagVo;
}
@Override
public String toString() {
JSONObject jsonObject = new JSONObject();
try {
jsonObject.put("index",index);
jsonObject.put("animType",animType);
} catch (Exception e) {
e.printStackTrace();
}
return jsonObject.toString();
}
}
在加载fragment的时候设置tag:
fragmentIndex++;
FragmentTagVo tagVo = new FragmentTagVo(fragmentIndex,animType==null?AnimType.NONE.toString():animType.toString());
try {
mFragmentTransaction.add(containerId, tagfragment, tagVo.toString());
} catch (Exception e) {
e.printStackTrace();
}
mFragmentTransaction.show(tagfragment);
mFragmentTransaction.commitAllowingStateLoss();
KeyboradUtil.hideSoftKeyboard(this);
返回时找到上一个fragment的方法:
PLog.i("list:" + fragmentlist);
for (int i = fragmentlist.size()-1; i >= 0 ; i--) {
Fragment fragment = fragmentlist.get(i);
if (!(fragment == null || !fragment.isVisible())) {//可视且不是没有设置view的fragment
//这里可以写应用自己的返回逻辑
//
Fragment backFragment = null;
PLog.d("tag:" + fragment.getTag());
FragmentTagVo tagVo = JSONObject.parseObject(fragment.getTag(),FragmentTagVo.class);
int fragIndex = tagVo.index-1;
Looper:
while (fragIndex >= 0) {//从list后面开始找,高效查找方法
FindByTag:
for (AnimType animType:AnimType.values()) {
tagVo = new FragmentTagVo(fragIndex,animType.toString());
backFragment = fragmentManager.findFragmentByTag(JSONObject.toJSONString(tagVo));
if (backFragment!=null) {
break FindByTag;
}
}
PLog.d("backFragment:" + backFragment);
if (backFragment != null) {
PLog.d("backFragment add?:" + backFragment.isAdded());
PLog.d("backFragment removing?:" + backFragment.isRemoving());
}
if (backFragment == null || !backFragment.isAdded() || backFragment.isRemoving()) {
--fragIndex;
} else {
break Looper;
}
}
PLog.d("currFragment:" + fragment.getClass().getSimpleName());
PLog.d("backFragment:" + backFragment);
}
}
处理完动画绑定在fragment的逻辑,开始往fragment添加动画。
先声明一个动画枚举类,包括以下动画:
public enum AnimType {
NONE,//没有动画
LeftInRightOut,//左进右出
BottomInTopOut,//上进,往下出
ZoomShow//fragment默认缩放
;
public static int[] getAnimRes (AnimType animType){
switch (animType) {
case LeftInRightOut:
return new int[]{R.anim.push_left_in,R.anim.push_left_out,R.anim.back_left_in, R.anim.back_right_out};
case BottomInTopOut:
return new int[]{R.anim.push_bottom_in,R.anim.push_top_out,R.anim.push_bottom_in,R.anim.push_top_out};
default:
return new int[]{0,0,0,0};
}
}
}
add之前添加动画:
public void loadFragment(Fragment tagfragment, FragmentTransaction mFragmentTransaction,@NonNull AnimType animType) {
if (mFragmentTransaction == null) {
mFragmentTransaction = getSupportFragmentManager().beginTransaction();
}
//動畫
if (animType==AnimType.ZoomShow) {
mFragmentTransaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
} else if (animType== AnimType.LeftInRightOut) {
mFragmentTransaction.setCustomAnimations(R.anim.push_left_in, R.anim.push_left_out,R.anim.back_left_in,R.anim.back_right_out);
} else if (animType== AnimType.BottomInTopOut) {
mFragmentTransaction.setCustomAnimations(R.anim.push_bottom_in,R.anim.push_top_out,R.anim.push_bottom_in,R.anim.push_top_out);
} else {
//NONE
}
}
退出时设置对于退出动画:
public void backPressed () {
......code for find back Fragment
if (backFragment != null) {
tagVo = JSONObject.parseObject(fragment.getTag(),FragmentTagVo.class);
AnimType exitAnim = null;
if(tagVo!=null)
for (AnimType animType:AnimType.values()) {
if (animType.toString().equals(tagVo.animType.toString())) {
exitAnim = animType;
}
}
final Fragment animShowFragment = backFragment;
final Fragment animHideFragment = fragment;
if (exitAnim==null || exitAnim==AnimType.NONE) {
FragmentTransaction mFragmentTransaction = getSupportFragmentManager().beginTransaction();
mFragmentTransaction.show(animShowFragment);
mFragmentTransaction.remove(animHideFragment);
mFragmentTransaction.commitAllowingStateLoss();
} else if (exitAnim==AnimType.ZoomShow) {
FragmentTransaction mFragmentTransaction = getSupportFragmentManager().beginTransaction();
mFragmentTransaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_CLOSE);
mFragmentTransaction.show(animShowFragment);
mFragmentTransaction.remove(animHideFragment);
mFragmentTransaction.commitAllowingStateLoss();
} else {
int[] animRes = AnimType.getAnimRes(exitAnim);
Animation animation = AnimationUtils.loadAnimation(getApplicationContext(), animRes[3]);
animation.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
}
@Override
public void onAnimationEnd(Animation animation) {
FragmentTransaction mFragmentTransaction = getSupportFragmentManager().beginTransaction();
mFragmentTransaction.show(animShowFragment);
mFragmentTransaction.remove(animHideFragment);
mFragmentTransaction.commitAllowingStateLoss();
fragmentChangeing = false;
}
@Override
public void onAnimationRepeat(Animation animation) {
}
});
fragment.getView().startAnimation(animation);
backFragment.getView().setAnimation(AnimationUtils.loadAnimation(getApplicationContext(), animRes[2]));
}
} else {
finish();
}
}//end if (!(fragment == null || !fragment.isVisible())) {//可视的
.......code for do other
}
如果让fragment拦截返回事件,或实现带条件的返回?
重写activity的onBackPressed返回方法,加入以下代码,让fragment调用就Ok了:
public void setCanBackPress(boolean can) {
this.mCanBackPress = can;
}
protected boolean mCanBackPress = true;
protected OnBackPressedListener onBackPressedListener;
public void setOnBackPressedListener(OnBackPressedListener listener) {
this.onBackPressedListener = listener;
}
@Override
public void onBackPressed() {
if (onBackPressedListener != null) {
onBackPressedListener.OnBackKeyDown();
return;
}
if (!mCanBackPress) {
return;
}
backPressed();//该方法用于返回上一个fragment,如果没上一个界面了,最终执行finish
}
如果打通这些fragments通信通道?实现像activity的onActivityResult方法一样
类似于广播者模式,每个fragment都可以是观察者和被观察者,用onActivityResult充当Observer接口,用枚举fragmentList的Fragment调用onActivityResult方法充当被观察者。有以下代码:
public void pushMsgToSubFragments (boolean needShow,int pushCode,Intent pushData) {
pushMsgToSubFragments(getSupportFragmentManager(), needShow,pushCode, Activity.RESULT_OK, pushData);
}
public void pushMsgToSubFragments (@NonNull FragmentManager fragmentManager,boolean needShow,int requestCode,int resultCode, Intent data) {
List<Fragment> fragmentlist = fragmentManager.getFragments();
if (fragmentlist!=null)
for (Fragment fragment:fragmentlist) {
if (fragment==null) {
continue;
}
if (fragment.isAdded()) {
if (needShow) {
if (!fragment.isHidden()) {
PLog.i("send to:" + fragment);
fragment.onActivityResult(requestCode, resultCode, data);
}
} else {
PLog.i("send to:" + fragment);
fragment.onActivityResult(requestCode, resultCode, data);
}
//如果fragment里面还嵌套了fragment,继续观察
pushMsgToSubFragments(fragment.getChildFragmentManager(),needShow,requestCode,resultCode,data);
}
}
}
//Fragment里面重写onActivityResult接送观察类型和数据
如果activity调用其他activity,返回数据,继续重新onactivityresult方法:
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
PLog.i("onActivityResult:" + requestCode);
try {
super.onActivityResult(requestCode, resultCode, data);
} catch (Exception e) {
e.printStackTrace();
}
pushMsgToSubFragments(getSupportFragmentManager(), false, requestCode, resultCode, data);
}
最后献上完整代码:
import android.app.Activity;
import android.content.Intent;
import android.os.Build;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.util.Log;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import java.util.ArrayList;
import java.util.List;
/**
* Created by george.yang on 15/11/18.
*/
public abstract class FragmentOnlySupportActivity extends PlugBaseActivity {
public abstract int getContainerId();
private int containerId = getContainerId();
public static boolean fragmentChangeing = false;
public <T extends Fragment> T getFragment(@Nullable FragmentManager manager, Class clazz) {
return getFragment(manager, false, clazz);
}
public <T extends Fragment> T getFragment(@Nullable FragmentManager manager, boolean showing, Class clazz) {
if (clazz == null) {
return null;
}
if (manager == null) {
manager = getSupportFragmentManager();
}
List<Fragment> fragmentlist = manager.getFragments();
if (fragmentlist != null) {
for (Fragment fragment : fragmentlist) {
if (fragment == null || fragment.isRemoving() || !fragment.isAdded() || (showing && fragment.isHidden())) {
continue;
}
if (clazz.getName().equals(fragment.getClass().getName())) {
return (T) fragment;
} else {
Fragment fragmentInner = getFragment(fragment.getChildFragmentManager(), showing, clazz);
if (fragmentInner != null) {
return (T) fragmentInner;
}
}
}
}
return null;
}
public void loadFragment(Fragment tagfragment, FragmentTransaction mFragmentTransaction) {
loadFragment(tagfragment,mFragmentTransaction, AnimType.LeftInRightOut);
}
public void loadFragment(Fragment tagfragment) {
loadFragment(tagfragment,AnimType.LeftInRightOut);
}
public void loadFragment(String fragmenName) {
try {
loadFragment((Class<? extends Fragment>) Class.forName(fragmenName));
} catch (Exception e) {
e.printStackTrace();
}
}
public void loadFragment(Class<? extends Fragment> fragmentClass) {
try {
loadFragment((Fragment) fragmentClass.newInstance());
} catch (Exception e) {
e.printStackTrace();
}
}
public void loadFragment(Fragment tagfragment,@NonNull AnimType animType) {
loadFragment(tagfragment, null, animType);
}
private int fragmentIndex;
public void loadFragment(Fragment tagfragment, FragmentTransaction mFragmentTransaction,@NonNull AnimType animType) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
if (isDestroyed()) {
return;
}
}
if (isFinishing()) {
return;
}
PLog.i("load:" + tagfragment);
if (!fragmentChangeing) {
fragmentChangeing = true;
if (tagfragment!=null) {
if (mFragmentTransaction == null) {
mFragmentTransaction = getSupportFragmentManager().beginTransaction();
}
//動畫
if (animType==AnimType.ZoomShow) {
mFragmentTransaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
} else if (animType== AnimType.LeftInRightOut) {
mFragmentTransaction.setCustomAnimations(R.anim.push_left_in, R.anim.push_left_out,R.anim.back_left_in,R.anim.back_right_out);
} else if (animType== AnimType.BottomInTopOut) {
mFragmentTransaction.setCustomAnimations(R.anim.push_bottom_in,R.anim.push_top_out,R.anim.push_bottom_in,R.anim.push_top_out);
} else {
//NONE
}
List<Fragment> fragmentlist = getSupportFragmentManager().getFragments();
if (fragmentlist != null)
for (int i = 0; i < fragmentlist.size(); i++) {
Fragment fragment = fragmentlist.get(i);
if (fragment != null) {
mFragmentTransaction.hide(fragment);
}
}
fragmentIndex++;
FragmentTagVo tagVo = new FragmentTagVo(fragmentIndex,animType==null?AnimType.NONE.toString():animType.toString());
try {
mFragmentTransaction.add(containerId, tagfragment, JSONObject.toJSONString(tagVo));
} catch (Exception e) {
e.printStackTrace();
}
mFragmentTransaction.show(tagfragment);
mFragmentTransaction.commitAllowingStateLoss();
KeyboradUtil.hideSoftKeyboard(this);
}
fragmentChangeing = false;
}
}
public void pushMsgToSubFragments (boolean needShow,int pushCode,Intent pushData) {
pushMsgToSubFragments(getSupportFragmentManager(), needShow,pushCode, Activity.RESULT_OK, pushData);
}
public void pushMsgToSubFragments (@NonNull FragmentManager fragmentManager,boolean needShow,int requestCode,int resultCode, Intent data) {
List<Fragment> fragmentlist = fragmentManager.getFragments();
if (fragmentlist!=null)
for (Fragment fragment:fragmentlist) {
if (fragment==null) {
continue;
}
if (fragment.isAdded()) {
if (needShow) {
if (!fragment.isHidden()) {
PLog.i("send to:" + fragment);
fragment.onActivityResult(requestCode, resultCode, data);
}
} else {
PLog.i("send to:" + fragment);
fragment.onActivityResult(requestCode, resultCode, data);
}
pushMsgToSubFragments(fragment.getChildFragmentManager(),needShow,requestCode,resultCode,data);
}
}
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
PLog.i("onActivityResult0:" + requestCode);
try {
super.onActivityResult(requestCode, resultCode, data);
} catch (Exception e) {
e.printStackTrace();
}
pushMsgToSubFragments(getSupportFragmentManager(), false, requestCode, resultCode, data);
}
final List<Fragment> removeFragment = new ArrayList<>();
public boolean removeFragment(Class clazz) {
if (clazz == null) {
return false;
}
synchronized (removeFragment) {
List<Fragment> fragmentlist = getSupportFragmentManager().getFragments();
if (fragmentlist != null) {
for (Fragment fragment : fragmentlist) {
if (fragment == null) {
continue;
}
if (clazz.getName().equals(fragment.getClass().getName())) {
PLog.i("remove:" + clazz.getName());
removeFragment.add(fragment);
}
}
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
for (Fragment fragment : removeFragment) {
ft.remove(fragment);
}
ft.commitAllowingStateLoss();
removeFragment.clear();
}
// }
}
return true;
}
public void setCanBackPress(boolean can) {
this.mCanBackPress = can;
}
protected boolean mCanBackPress = true;
protected OnBackPressedListener onBackPressedListener;
public void setOnBackPressedListener(OnBackPressedListener listener) {
this.onBackPressedListener = listener;
}
@Override
public void onBackPressed() {
if (onBackPressedListener != null) {
onBackPressedListener.OnBackKeyDown();
return;
}
if (!mCanBackPress) {
return;
}
backPressed();
}
//[博客出处](http://georgeyang.cn)
public void backPressed () {
boolean waitAnimEndUnLock = false;
if (!fragmentChangeing) {
fragmentChangeing = true;
try {
FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.executePendingTransactions();//同步结束
List<Fragment> fragmentlist = fragmentManager.getFragments();
if (fragmentlist==null) {
finish();
}
PLog.i("list:" + fragmentlist);
for (int i = fragmentlist.size()-1; i >= 0 ; i--) {
Fragment fragment = fragmentlist.get(i);
if (!(fragment == null || !fragment.isVisible())) {//可视且不是没有设置view的fragment
//这里可以写应用自己的返回逻辑
//
Fragment backFragment = null;
PLog.d("tag:" + fragment.getTag());
FragmentTagVo tagVo = JSONObject.parseObject(fragment.getTag(),FragmentTagVo.class);
int fragIndex = tagVo.index-1;
Looper:
while (fragIndex >= 0) {
FindByTag:
for (AnimType animType:AnimType.values()) {
tagVo = new FragmentTagVo(fragIndex,animType.toString());
backFragment = fragmentManager.findFragmentByTag(JSONObject.toJSONString(tagVo));
if (backFragment!=null) {
break FindByTag;
}
}
PLog.d("backFragment:" + backFragment);
if (backFragment != null) {
PLog.d("backFragment add?:" + backFragment.isAdded());
PLog.d("backFragment removing?:" + backFragment.isRemoving());
}
if (backFragment == null || !backFragment.isAdded() || backFragment.isRemoving()) {
--fragIndex;
} else {
break Looper;
}
}
PLog.d("currFragment:" + fragment.getClass().getSimpleName());
PLog.d("backFragment:" + backFragment);
if (backFragment != null) {
tagVo = JSONObject.parseObject(fragment.getTag(),FragmentTagVo.class);
AnimType exitAnim = null;
if(tagVo!=null)
for (AnimType animType:AnimType.values()) {
if (animType.toString().equals(tagVo.animType.toString())) {
exitAnim = animType;
}
}
final Fragment animShowFragment = backFragment;
final Fragment animHideFragment = fragment;
if (exitAnim==null || exitAnim==AnimType.NONE) {
FragmentTransaction mFragmentTransaction = getSupportFragmentManager().beginTransaction();
mFragmentTransaction.show(animShowFragment);
mFragmentTransaction.remove(animHideFragment);
mFragmentTransaction.commitAllowingStateLoss();
} else if (exitAnim==AnimType.ZoomShow) {
FragmentTransaction mFragmentTransaction = getSupportFragmentManager().beginTransaction();
mFragmentTransaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_CLOSE);
mFragmentTransaction.show(animShowFragment);
mFragmentTransaction.remove(animHideFragment);
mFragmentTransaction.commitAllowingStateLoss();
} else {
int[] animRes = AnimType.getAnimRes(exitAnim);
Animation animation = AnimationUtils.loadAnimation(getApplicationContext(), animRes[3]);
animation.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
}
@Override
public void onAnimationEnd(Animation animation) {
FragmentTransaction mFragmentTransaction = getSupportFragmentManager().beginTransaction();
mFragmentTransaction.show(animShowFragment);
mFragmentTransaction.remove(animHideFragment);
mFragmentTransaction.commitAllowingStateLoss();
fragmentChangeing = false;
}
@Override
public void onAnimationRepeat(Animation animation) {
}
});
fragment.getView().startAnimation(animation);
backFragment.getView().setAnimation(AnimationUtils.loadAnimation(getApplicationContext(), animRes[2]));
}
} else {
finish();
}
}//end if (!(fragment == null || !fragment.isVisible())) {//可视的
}
} catch (Exception e) {
e.printStackTrace();
}
KeyboradUtil.hideSoftKeyboard(this);
if (!waitAnimEndUnLock) {
PLog.i("unlock:338");
fragmentChangeing = false;
}
}
}
}