Activity与Fragment封装初探(持续更新)

本文介绍了如何通过封装Activity和Fragment来提高代码复用性和维护性。通过抽象方法和流程优化,减少重复代码,使得界面初始化过程更为简洁高效。

俗话说,不想成为架构师的程序员不是好程序员。
封装的过程感觉就是一个发现,并且抽离的过程。需要时间和经验的积累,难以强求。心累不已。
在日常的开发中,Activity与Fragment是用到的最多的控件,里面必定会有些重复的代码,如果不加以复用,会让整个Activity和Fragment的代码显的臃肿不堪,总结一下学到的Activity与Fragment的最常用的封装方式。

整个Activity的一般都会有一些固定的流程,我们的目的就是为了抽离这些固定的逻辑,方便在子类中直接复用。
比如初始化控件的方法可以抽象成

 protected void initWidget()

得到当前界面的资源文件Id的方法可以抽离成,

 //方法必须是抽象的,我们要求子类必须继承此方法
 protected abstract int getContentLayoutId();

另外还有初始化数据的方法可以抽离成

  protected void initData()

以上情况是走我们的正常流程时才会触发,我们在进入界面的时候,必须确保我们传入的初始化参数是正确的才可以进行初始化,如果说传入的基本数据都不成功,我们也就没有必要初始化我们的基本数据了,所以需要一个方法

protected boolean initArgs(Bundle bundle)

另外我们知道,我们Window的初始化是不需要等到界面初始化完成之后才初始化的,所以对Window的初始化也需要一个方法

 protected void initWidget()

最终我们的最重要的onCreate方法可能会成为这样

 protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // 在界面未初始化之前调用的初始化窗口
        initWidows();

        if (initArgs(getIntent().getExtras())) {
            // 得到界面Id并设置到Activity界面中
            int layId = getContentLayoutId();
            setContentView(layId);
            initBefore();
            initWidget();
            initData();
        } else {
            finish();
        }
    }

另外可能还需要

 // 当点击界面导航返回时,Finish当前界面
 @Override
    public boolean onSupportNavigateUp() 

现在的开发情况一般都是Activity和Fragment相结合进行开发的,在处理后退的时候,我们不可能一个一个的处理,最好是复写Activity的

@Override
    public void onBackPressed() 

最终得到的我们自己的Activity可能会是这样

/**
 * @author HFRX hfrx1314@qq.com
 * @version 1.0.0
 */
public abstract class Activity extends AppCompatActivity {

    protected PlaceHolderView mPlaceHolderView;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // 在界面未初始化之前调用的初始化窗口
        initWidows();

        if (initArgs(getIntent().getExtras())) {
            // 得到界面Id并设置到Activity界面中
            int layId = getContentLayoutId();
            setContentView(layId);
            initBefore();
            initWidget();
            initData();
        } else {
            finish();
        }
    }

    /**
     * 初始化控件调用之前
     */
    protected void initBefore() {

    }

    /**
     * 初始化窗口
     */
    protected void initWidows() {

    }

    /**
     * 初始化相关参数
     *
     * @param bundle 参数Bundle
     * @return 如果参数正确返回True,错误返回False
     */
    protected boolean initArgs(Bundle bundle) {
        return true;
    }

    /**
     * 得到当前界面的资源文件Id
     *
     * @return 资源文件Id
     */
    protected abstract int getContentLayoutId();

    /**
     * 初始化控件
     */
    protected void initWidget() {
        ButterKnife.bind(this);
    }

    /**
     * 初始化数据
     */
    protected void initData() {

    }


    @Override
    public boolean onSupportNavigateUp() {
        // 当点击界面导航返回时,Finish当前界面
        finish();
        return super.onSupportNavigateUp();
    }

    @Override
    public void onBackPressed() {
        // 得到当前Activity下的所有Fragment
        @SuppressLint("RestrictedApi")
        List<Fragment> fragments = getSupportFragmentManager().getFragments();
        // 判断是否为空
        if (fragments != null && fragments.size() > 0) {
            for (Fragment fragment : fragments) {
                // 判断是否为我们能够处理的Fragment类型
                if (fragment instanceof net.qiujuer.italker.common.app.Fragment) {
                    // 判断是否拦截了返回按钮
                    if (((net.qiujuer.italker.common.app.Fragment) fragment).onBackPressed()) {
                        // 如果有直接Return
                        return;
                    }
                }
            }
        }

        super.onBackPressed();
        finish();
    }

    /**
     * 设置占位布局
     *
     * @param placeHolderView 继承了占位布局规范的View
     */
    public void setPlaceHolderView(PlaceHolderView placeHolderView) {
        this.mPlaceHolderView = placeHolderView;
    }
}

Fragment封装与Activity大同小异,个人感觉最终要的是处理Fragment的复用的问题,因为存在如下的情况,如果Fragment被回收,重新初始化Fragment的时候,有可能我们的mRoot还没被回收,那么他的Parent中就会有数据,所以我们要把它移除掉,另外,在我们监听返回键时,返回True代表我已处理返回逻辑,Activity不用自己finish。返回False代表我没有处理逻辑,Activity自己走自己的逻辑。

/**
 * @author HFRX hfrx1314@qq.com
 * @version 1.0.0
 */
public abstract class Fragment extends android.support.v4.app.Fragment {
    protected View mRoot;
    protected Unbinder mRootUnBinder;
    protected PlaceHolderView mPlaceHolderView;
    // 标示是否第一次初始化数据
    protected boolean mIsFirstInitData = true;

    @Override
    public void onAttach(Context context) {
        super.onAttach(context);

        // 初始化参数
        initArgs(getArguments());

    }

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        if (mRoot == null) {
            int layId = getContentLayoutId();
            // 初始化当前的跟布局,但是不在创建时就添加到container里边
            View root = inflater.inflate(layId, container, false);
            initWidget(root);
            mRoot = root;
        } else {
            if (mRoot.getParent() != null) {
                // 把当前Root从其父控件中移除
                ((ViewGroup) mRoot.getParent()).removeView(mRoot);
            }
        }

        return mRoot;
    }

    @Override
    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        if (mIsFirstInitData) {
            // 触发一次以后就不会触发
            mIsFirstInitData = false;
            // 触发
            onFirstInit();
        }

        // 当View创建完成后初始化数据
        initData();
    }

    /**
     * 初始化相关参数
     */
    protected void initArgs(Bundle bundle) {

    }

    /**
     * 得到当前界面的资源文件Id
     *
     * @return 资源文件Id
     */
    @LayoutRes
    protected abstract int getContentLayoutId();

    /**
     * 初始化控件
     */
    protected void initWidget(View root) {
        mRootUnBinder = ButterKnife.bind(this, root);
    }

    /**
     * 初始化数据
     */
    protected void initData() {

    }

    /**
     * 当首次初始化数据的时候会调用的方法
     */
    protected void onFirstInit() {

    }

    /**
     * 返回按键触发时调用
     *
     * @return 返回True代表我已处理返回逻辑,Activity不用自己finish。
     * 返回False代表我没有处理逻辑,Activity自己走自己的逻辑
     */
    public boolean onBackPressed() {
        return false;
    }


    /**
     * 设置占位布局
     *
     * @param placeHolderView 继承了占位布局规范的View
     */
    public void setPlaceHolderView(PlaceHolderView placeHolderView) {
        this.mPlaceHolderView = placeHolderView;
    }

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值