91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Android如何實現仿微信Viewpager-Fragment惰性加載

發布時間:2021-06-28 09:47:45 來源:億速云 閱讀:90 作者:小新 欄目:移動開發

這篇文章將為大家詳細講解有關Android如何實現仿微信Viewpager-Fragment惰性加載,小編覺得挺實用的,因此分享給大家做個參考,希望大家閱讀完這篇文章后可以有所收獲。

效果如圖:

Android如何實現仿微信Viewpager-Fragment惰性加載

什么是lazy-loading呢?顧名思義就是在必要的時候才加載,否則不進行View的繪制和數據的加載。原因是Viewpager一次只會顯示一個頁卡,那么剛開始的時候,只需加載第一張Fragment頁卡,其他的不加載,當用戶向右滑動切換再進行加載。因為其他Fragment對于用戶來說是不可見的,如果一開始就把全部Fragment一起加載,可能造成啟動時卡頓的問題,更重要的是可能白白耗費用戶的流量,因為用戶可能并不需要其他Fragment的信息。

今天Google了有關Fragment惰性加載的資料,并沒有找到介紹得清楚詳細的博文+demo。所以我找到了Github上的一個開源項目demo里有關惰性加載的代碼,學習了這個知識點,并把它整理出來分享給大家。

你應該知道

你應該知道viewPager.setOffscreenPageLimit();方法。該方法設置ViewPager允許有多少張pages存在于屏幕外(不包括正在顯示的page),默認值是1。在范圍之外的pages 的View會被銷毀,即onDestroyView()會被執行。

Viewpager里面FragmentPagerAdapter、FragmentStatePagerAdapter的區別:

1.FragmentPagerAdapter會將每一個生成的Fragment都放到內存中,即無論怎么滑動切換ViewPager,都不會有一個Fragment的onDestroy方法被調用。但Fragment不在viewPager.setOffscreenPageLimit(3);保護的范圍內會調用FragmentManager的detach()方法,相應的Fragment的onDestroyView會執行,但Fragment實例仍在!所以該類適用于需要展示的Fragment比較少的情況。

2.FragmentStateAdapter 有點類似于LIstview的RecyclerBin機制,當Fragment不在viewPager.setOffscreenPageLimit(3);保護的范圍內,Fragment的就會被銷毀,onDestroy()、onDetach()方法會被執行。適用于要展示Fragment數量比較多,Fragment的子View和數據量復雜的情況。
熟知Fragment的生命周期。

Android如何實現仿微信Viewpager-Fragment惰性加載

Fragment的生命周期

3.剛被new出來的Fragment并沒有開始它的生命周期,當它被添加到FragmentManager時生命周期才開始。

4.我們通常是在onCreateView()中對Fragment完成視圖的構建。若是要實現延遲加載,可以在調用onCreateView時獲得一個空container的引用。當等待用戶切換到屏幕的時候,開始加載數據和視圖。

那么如何得知我們的Fragment何時被切換到屏幕呢?核心方法就是getUserVisibleHint()和在Fragment中重寫setUserVisibleHint(boolean isVisibleToUser){…}方法。

在官方文檔是這樣描述該方法的:

public void setUserVisibleHint (boolean isVisibleToUser)
Added in API level 15
Set a hint to the system about whether this fragment's UI is currently visible to the user. This hint defaults to true and is persistent across fragment instance state save and restore.
An app may set this to false to indicate that the fragment's UI is scrolled out of visibility or is otherwise not directly visible to the user. This may be used by the system to prioritize operations such as fragment lifecycle updates or loader ordering behavior.
Parameters
isVisibleToUser true if this fragment's UI is currently visible to the user (default), false if it is not.

該方法的作用是設置一個提示或者標志,該標志代表的是Fragment在當前是否處于對用戶的可見狀態。注意這里的可見并不能與Activity或Fragment的onStart或者onResume混淆。因為Fragment處于onResume狀態并不代表它對用戶是可見的!仍覺得很困惑?那我們一起來Log一下吧。

我們把生命周期回調方法加了Log語句。

  @Override
  public void setUserVisibleHint(boolean isVisibleToUser) {
    super.setUserVisibleHint(isVisibleToUser);
    Log.d("TAG", "setUserVisibleHint() called with: " + "isVisibleToUser = [" + isVisibleToUser + "]");
  }

我們允許有4張頁卡的緩存,因為微信是有4個tab的。這樣ViewPager來回切換就不會有頁卡被銷毀了。

viewPager.setOffscreenPageLimit(3);

啟動ViewPager后的Log:

D/TAG: setUserVisibleHint() called with: isVisibleToUser = [false]
D/TAG: setUserVisibleHint() called with: isVisibleToUser = [false]
D/TAG: setUserVisibleHint() called with: isVisibleToUser = [false]
D/TAG: setUserVisibleHint() called with: isVisibleToUser = [false]
D/TAG: setUserVisibleHint() called with: isVisibleToUser = [true]
D/TAG: onCreateView() : getUserVisibleHint():true
D/TAG: onStart() : getUserVisibleHint():true
D/TAG: onResume() : getUserVisibleHint():true
D/TAG: onCreateView() : getUserVisibleHint():false
D/TAG: onCreateView() : getUserVisibleHint():false
D/TAG: onCreateView() : getUserVisibleHint():false
D/TAG: onStart() : getUserVisibleHint():false
D/TAG: onResume() : getUserVisibleHint():false
D/TAG: onStart() : getUserVisibleHint():false
D/TAG: onResume() : getUserVisibleHint():false
D/TAG: onStart() : getUserVisibleHint():false
D/TAG: onResume() : getUserVisibleHint():false

從Log中,可得知,setUserVisibleHint()比onCreateView()先調用,并且只有一個方法的isVisbleToUser==true。由此我們可以斷定,正在展示的fragment對應的isVisibleToUser才為true。我們現在有4個page,onCreateView()、onStart()、onResume()分別共調用了4次,由此可知,盡管Fragment沒有被展示,ViewPager也會將它們構建起來,會回調onStart、onResume。那么ViewPager初始化時構建Fragment的個數與什么有關呢?這個主要跟使用的Adapter類型和setOffscreenPageLimit()有關。

接下來向右滑,切換到第二頁,Log如下:

D/TAG: setUserVisibleHint() called with: isVisibleToUser = [false]
D/TAG: setUserVisibleHint() called with: isVisibleToUser = [true]

這次只會調用兩次setUserVisibleHint(),將要剛剛顯示的Fragment的isVisibleToUser 設置為false,并把將要顯示的Fragment的isVisibleToUser 設置為true。

當我退出程序,Log如下:

D/TAG: onPause() : getUserVisibleHint():true
D/TAG: onPause() : getUserVisibleHint():false
D/TAG: onPause() : getUserVisibleHint():false
D/TAG: onPause() : getUserVisibleHint():false
D/TAG: onStop() called: getUserVisibleHint():true
D/TAG: onStop() called: getUserVisibleHint():false
D/TAG: onStop() called: getUserVisibleHint():false
D/TAG: onStop() called: getUserVisibleHint():false
D/TAG: onDestroyView() : getUserVisibleHint():true
D/TAG: onDestroy() :
D/TAG: onDetach() :
D/TAG: onDestroyView() : getUserVisibleHint():false
D/TAG: onDestroy() :
D/TAG: onDetach() :
D/TAG: onDestroyView() : getUserVisibleHint():false
D/TAG: onDestroy() :
D/TAG: onDetach() :
D/TAG: onDestroyView() : getUserVisibleHint():false
D/TAG: onDestroy() :
D/TAG: onDetach() :

從這“死亡日志”中,我們發現,getUserVisibleHint()貫穿著Fragment的凋亡生命線。
到此,對這個關鍵的方法,我們算是有了一個宏觀的認識。

具體實現

那么具體應該怎么實現呢?我們可以在自定義一個抽象類LazyFragment,重寫onCreateView()方法,只返回一個簡單的,甚至是空的(不是null)的ViewGroup作為Container,比如return new FrameLayout();當然這個ViewGroup我們需要保存為成員變量。接下來重寫setUserVisibleHint(boolean isVisibleToUser)方法,如果該Fragment處于用戶可見狀態,就會調用該方法,并傳過來的isVisibleToUser==true。所以根據這個hint做一個判斷,若等于true,立即加載原本要正常顯示的視圖和數據。當然這個方法可以作為一個抽象方法交給子類去實現。具體的實現就是這樣!Talk is simple,show you the code!

LazyFragment:

省去了一些,回調方法,只給出了核心的幾個方法,完整的可以看文章末尾的項目源碼。注釋已經寫得相對完善,如果有不明白的地方歡迎評論留言。

public class LazyFragment extends BaseFragment {
 private boolean isInit = false;//真正要顯示的View是否已經被初始化(正常加載)
 private Bundle savedInstanceState;
 public static final String INTENT_BOOLEAN_LAZYLOAD = "intent_boolean_lazyLoad";
 private boolean isLazyLoad = true;
 private FrameLayout layout;
 private boolean isStart = false;//是否處于可見狀態,in the screen

 @Deprecated
 protected final void onCreateView(Bundle savedInstanceState) {
  Log.d("TAG", "onCreateView() : " + "getUserVisibleHint():" + getUserVisibleHint());
  super.onCreateView(savedInstanceState);
  Bundle bundle = getArguments();
  if (bundle != null) {
   isLazyLoad = bundle.getBoolean(INTENT_BOOLEAN_LAZYLOAD, isLazyLoad);
  }
  //判斷是否懶加載
  if (isLazyLoad) {
   //處于完全可見、沒被初始化的狀態,調用onCreateViewLazy顯示內容
   if (getUserVisibleHint() && !isInit) {
    this.savedInstanceState = savedInstanceState;
    onCreateViewLazy(savedInstanceState);
    isInit = true;
   } else {
    //進行懶加載
    layout = new FrameLayout(getApplicationContext());
    layout.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
    View view = LayoutInflater.from(getApplicationContext()).inflate(R.layout.fragment_lazy_loading, null);
    layout.addView(view);
    super.setContentView(layout);
   }
  } else {
   //不需要懶加載,開門江山,調用onCreateViewLazy正常加載顯示內容即可
   onCreateViewLazy(savedInstanceState);
   isInit = true;
  }
 }

 @Override
 public void setUserVisibleHint(boolean isVisibleToUser) {
  super.setUserVisibleHint(isVisibleToUser);
  Log.d("TAG", "setUserVisibleHint() called with: " + "isVisibleToUser = [" + isVisibleToUser + "]");
  //一旦isVisibleToUser==true即可對真正需要的顯示內容進行加載

  //可見,但還沒被初始化
  if (isVisibleToUser && !isInit && getContentView() != null) {
   onCreateViewLazy(savedInstanceState);
   isInit = true;
   onResumeLazy();
  }
  //已經被初始化(正常加載)過了
  if (isInit && getContentView() != null) {
   if (isVisibleToUser) {
    isStart = true;
    onFragmentStartLazy();
   } else {
    isStart = false;
    onFragmentStopLazy();
   }
  }
 }

 @Override
 public void setContentView(int layoutResID) {
  //判斷若isLazyLoad==true,移除所有lazy view,加載真正要顯示的view
  if (isLazyLoad && getContentView() != null && getContentView().getParent() != null) {
   layout.removeAllViews();
   View view = inflater.inflate(layoutResID, layout, false);
   layout.addView(view);
  }
  //否則,開門見山,直接加載
  else {
   super.setContentView(layoutResID);
  }
 }

 @Override
 public void setContentView(View view) {
  //判斷若isLazyLoad==true,移除所有lazy view,加載真正要顯示的view
  if (isLazyLoad && getContentView() != null && getContentView().getParent() != null) {
   layout.removeAllViews();
   layout.addView(view);
  }
  //否則,開門見山,直接加載
  else {
   super.setContentView(view);
  }
 }
}

具體的實現類:

public class MoreFragment extends LazyFragment {
 private TextView tvLoading;
 private ImageView ivContent;
 private int tabIndex;
 public static final String INTENT_INT_INDEX="index";

 public static MoreFragment newInstance(int tabIndex) {

  Bundle args = new Bundle();
  args.putInt(INTENT_INT_INDEX, tabIndex);
  MoreFragment fragment = new MoreFragment();
  fragment.setArguments(args);
  return fragment;
 }
 @Override
 protected void onCreateViewLazy(Bundle savedInstanceState) {
  super.onCreateViewLazy(savedInstanceState);
  setContentView(R.layout.fragment_tabmain_item);
  tabIndex = getArguments().getInt(INTENT_INT_INDEX);
  ivContent = (ImageView) findViewById(R.id.iv_content);
  tvLoading = (TextView) findViewById(R.id.tv_loading);
  getData();
 }

 private void getData() {
  new Thread(new Runnable() {
   @Override
   public void run() {
    //異步處理加載數據
    //...
    //完成后,通知主線程更新UI
    handler.sendEmptyMessageDelayed(1, 2000);
   }
  }).start();
 }

 @Override
 public void onDestroyViewLazy() {
  super.onDestroyViewLazy();
  handler.removeMessages(1);
 }

 private Handler handler = new Handler() {
  public void handleMessage(android.os.Message msg) {
   tvLoading.setVisibility(View.GONE);
   int id=0;
   switch (tabIndex){
    case 1:
     id=R.drawable.a;
     break;
    case 2:
     id=R.drawable.b;
     break;
    case 3:
     id=R.drawable.c;
     break;
    case 4:
     id=R.drawable.d;
     break;
   }
   ivContent.setImageResource(id);
   ivContent.setVisibility(View.VISIBLE);
  }
 };
}

為了簡化布局,demo中只用了微信上的幾張截圖,希望大家能專注重點。具體效果如圖:

Android如何實現仿微信Viewpager-Fragment惰性加載

關于“Android如何實現仿微信Viewpager-Fragment惰性加載”這篇文章就分享到這里了,希望以上內容可以對大家有一定的幫助,使各位可以學到更多知識,如果覺得文章不錯,請把它分享出去讓更多的人看到。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

襄垣县| 财经| 道真| 壶关县| 绥滨县| 白山市| 巩义市| 呼伦贝尔市| 塘沽区| 黄山市| 宁晋县| 大渡口区| 长沙县| 布尔津县| 双峰县| 焉耆| 云林县| 崇左市| 绥棱县| 科技| 图们市| 库车县| 凌海市| 泗水县| 太湖县| 九台市| 新余市| 大庆市| 福清市| 金坛市| 高阳县| 贵德县| 定安县| 遂宁市| 修水县| 宿迁市| 通江县| 宁波市| 子洲县| 海城市| 盐津县|