《一个Android工程的从零开始》阶段总结与修改7-BaseFragmentActivity

先扯两句

之前那么些天没有写博客,这总算赶上一个假期,打算把阶段性修改的部分都总结一下发出来,这应该是最后一篇了,其中当然也有不完整的地方,那就是之前写的博客会再写一下BaseFragment封装的部分,BaseFragment系列与BaseActivity系列基本功能都是一致的,整体差别不大,所以这里也就不多做说明了,大家可以直接取我的github查源码,有什么需要也可以在博客中留言沟通,这里就不多加赘述了。
好了,闲言少叙,老规矩还是先上我的Git,然后开始正文吧。 MyBaseApplication (https://github.com/BanShouWeng/MyBaseApplication)

正文

首先,关于BaseFragmentActivity从BaseActivity中拆解出来是早就已经定好的部分,这部分主要封装的都是一些Activity调用Fragment的方法,当然,这部分没有包含ViewPager的使用,只是单纯的添加Fragment而已,关于ViewPager的部分后续会做考虑,有需要的大家只能先自行封装一下了,比较浅显的运用,我之前编写的一个小demo中有所涉猎,大家也可以去看一下,或许能有所帮助。
下面真的开始进入正文了。

添加

private FragmentTransaction transaction;

/**
 * 添加Fragment
 *
 * @param containerViewId 对应布局的id
 * @param fragments       所要添加的Fragment,可以添加多个
 */
public void addFragment(int containerViewId, Fragment... fragments) {
    if (null == transaction) {
        transaction = getSupportFragmentManager().beginTransaction();
    }
    if (fragments != null) {
        for (int i = 0; i < fragments.length; i++) {
            transaction.add(containerViewId, fragments[i]);
            if (i != fragments.length - 1) {
                transaction.hide(fragments[i]);
            }
        }
        transaction.commit();
    } else {
        Logger.e(getName(), "没有Fragment");
    }
}

这个部分主要针对的是APP主页的添加,一次批量添加所有的Fragment,参数比较简单,其一是Fragment所要替换的占位布局的id,其二是所要加载的Fragment,其余的就是判空之类的处理,并不复杂。

展示与隐藏

/**
 * 显示Fragment
 *
 * @param fragment 所要显示的Fragment
 */
public void showFragment(Fragment fragment) {
    if (null == transaction) {
        transaction = getSupportFragmentManager().beginTransaction();
    }
    if (fragment != null) {
        transaction.show(fragment).commit();
    } else {
        Logger.e(getName(), "ragment不存在");
    }
}

/**
 * 隐藏Fragment
 *
 * @param fragments 所要隐藏的Fragment,可以添加多个
 */
public void hideFragment(Fragment... fragments) {
    if (null == transaction) {
        transaction = getSupportFragmentManager().beginTransaction();
    }
    if (fragments != null) {
        for (Fragment fragment : fragments) {
            transaction.hide(fragment);
        }
        transaction.commit();
    } else {
        Logger.e(getName(), "没有Fragment");
    }
}

添加后,我们需要将展示其中的某一个Fragment,而其他的则需要隐藏起来,其实当我们调用了某一个的显示后,对应Fragment自定会被置于组上层,呈现在用户眼前。不过开发中,我们或许会需要判断当前Fragment是否处于显示状态,或者隐藏状态,所以最好还是调用一下这两个方法,方便操作以及手机适配。
显隐状态监听方法:

@Override
public void onHiddenChanged(boolean hidden) {
    super.onHiddenChanged(hidden);
    if(hidden){
        //TODO now visible to user
    } else {
        //TODO now invisible to user
    }
}

移除

/**
 * 移除Fragment
 *
 * @param fragments 所要移除的Fragment,可以添加多个
 */
public void removeFragment(Fragment... fragments) {
    if (null == transaction) {
        transaction = getSupportFragmentManager().beginTransaction();
    }
    if (fragments != null) {
        for (Fragment fragment : fragments) {
            transaction.hide(fragment);
        }
        transaction.commit();
    } else {
        Logger.e(getName(), "没有Fragment");
    }
}

有添加自然会有删除,不过这个方法从开发到现在,记忆中是没有使用过,不过存在即合理,还是一并封装了,总比需要用的时候没有要强很多啊。

替换

/**
 * 替换Fragment
 *
 * @param containerViewId 对应布局的id
 * @param fragment        用于替代原有Fragment的心Fragment
 */
public void replaceFragment(int containerViewId, Fragment fragment) {
    if (null == transaction) {
        transaction = getSupportFragmentManager().beginTransaction();
    }
    if (fragment != null) {
        transaction.replace(containerViewId, fragment).commit();
    } else {
        Logger.e(getName(), "ragment不存在");
    }
}

上面说的方法主要都是批量处理的,也就是在同一个占位控件处,添加了多层Fragment,用代码控制其隐藏或者显示的状态来操作,好处是可以更流畅的切换Fragment而不需要每次切换都重新加载,以及数据获取。但是得到便利的同时,付出的代价就是资源的耗费。浅显点理解就是同一时间只显示一个Fragment,其余Fragment的持有都是资源的浪费。同样,还有一个问题就是当APP长时间后台运行时,较多的Fragment很容易被GC回收,再次打开APP时导致APP的崩溃。

而使用replace则不会有上述被回收的问题,以及资源的浪费。可同样,它付出的代价就是APP Fragment切换时的流畅体验,之前看过一篇APP测试报告,要求首页不同页面间随机快速切换20次、无卡顿、无崩溃。这个时候如果使用replace,那绝对会是一个悲剧。

至于具体如何选择,还是那句话,看业务需求吧,这已经不是能随便看心情的事了。

划重点

不要吐槽这个标题,我也不想啊,实在是池子的脱口秀看多了。
其实上述这些真的没有什么可写的,只是代码的堆积,最多就是根据我浅显的工作经验区分一下应用场景以及差异,所以险些一激动直接不写这篇博客了,毕竟有源码大家也都能看出个所以然来。
不过懒汉最该做的事就是老老实实的闲着,哪怕发呆也好啊。我这种闲不住的懒汉就悲催了,非要去看什么《阿里巴巴Android开发手册》,结果就发现了之前封装中的问题(前面发的是已经修改过的),这下好了,还得写一篇博客,没办法好好偷懒了!先看看阿里巴巴的大牛是怎么说的。

Activity 可 能 因 为 各 种 原 因 被 销 毁 , Android 支 持 页 面 被 销 毁 前 通 过
Activity#onSaveInstanceState() 保 存 自 己 的 状 态 。 但 如 果
FragmentTransaction.commit()发生在 Activity 状态保存之后,就会导致 Activity 重
建、恢复状态时无法还原页面状态,从而可能出错。为了避免给用户造成不好的体
验,系统会抛出 IllegalStateExceptionStateLoss 异常。推荐的做法是在 Activity 的
onPostResume() 或 onResumeFragments() ( 对 FragmentActivity ) 里 执 行
FragmentTransaction.commit(),如有必要也可在 onCreate()里执行。不要随意改用
FragmentTransaction.commitAllowingStateLoss()或者直接使用 try-catch 避免
crash,这不是问题的根本解决之道,当且仅当你确认 Activity 重建、恢复状态时,
本次 commit 丢失不会造成影响时才可这么做。

翻译一下,就是当使用commit的时候,可能会因为Fragment被回收,而导致“Caused by: java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
”异常,而网上查到的大多数讲解都是将commit替换成commitAllowingStateLoss方法,可实际上这是治标不治本的玩法,并没有从根本上解决问题,所以还不如让APP崩溃,重新运行的好。

当发现以我现在的实力实在说不明白这两者之间的区别怎么办呢?当然是求助大神了Android commit和commitAllowingStateLoss区别及应用场景(别问我为什么这次没有给作者链接,这就是人间的gitPage的链接,如果不是不会玩,我都想搭一个了),这篇博客中有比较详细的说明,所谓公说公有理婆说婆有理,而这篇博客中的说法还算是比较中肯的了,具体使用哪种方式,各位自行决断吧。

附录

《一个Android工程的从零开始》- 目录

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,463评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,868评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,213评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,666评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,759评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,725评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,716评论 3 415
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,484评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,928评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,233评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,393评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,073评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,718评论 3 324
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,308评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,538评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,338评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,260评论 2 352

推荐阅读更多精彩内容