1、前言
封裝作為面向對象的三大特性之一,在我們平時的coding過程用的那是非常的多的。大多數時候,我們可以根據封裝情況評判代碼的質量水平。
本文主要講解的是fragment的封裝。大體上,在項目的初期,我們都會在基類中把一些常用的東西封裝起來,以供子類方便的調用。這用做的好處是顯而易見的:
- 將一些共用的東西集中放在base基類中
- 方便后期修改維護
- 避免子類代碼冗余
- 消除不必要的重復代碼
- 方便子類的使用
2、開始封裝
2.1 獲取mActivity
在fragment中,我們可以通過getActivity()方法獲取到當前依附的activity實例。但是如果在使用的時候直接獲取有時候可能會報空指針,那么我們可以在fragment生命周期的onAttach(Context context)方法中獲取到並提升為全局變量。
/** * 貼附的activity */ protected FragmentActivity mActivity; @Override public void onAttach(Context context) { super.onAttach(context); mActivity = getActivity(); }
2.2 onCreateView方法的封裝
通常,我們需要在fragment的onCreateView方法中做一些初始化的事情,比如加載布局文件,findview,網絡加載數據,初始化數據等,將這些事情都寫在一個方法中顯得onCreateView非常的龐大,我們可以分成幾個方法抽離出來,這樣代碼既美觀又方便閱讀:
@Override @Nullable public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { mRootView = inflater.inflate(setLayoutResouceId(), container, false); initData(getArguments()); initView(); mIsPrepare = true; onLazyLoad(); setListener(); return mRootView; }
以上代碼我們根據功能進行以下封裝,注意方法調用順序不可調換:
- setLayoutResouceId():設置布局資源id
- initData(getArguments()) :數據初始化,主要包括拆包從activity傳遞過來的參數,適配器初始化,集合初始化等,不可進行view的操作
- mIsPrepare置為true:mIsPrepare 表示是否已經加載view,該屬性主要用於懶加載(下文會詳細介紹懶加載)
- onLazyLoad():懶加載數據,在oncreatview方法中調用可以直接理解為加載數據,方法中可以進行view的操作
- setListener():各種監聽事件的統一設置
2.3 field介紹
封裝的屬性代碼注釋已經寫的很清楚了:
/** * 貼附的activity */ protected FragmentActivity mActivity; /** * 根view */ protected View mRootView; /** * 是否對用戶可見 */ protected boolean mIsVisible; /** * 是否加載完成 * 當執行完oncreatview,View的初始化方法后方法后即為true */ protected boolean mIsPrepare;
2.4 封裝的方法
以下封裝的三個方法用於子類的實現:
/** * 初始化數據 * @author 漆可 * @date 2016-5-26 下午3:57:48 * @param arguments 接收到的從其他地方傳遞過來的參數 */ protected void initData(Bundle arguments) { } /** * 初始化View * @author 漆可 * @date 2016-5-26 下午3:58:49 */ protected void initView() { } /** * 設置監聽事件 * @author 漆可 * @date 2016-5-26 下午3:59:36 */ protected void setListener() { }
2.5 setLayoutResouceId方法
setLayoutResouceId()是一個抽象方法,子類必須實現,用於獲取布局文件的資源id,加載到fragment中,並在onCreatview方法中用mRootView保存其引用
/** * 設置根布局資源id * @author 漆可 * @date 2016-5-26 下午3:57:09 * @return */ protected abstract int setLayoutResouceId();
2.6 打造專屬的findViewById()方法
是不是很羡慕activity的findViewById()方法,在我們封裝的basefragment中,也有自己的findViewById()方法,而且比activity的更加強大,因為它可以直接轉化成我們相對應的view,而不需要強制轉化。有了它,我們的fragment子類就可以直接使用了。
@SuppressWarnings("unchecked") protected <T extends View> T findViewById(int id) { if (mRootView == null) { return null; } return (T) mRootView.findViewById(id); }
2.7 懶加載
何為懶加載,就是view沒有與用戶交互的話並不會加載,但是他的加載順序又非常快。該方法主要在viewpager嵌套fragment中使用得多。我們都知道,viewpager可以提前加載左右指定數目(當然這個數目可以通過setOffscreenPageLimit(int limit)設置)的fragment,如果我們使用懶加載,就只會做些view的創建等操作,避免提前執行其他頁面的網絡請求。
一下代碼中,setUserVisibleHint(boolean isVisibleToUser)表示是否與用戶可交互,他在onCreatview方法前執行,當isVisibleToUser為true時表示對用戶可見,在這里我們執行自定義的onVisibleToUser()
方法,在onVisibleToUser()中,我們進行判斷,當mIsPrepare為true且與用戶可交互時執行我們的onLazyLoad()方法進行懶加載。
@Override public void setUserVisibleHint(boolean isVisibleToUser) { super.setUserVisibleHint(isVisibleToUser); this.mIsVisible = isVisibleToUser; if (isVisibleToUser) { onVisibleToUser(); } } /** * 用戶可見時執行的操作 * @author 漆可 * @date 2016-5-26 下午4:09:39 */ protected void onVisibleToUser() { if (mIsPrepare && mIsVisible) { onLazyLoad(); } }
3 結束
好了,整個basefragment的封裝就做好了,下面是完整代碼,由於代碼量不多,本篇博客就不上傳完整demo了。
public abstract class BaseFragment extends Fragment { /** * 貼附的activity */ protected FragmentActivity mActivity; /** * 根view */ protected View mRootView; /** * 是否對用戶可見 */ protected boolean mIsVisible; /** * 是否加載完成 * 當執行完oncreatview,View的初始化方法后方法后即為true */ protected boolean mIsPrepare; @Override public void onAttach(Context context) { super.onAttach(context); mActivity = getActivity(); } @Override @Nullable public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { mRootView = inflater.inflate(setLayoutResouceId(), container, false); initData(getArguments()); initView(); mIsPrepare = true; onLazyLoad(); setListener(); return mRootView; } /** * 初始化數據 * @author 漆可 * @date 2016-5-26 下午3:57:48 * @param arguments 接收到的從其他地方傳遞過來的參數 */ protected void initData(Bundle arguments) { } /** * 初始化View * @author 漆可 * @date 2016-5-26 下午3:58:49 */ protected void initView() { } /** * 設置監聽事件 * @author 漆可 * @date 2016-5-26 下午3:59:36 */ protected void setListener() { } @Override public void setUserVisibleHint(boolean isVisibleToUser) { super.setUserVisibleHint(isVisibleToUser); this.mIsVisible = isVisibleToUser; if (isVisibleToUser) { onVisibleToUser(); } } /** * 用戶可見時執行的操作 * @author 漆可 * @date 2016-5-26 下午4:09:39 */ protected void onVisibleToUser() { if (mIsPrepare && mIsVisible) { onLazyLoad(); } } /** * 懶加載,僅當用戶可見切view初始化結束后才會執行 * @author 漆可 * @date 2016-5-26 下午4:10:20 */ protected void onLazyLoad() { } @SuppressWarnings("unchecked") protected <T extends View> T findViewById(int id) { if (mRootView == null) { return null; } return (T) mRootView.findViewById(id); } /** * 設置根布局資源id * @author 漆可 * @date 2016-5-26 下午3:57:09 * @return */ protected abstract int setLayoutResouceId(); }