您的位置:首页 > 其它

从BaseActivity与BaseFragment的封装谈起

2016-10-21 15:08 197 查看
这篇博客主要是从BaseActivity与BaseFragment的封装开始,总结自己在实战开发中关于Fragment的注意事项以及心得体会。先看以下效果图:



这里模拟的是用户登录模块,你可能会说,很普通的效果嘛,这有啥。嘿嘿,那我要告诉你的是,这么多模块仅仅由两个Activity构成的。等你从头到尾看完这篇博客,你就会惊叹其中的奥秘了。废话不多说,开始。

多模块Activity+多Fragment

开发APP非常适合的架构,相对于多Activity,这种架构APP占用内存降低,性能提升;相对于单Activity+多Fragment,这种开发起来逻辑相对简单,不容易出错。

对于多模块Activity+多Fragment,这里有两个概念需要我们了解一下

同级式Fragment:比如QQ的主界面,消息,联系人,动态,这三个Fragment就属于同级关系,我们平时项目中主界面的Fragment也是属于同级Fragment

流程式Fragment:比如我这个示例Demo,可以理解为用户账户流程,可以包括:登录/注册模块—-忘记/找回密码模块—-用户协议模块,这些Fragent就是属于流程式Fragment

我的示例Demo使用的是流程式Fragment,结合今天的主题—-BaseActivity与BaseFragment的封装,我们一探究竟。

1.BaseActivity的封装:

?
(1)两个必须实现的抽象方法,获取布局文件Layout的resource ID,获取布局文件中Fragment的ID

(2)添加fragment:开启一个事物,替换了当前layout容器中的由getFragmentContentId()标识的fragment。通过调用 addToBackStack(String tag), replace事务被保存到back stack, 因此用户可以回退事务,并通过按下BACK按键带回前一个fragment,如果没有调用 addToBackStack(String tag), 那么当事务提交后, 那个fragment会被销毁,并且用户不能导航回到它。其中参数tag将作为本次加入BackStack的Transaction的标志。commitAllowingStateLoss(),这种提交是允许发生异常时状态值丢失的情况下也能正常提交事物。

(3)移除fragment:与addToBackStack()相对应的接口方法是popBackStack(),调用该方法后会将事务操作插入到FragmentManager的操作队列,轮询到该事务时开始执行。这里进行了一下判断,获取回退栈中所有事务数量,大于1的时候,执行回退操作,等于1的时候,代表当前Activity只剩下一个Fragment,直接finish()当前Activity即可

(4)监听返回键的返回事件,当事务数量等于1的时候,直接finish()

2.BaseActivity的进一步封装—-AppActivity:

?
(1)一个必须实现的抽象方法来获取当前Activity应该显示的第一个Fragment

(2)获取intent的方法,在需要传递或者接受数据的中Activity实现

(3)在Activity的onCreate()方法中拿到intent,并且添加第一个fragment作为Activity的主界面进行显示

最后贴一下activity_base.xml布局文件代码

?
3.BaseFragment的封装:

?
安卓有一种特殊情况,就是在APP运行在后台的时候,系统资源紧张的时候会把APP的资源全部回收(杀死APP的进程),这时候把APP再从后台返回到前台的时候,APP会重启。

这种内存不足的情况会导致许多问题,其中之一就是Fragment调用getActivity()的地方却返回null,报了空指针异常。解决办法就是在Fragment基类里设置一个Activity mActivity的全局变量,在onAttach(Activity activity)里赋值,使用mActivity代替getActivity()。其他的代码注释很详细,大家一看便懂。

4.Activity与Fragment的使用:

BaseActivity与BaseFragment的封装都已经完成,接下来就是具体在项目中的使用了,这里分两种情况。

第一种情况:不接收数据的Activity

?
示例Demo中的主界面MainActivity,没有接收其他界面传递过来的数据。可以看到代码相当的精简,对应的MainFragment代码如下:

?
很简单的业务逻辑,点击第一个按钮,携带数据,跳转到LoginActivity;点击第二个按钮,跳转到注册模块,这里故意添加了一个参数,这里后面会说到。

第二种情况:接收数据的Activity

?
可以看到,LoginActivity与MainActivity不一样的是,重写了handleIntent()这个方法来获取传递过来的数据,更加重要的一点,创建Fragment的时候传递了一个参数这是为什么呢,先来看看fragment的代码你就知道了

?
代码不少,我们先挑重点讲:

?
给Fragment添加newInstance方法,将需要的参数传入,设置到bundle中,然后setArguments(bundle),最后在onCreate中进行获取。

这种使用arguments来创建Fragment的方法,强烈推荐使用:

(1)这样就完成了Fragment和Activity间的解耦,使用Fragment的一个很大的原因,就是为了复用。这一点在我主界面点击第二个按钮跳转到注册界面有所体现

(2)对Fragment传递数据,建议使用setArguments(Bundle args),而后在onCreate中使用getArguments()取出,在 内存不足导致异常时,系统会帮你保存数据,不会造成数据的丢失。和Activity的Intent原理一致。

(3)使用newInstance(参数) 创建Fragment对象,优点是调用者只需要关系传递的哪些数据,而无需关心传递数据的Key是什么。

然后就是业务逻辑:

(1)点击注册按钮,跳转到注册模块,注意这里我传递了一个和主界面不一样的参数,为了区分,并且都在注册模块进行了显示。你会发现,示例Demo中,点击登录模块的注册按钮与点击首界面的注册按钮跳转到注册模块时候,显示的文字不一样。这里纯属演示,实际项目中,我们可以根据传递的不同参数,对Fragment进行不一样的操作,显示不一样的数据。达到最大程度的Fragment复用!

(2)点击返回按钮,一句话就帮你搞定,轻松返回上一个界面:

?
当然,点击手机返回键效果也是一样的

(3)点击用户协议按钮,跳转到用户协议模块。

至于其他的界面大同小异,你可以加上忘记密码/修改密码等模块,完全没问题。关于流程式Fragment,就先到这里,看看同级式Fragment应该注意的问题。

5.hide()与show()导致的Fragment重叠:

同级式Fragment在内存不足导致的异常情况下,会出现重叠现象,处理方法是在基类Activity的onCreate函数,先去判断savedInstanceState是否为null,如果不为null,则表示里面有保存这个fragment。则不再重新去add这个fragment,而是通过Tag从前保存的数据中直接去读取,看一下代码:

在add的时候,加上一个tab参数

?
?
到这里,BaseActivity与BaseFragment的封装已经结束了,这只是最最最基础的封装,大家可以把一些常用的方法封装到基类当中,让基类Activity与Fragment发挥最大程度的作用。

当然,业务逻辑简单的界面,一个Activity就可以搞定的那种,那就没必要使用这种方法了。这里把自己封装过程中关于Fragment的一些心得记录下来。关于Fragment的深度解析与其他注意事项,大家可以参考刚才给出的资料。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: