GeorgeYang'Blog

my technology blog

让android应用实现只有一个activity的fragmentOnlySupportActivity

阅读:725 创建时间:16-04-02 00:34:50 tags:android,fragment

自从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);
     }

最后献上完整代码:

github地址

 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;
             }
         }
     }



 }

github地址