1. 程式人生 > >ViewPager+Fragment 懶加載

ViewPager+Fragment 懶加載

activit svi class span you ace -1 ring rep

轉載於:

作者:尹star
鏈接:http://www.jianshu.com/p/c5d29a0c3f4c
來源:簡書 ViewPager+Fragment的模式再常見不過了,以國民應用微信為例,假設微信也是ViewPager+Fragment的實現方式,那表現形式上就是一個ViewPager管理了四個Fragment,左右滑動來回切換。但是ViewPager有一個奇葩的特性叫:預加載,比如打開微信,首先看到的是第一個Tab(微信),但事實上第二個Tab(通訊錄)已經加載好了。當選擇第二個Tab(通訊錄),第三個Tab(發現)已經加載好了,以此類推。
但上訴ViewPager+Fragment的這種組合並不完美,因為我希望用戶選擇了哪個Tab再去加載哪個Tab的數據,而不要去做預加載,假如當前頁面和預加載頁面都有大量的網絡請求,可能就會比較慢,有很多請求在排隊。關於這個問題,也有很偏激的做法,比如棄用ViewPager,自己手動管理Fragment,或者直接禁掉ViewPager預加載。有一種比較合適的方案是保持ViewPager預加載的特性,但是只初始化View,選擇當前Tab的時候再進行網絡請求。關於這一方案的實現,也是眾說紛紜,千奇百怪。
直接上代碼。
public
abstract class BasePageFragment extends Fragment { protected boolean isViewInitiated; protected boolean isVisibleToUser; protected boolean isDataInitiated; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); } @Override
public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); isViewInitiated = true; prepareFetchData(); } @Override public void setUserVisibleHint(boolean isVisibleToUser) { super.setUserVisibleHint(isVisibleToUser);
this.isVisibleToUser = isVisibleToUser; prepareFetchData(); } public abstract void fetchData(); public boolean prepareFetchData() { return prepareFetchData(false); } public boolean prepareFetchData(boolean forceUpdate) { if (isVisibleToUser && isViewInitiated && (!isDataInitiated || forceUpdate)) { fetchData(); isDataInitiated = true; return true; } return false; } }
這是一個父類,看代碼這裏只有一個setUserVisibleHint需要說下,這是一個相當生僻的方法,我們可以用這個方法來判斷當前UI是否可見,所以在prepareFetchData方法裏我們做如下判斷:就是當前UI可見,並且fragment已經初始化完畢,如果網絡數據未加載,那麽請求數據,或者需要強制刷新頁面,那麽也去請求數據,So easy。子Fragment只需要繼承父類,實現抽象方法,在fetchData()裏做網絡請求或者其他耗時操作即可。再在寫個子類吧。
public class PageFragment extends BasePageFragment {

    public static PageFragment newInstance(String title){
        PageFragment fragment = new PageFragment();
        Bundle args = new Bundle();
        args.putString("key_fragment_title", title);
        fragment.setArguments(args);
        return fragment;
    }

    private String title;
    private TextView tv;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        title = getArguments().getString("key_fragment_title");
        Trace.d(title + ":onCreate");
    }

    @Override
    public void onResume() {
        super.onResume();
        Trace.d(title + ":onResume");
    }


    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        Trace.d(title + ":onCreateView");
        tv = new TextView(getActivity());
        return tv;
    }

    @Override
    public void fetchData() {
        tv.setText(title);
        /** * 在這裏請求網絡。 */
    }

}

如果你也有這樣的需求或者煩惱,保證藥到病除。

有同學說實踐過程中遇到了些問題,比如Fragment只刷新一次,這個問題只要手動調用prepareFetchData(),傳true即可強制刷新了。還有同學質疑setUserVisibleHint()和onActivityCreated()的執行先後的問題。關於這個請看下圖。

技術分享

ViewPager+Fragment 懶加載