欧美一区二区三区老妇人-欧美做爰猛烈大尺度电-99久久夜色精品国产亚洲a-亚洲福利视频一区二区

Android在多種設(shè)計(jì)下實(shí)現(xiàn)懶加載機(jī)制的方法

前言

發(fā)展壯大離不開(kāi)廣大客戶(hù)長(zhǎng)期以來(lái)的信賴(lài)與支持,我們將始終秉承“誠(chéng)信為本、服務(wù)至上”的服務(wù)理念,堅(jiān)持“二合一”的優(yōu)良服務(wù)模式,真誠(chéng)服務(wù)每家企業(yè),認(rèn)真做好每個(gè)細(xì)節(jié),不斷完善自我,成就企業(yè),實(shí)現(xiàn)共贏。行業(yè)涉及木制涼亭等,在網(wǎng)站建設(shè)公司、成都營(yíng)銷(xiāo)網(wǎng)站建設(shè)、WAP手機(jī)網(wǎng)站、VI設(shè)計(jì)、軟件開(kāi)發(fā)等項(xiàng)目上具有豐富的設(shè)計(jì)經(jīng)驗(yàn)。

前段時(shí)間在自己的練習(xí)項(xiàng)目中想用到懶加載機(jī)制,查看了大多數(shù)資料只介紹了在 View Pager + Fragment 組合的情況下實(shí)現(xiàn)的懶加載,但是現(xiàn)在大多數(shù)App更多的是 Fragmentmanager 去管理主頁(yè)面多個(gè) Fragment 的顯示與隱藏,然后主界面的某個(gè)或多個(gè) Fragment 里又嵌套了多個(gè) Fragment + ViewPager (詳細(xì)見(jiàn)下圖),對(duì)于這種情況,適用于第一種的方式是不能直接解決第二種的情況的,所以寫(xiě)下這篇文章,記錄一下踩的幾個(gè)坑,希望對(duì)同像我一樣的初學(xué)者提供一種思考方式作為參考(如果有錯(cuò)誤或者不合適的地方,希望各位前輩能在評(píng)論區(qū)指出,非常感謝!)。

關(guān)于懶加載

1. 什么是懶加載?

懶加載也叫延遲加載,在APP中指的是每次只加載當(dāng)前頁(yè)面,是一種很好的優(yōu)化APP性能的一種方式。

2.為什么要用懶加載?

優(yōu)化APP性能,提升用戶(hù)體驗(yàn):如果用戶(hù)打開(kāi)某頁(yè)面,就會(huì)去預(yù)加載其它的頁(yè)面時(shí),數(shù)據(jù)集較小或者網(wǎng)絡(luò)性能較優(yōu)時(shí)還好,但是如果數(shù)據(jù)集過(guò)大或者網(wǎng)絡(luò)性能不佳時(shí),就會(huì)造成用戶(hù)等待的時(shí)間較長(zhǎng),APP界面產(chǎn)生明顯的滯頓感的情況,嚴(yán)重影響到用戶(hù)的體驗(yàn)。

減少無(wú)效資源的加載,減少服務(wù)器的壓力,節(jié)省用戶(hù)流量:如果用戶(hù)只想瀏覽或者經(jīng)常瀏覽某個(gè)特定的頁(yè)面,如果使用預(yù)加載的方式,就會(huì)造成資源浪費(fèi),增加服務(wù)器的壓力等。

 實(shí)現(xiàn)懶加載

 1.ViewPager+Fragment情況

Android在多種設(shè)計(jì)下實(shí)現(xiàn)懶加載機(jī)制的方法 

1.1遇到的問(wèn)題

在我們平時(shí)開(kāi)發(fā)中,經(jīng)常使用 ViewPager+Fragment 的組合來(lái)實(shí)現(xiàn)左右滑動(dòng)的頁(yè)面設(shè)計(jì)(如上圖),但是 ViewPger 有個(gè) 預(yù)加載機(jī)制,默認(rèn)會(huì)把 ViewPager 當(dāng)前位置的左右相鄰頁(yè)面預(yù)先初始化(俗稱(chēng)預(yù)加載),即使設(shè)置 setOffscreenPageLimit(0) 也無(wú)效果,也會(huì)預(yù)加載。通過(guò)點(diǎn)進(jìn)源碼中發(fā)現(xiàn),如果不主動(dòng)設(shè)置 setOffscreenPageLimit() 方法, mOffscreenPageLimit 默認(rèn)值為1,即使設(shè)置了0(小于1)的值了,但是還會(huì)按照 mOffscreenPageLimit=limit=1 處理。

private int mOffscreenPageLimit = 1;//即使不設(shè)置,默認(rèn)值就為1

public int getOffscreenPageLimit() {
    return this.mOffscreenPageLimit;
  }
  
public void setOffscreenPageLimit(int limit) {
    if (limit < 1) {//設(shè)置為0,還是會(huì)默認(rèn)為1
      Log.w("ViewPager", "Requested offscreen page limit " + limit + " too small; defaulting to " + 1);
      limit = 1;
    }
    if (limit != this.mOffscreenPageLimit) {
      this.mOffscreenPageLimit = limit;
      this.populate();
    }

1.2 解決思路

Fragment 有一個(gè)非生命周期的 setUserVisibleHint(boolean isVisibleToUser) 回調(diào)方法, 當(dāng) ViewPager 嵌套 Fragment 時(shí)會(huì)起作用,如果切換 ViewPager 則該方法也會(huì)被調(diào)用,參數(shù) isVisibleToUsertrue 代表當(dāng)前 Fragment 對(duì)用戶(hù)可見(jiàn),否則不可見(jiàn)。 所以最簡(jiǎn)單的思路: Fragment 可見(jiàn)時(shí)才去加載數(shù)據(jù),不可見(jiàn)時(shí)就不讓它加載數(shù)據(jù) 。據(jù)我們創(chuàng)建抽象 BaseFragment ,對(duì)其進(jìn)行封裝。首先我們引入 isVisibleToUser 變量,負(fù)責(zé)保存當(dāng)前 Fragment 對(duì)用戶(hù)的可見(jiàn)狀態(tài)。 同時(shí)還有幾個(gè)值得注意的地方:

setUserVisibleHint(boolean isVisibleToUser) 方法的回調(diào)時(shí)機(jī)并沒(méi)有與 Fragment 的生命周期有確切的關(guān)聯(lián),比如說(shuō),回調(diào)時(shí)機(jī)有可能在 onCreateView() 方法之后,也可能在 onCreateView() 方法之前。因此,必須引入一個(gè)標(biāo)志位 isPrepareView 判斷view是否創(chuàng)建完成,不然,很容易會(huì)造成空指針異常。我們初始化該變量為 false ,在 onViewCreated() 中,也就是view創(chuàng)建完成后,將其賦值為 true 。

數(shù)據(jù)初始化只應(yīng)該加載一次,因此,引入第二個(gè)標(biāo)志位, isInitData ,初始為 false, 在數(shù)據(jù)加載完成之后,將其賦值為 true ,下次返回此頁(yè)面時(shí)不會(huì)再自動(dòng)加載。至此,我們的懶加載方法考慮了所有條件。也就是當(dāng) isVisibleToUsertrue , isInitDatafalse , isPrepareViewtrue 時(shí),進(jìn)行數(shù)據(jù)加載,并且加載后為了防止重復(fù)調(diào)用,將 isInitData 賦值為 true 。

將懶加載數(shù)據(jù)提取成一個(gè)方法,那么這個(gè)方法該何時(shí)調(diào)用呢?首先 setUserVisibleHint(boolean isVisibleToUser) 方法中是必須調(diào)用的,即當(dāng) Fragment 由可見(jiàn)變?yōu)椴豢梢?jiàn)和不可見(jiàn)變?yōu)榭梢?jiàn)時(shí)回調(diào)。 其次,很容易忽略的一點(diǎn)。對(duì)于第一個(gè) Fragment ,如果 setUserVisibleHint(boolean isVisibleToUser ) 方法在 onCreateView() 之前調(diào)用的話(huà),如果懶加載方法只在 setUserVisibleHint(boolean isVisibleToUser ) 中調(diào)用,那么該 Fragment 將只能在被主動(dòng)切換一次之后才能加載數(shù)據(jù),這肯定是不可能的,因此,我們需要在view創(chuàng)建完成之后,也進(jìn)行一次調(diào)用。思來(lái)想去,在 onActivityCreated() 方法中是最合適的。我們?cè)诶^承的時(shí)候,在 onViewCreated() 方法中進(jìn)行一些初始化就行了,這樣不會(huì)引起沖突。

1.3 BaseFragment代碼實(shí)現(xiàn)

public abstract class BaseFragment extends Fragment {

  private Boolean isInitData = false; //標(biāo)志位,判斷數(shù)據(jù)是否初始化
  private Boolean isVisibleToUser = false; //標(biāo)志位,判斷fragment是否可見(jiàn)
  private Boolean isPrepareView = false; //標(biāo)志位,判斷view已經(jīng)加載完成 避免空指針操作

  @Nullable
  @Override
  public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
    return inflater.inflate(getLayoutId(),container,false);
  }

  @Override
  public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);
    isPrepareView=true;//此時(shí)view已經(jīng)加載完成,設(shè)置其為true
  }
  /**
   * 懶加載方法
   */
  public void lazyInitData(){
    if(!isInitData && isVisibleToUser && isPrepareView){//如果數(shù)據(jù)還沒(méi)有被加載過(guò),并且fragment已經(jīng)可見(jiàn),view已經(jīng)加載完成
      initData();//加載數(shù)據(jù)
      isInitData=true;//是否已經(jīng)加載數(shù)據(jù)標(biāo)志重新賦值為true
    }
  }

  @Override
  public void setUserVisibleHint(boolean isVisibleToUser) {
    super.setUserVisibleHint(isVisibleToUser);
    this.isVisibleToUser=isVisibleToUser;//將fragment是否可見(jiàn)值賦給標(biāo)志isVisibleToUser
    lazyInitData();//懶加載
  }

  /**
   * fragment生命周期中onViewCreated之后的方法 在這里調(diào)用一次懶加載 避免第一次可見(jiàn)不加載數(shù)據(jù)
   * @param savedInstanceState
   */
  @Override
  public void onActivityCreated(@Nullable Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);
    lazyInitData();//懶加載
  }

  /**
   * 由子類(lèi)實(shí)現(xiàn)
   * @return 返回子類(lèi)的布局id
   */
  abstract int getLayoutId();

  /**
   * 加載數(shù)據(jù)的方法,由子類(lèi)實(shí)現(xiàn)
   */
  abstract void initData();
}

2.Fragment+ViewPager+Fragment情況

Android在多種設(shè)計(jì)下實(shí)現(xiàn)懶加載機(jī)制的方法 

2.1 遇到的問(wèn)題

如圖2,對(duì)于這種由 Fragmentmanager 管理主頁(yè)面的多個(gè) Fragment 的顯示與隱藏,在其中的某個(gè) Fragment 中又嵌套了多個(gè) Fragment 的情況( 如上圖),上面的方案是無(wú)法解決的,如果主頁(yè)面的 Fragment 直接繼承上面的 BaseFragment ,就會(huì)出現(xiàn)主頁(yè)的幾個(gè) Fragment 都不會(huì)加載的現(xiàn)象,為什么會(huì)這樣呢,按道理說(shuō) Fragment 應(yīng)該可見(jiàn)了,加載數(shù)據(jù)的判斷邏輯應(yīng)該沒(méi)問(wèn)題啊,而且上面那個(gè)demo也跑成功了。最終我發(fā)現(xiàn),問(wèn)題出在 setUserVisibleHint() 這個(gè)方法上,點(diǎn)進(jìn)去它的源碼發(fā)現(xiàn)注釋中有這么一句話(huà):

This may be used by the system to prioritize operations such as fragment lifecycle updates or loader ordering behavior.

也就是說(shuō)這個(gè)可能被用來(lái)在一組有序的 Fragment 里 ,例如 Fragment 生命周期的更新。告訴我們這個(gè)方法被調(diào)用希望在一個(gè)pager里 ,因此 FragmentPagerAdapter 所以可以使用這個(gè),而主頁(yè)面的幾個(gè) Fragment 我們是通過(guò) Fragmentmanager 管理的,所以 setUserVisibleHint() 是不會(huì)被調(diào)用,而我們?cè)O(shè)置的 isVisibleToUser=false 默認(rèn)值一直不會(huì)變,那么 lazyInitData() 方法也就一直不會(huì)執(zhí)行。

 /**
   * 懶加載方法
   */
  public void lazyInitData(){
    if(!isInitData && isVisibleToUser && isPrepareView){//因?yàn)閕sVisibleToUser一直都是false,所以iniData()是不會(huì)被執(zhí)行的
      initData();//加載數(shù)據(jù)
      isInitData=true;
    }
  }

2.2 解決思路

這里我的處理方式是,在lazyInitData()中多加了一段處理邏輯,如下:

/**
   * 懶加載方法
   */
  public void lazyInitData(){
    if(!isInitData && isVisibleToUser && isPrepareView){//如果數(shù)據(jù)還沒(méi)有被加載過(guò),并且fragment已經(jīng)可見(jiàn),view已經(jīng)加載完成
      initData();//加載數(shù)據(jù)
      isInitData=true;//是否已經(jīng)加載數(shù)據(jù)標(biāo)志重新賦值為true
    }else if (!isInitData && getParentFragment()==null && isPrepareView){
      initData();
      isInitData=true;
    }
  }
  
  /**
   * Fragment顯示隱藏監(jiān)聽(tīng)
   * @param hidden
   */
  @Override
  public void onHiddenChanged(boolean hidden) {
    super.onHiddenChanged(hidden);
    if (!hidden) {
    lazyInitData(); 
    }
  }

對(duì)于主頁(yè)面的多個(gè) Fragment 只會(huì)在第二個(gè)判斷邏輯處理(因?yàn)樗?isVisibleToUser 值一直等于 false ),對(duì)于嵌套的 Fragment 只會(huì)經(jīng)過(guò)第一個(gè)處理邏輯(因?yàn)樗?getParentFragment()!=null ),然后通過(guò) onHiddenChanged() 方法去加載 lazyInitData() 方法,這樣以來(lái)就能處理這種情況了。

但是這時(shí)候又會(huì)出現(xiàn)一個(gè)問(wèn)題,如果一個(gè)APP里第一種,第二種情況并存的話(huà),這段代碼又不適合第一種情況了,因?yàn)閷?duì)于第一種的情況當(dāng)判定 isVisibleToUserfalse 時(shí),雖然不走第一個(gè)處理邏輯,但是它的 getParentFragment() 一直是等于 null 的,那么它就會(huì)走第二個(gè)判斷邏輯,這樣又會(huì)預(yù)加載了。

對(duì)于這種情況,我的處理方式:給每個(gè)Fragment設(shè)置一個(gè)標(biāo)志值,當(dāng)是第一種情況時(shí),設(shè)為true,第二種情況時(shí),設(shè)置false,然后再分別處理相應(yīng)的判斷邏輯。代碼如下:

 /**
   * 懶加載方法
   */
  public void lazyInitData(){
    if(setFragmentTarget()){
      if(!isInitData && isVisibleToUser && isPrepareView){//如果數(shù)據(jù)還沒(méi)有被加載過(guò),并且fragment已經(jīng)可見(jiàn),view已經(jīng)加載完成
        initData();//加載數(shù)據(jù)
        isInitData=true;//是否已經(jīng)加載數(shù)據(jù)標(biāo)志重新賦值為true
      }
    }else {
      if(!isInitData && isVisibleToUser && isPrepareView){//如果數(shù)據(jù)還沒(méi)有被加載過(guò),并且fragment已經(jīng)可見(jiàn),view已經(jīng)加載完成
        initData();//加載數(shù)據(jù)
        isInitData=true;//是否已經(jīng)加載數(shù)據(jù)標(biāo)志重新賦值為true
      }else if (!isInitData && getParentFragment()==null && isPrepareView ){
        initData();
        isInitData=true;
      }
    }
  }
  
   /**
   * 設(shè)置Fragment target,由子類(lèi)實(shí)現(xiàn)
   */
  abstract boolean setFragmentTarget();

經(jīng)過(guò)這樣的處理之后,第一種情況和第二種情況,或兩者并存的情況下都能保證在繼承一個(gè)base下,實(shí)現(xiàn)懶加載。

2.3 BaseFragmentTwo最終代碼實(shí)現(xiàn)

public abstract class BaseFragmentTwo extends Fragment {
  private Boolean isInitData = false; //標(biāo)志位,判斷數(shù)據(jù)是否初始化
  private Boolean isVisibleToUser = false; //標(biāo)志位,判斷fragment是否可見(jiàn)
  private Boolean isPrepareView = false; //標(biāo)志位,判斷view已經(jīng)加載完成 避免空指針操作

  @Nullable
  @Override
  public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
    return inflater.inflate(getLayoutId(),container,false);
  }

  @Override
  public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);
    isPrepareView=true;//此時(shí)view已經(jīng)加載完成,設(shè)置其為true
  }
  /**
   * 懶加載方法
   */
  public void lazyInitData(){
    if(setFragmentTarget()){
      if(!isInitData && isVisibleToUser && isPrepareView){//如果數(shù)據(jù)還沒(méi)有被加載過(guò),并且fragment已經(jīng)可見(jiàn),view已經(jīng)加載完成
        initData();//加載數(shù)據(jù)
        isInitData=true;//是否已經(jīng)加載數(shù)據(jù)標(biāo)志重新賦值為true
      }
    }else {
      if(!isInitData && isVisibleToUser && isPrepareView){//如果數(shù)據(jù)還沒(méi)有被加載過(guò),并且fragment已經(jīng)可見(jiàn),view已經(jīng)加載完成
        initData();//加載數(shù)據(jù)
        isInitData=true;//是否已經(jīng)加載數(shù)據(jù)標(biāo)志重新賦值為true
      }else if (!isInitData && getParentFragment()==null && isPrepareView ){
        initData();
        isInitData=true;
      }
    }
  }



  @Override
  public void onHiddenChanged(boolean hidden) {
    super.onHiddenChanged(hidden);
    if (!hidden) { lazyInitData(); }
  }

  @Override
  public void setUserVisibleHint(boolean isVisibleToUser) {
    super.setUserVisibleHint(isVisibleToUser);
    this.isVisibleToUser=isVisibleToUser;//將fragment是否可見(jiàn)值賦給標(biāo)志isVisibleToUser
    lazyInitData();//加載懶加載
  }

  /**
   * fragment生命周期中onViewCreated之后的方法 在這里調(diào)用一次懶加載 避免第一次可見(jiàn)不加載數(shù)據(jù)
   * @param savedInstanceState
   */
  @Override
  public void onActivityCreated(@Nullable Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);
    lazyInitData();
  }

  /**
   * 由子類(lèi)實(shí)現(xiàn)
   * @return 返回子類(lèi)的布局id
   */
  abstract int getLayoutId();

  /**
   * 加載數(shù)據(jù)的方法,由子類(lèi)實(shí)現(xiàn)
   */
  abstract void initData();

  /**
   * 設(shè)置Fragment target,由子類(lèi)實(shí)現(xiàn)
   */
  abstract boolean setFragmentTarget();

}

其它需要注意:

①給 viewpager 設(shè)置 adapter 時(shí),一定要傳入 getChildFragmentManager() ,否則 getParentFragment() 將會(huì)一直等于 null ,這會(huì)影響 lazyInitData() 的判斷,導(dǎo)致懶加載出現(xiàn)混亂甚至無(wú)效的情況。

②demo中我使用的是 ViewPager+Tablayout 的組合方式,在使用 Tablayout 時(shí)一定要保證 styles.xml 中的主題應(yīng)該使用 Theme.AppCompat.Light.NoActionBar 或者 Theme.AppCompat.LightTheme.AppCompat.XXX 的主題。

項(xiàng)目地址

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持創(chuàng)新互聯(lián)。

分享名稱(chēng):Android在多種設(shè)計(jì)下實(shí)現(xiàn)懶加載機(jī)制的方法
鏈接分享:http://chinadenli.net/article6/gicgig.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供App開(kāi)發(fā)、云服務(wù)器、做網(wǎng)站、小程序開(kāi)發(fā)、軟件開(kāi)發(fā)、定制網(wǎng)站

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶(hù)投稿、用戶(hù)轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話(huà):028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)

手機(jī)網(wǎng)站建設(shè)