日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 运维知识 > Android >内容正文

Android

Android Fragment 生命周期及其正确使用(建议使用自定义View替换Fragment)

發(fā)布時間:2024/1/17 Android 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Android Fragment 生命周期及其正确使用(建议使用自定义View替换Fragment) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

使用Fragment 官方例子中顯示:

例如:一個學(xué)生Fragment,需要傳入studentId,進(jìn)行http請求顯示,那么setArguments后防止殺掉Fragment后,參數(shù)為0,顯示不了數(shù)據(jù)。

1 public static StudentFragment newInstance(int studentId){ 2 StudentFragment fragment = new StudentFragment(); 3 Bundle bundle = new Bundle(); 4 bundle.putInt("student_id", studentId); 5 fragment.setArguments(bundle); 6 return fragment; 7 }

setArguments:

1 private int mStudentId = 0; 2 3 @Override 4 public void setArguments(Bundle args) { 5 super.setArguments(args); 6 7 mStudentId = args.getInt("student_id", 0); 8 }

那么app在殺死后,回到這個Fragment 時,會在onCreateView時,進(jìn)行獲取參數(shù),獲取正確的頁面數(shù)據(jù),不然有可能會因為null,而崩毀。

@Overridepublic View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {mStudentId = getArguments().getInt("student_id", 0);return super.onCreateView(inflater, container, savedInstanceState);}

?

?

我為什么不主張使用Fragment

Fragment:(?Fragment就相當(dāng)于一個有生命周期的View,它的生命周期被所在的Activity的生命周期管理?)

生命周期回調(diào)說明:

onAttach(Activity)
當(dāng)Fragment與Activity發(fā)生關(guān)聯(lián)時調(diào)用。
onCreateView(LayoutInflater, ViewGroup,Bundle)
創(chuàng)建該Fragment的視圖
onActivityCreated(Bundle)
當(dāng)Activity的onCreate方法返回時調(diào)用
onDestoryView()
與onCreateView想對應(yīng),當(dāng)該Fragment的視圖被移除時調(diào)用
onDetach()
與onAttach相對應(yīng),當(dāng)Fragment與Activity關(guān)聯(lián)被取消時調(diào)用

與Activity 依賴關(guān)系:

與ViewPager 的關(guān)系:

(1)setOffscreenPageLimit

1 // 預(yù)加載頁面的數(shù)量 2 viewPager.setOffscreenPageLimit(2);

知道ViewPager會有預(yù)加載的特性,我以為Fragment_1會從 1 onAttach() 開始直到 6 onResume()后,Fragment_2才會開始從 1onAttach()開始,到了3 onCreateView()會停止。然而,并不是預(yù)想的這樣。

首先,Fragment_1 經(jīng)歷 1_onAttach() 和 2_onCreate() 后, Fragment_2也開始走了 1_onAttach()和 2_onCreate()方法。

接著,Fragment_1依次經(jīng)歷 3_onCreateView(), 4_onCreateActivity(),5 _onStart ,6_onResume()。此時,Fragment_1獲得焦點,已經(jīng)展示在手機(jī)屏幕。Fragment_2也接著從 3_onCreate()開始直到也執(zhí)行到 6_onResume()方法。疑問就在這,我個人感覺既然Fragment_2沒有在屏幕顯示,就不會執(zhí)行到 6_onResume()方法,然而Log信息卻顯示執(zhí)行到了 6_onResume()。這里記錄一下。

多了Fragment_3的Log信息,而且走的方法和Frgment_1和2是一樣的。后面的情況的Log信息便不再貼出來了,本質(zhì)是一樣的,只是多預(yù)加載了一個Fragment。但此時ViewPager依然只是保留3個Fragment的信息。當(dāng)滑到Fragment_4的時候,Fragment_1走了7_onPause(),8_onStop(),9_onDestroyView()。Fragment_2,3,4則處于6_onResume()。

這個方法對Fragment生命周期方法的調(diào)用順序上并沒有什么影響,只是預(yù)加載的Fragment的數(shù)量又設(shè)置的limit參數(shù)決定。

(2)setUserVisibleHint

setUserVisibleHint()這個方法會在預(yù)加載Fragment時,會在Fragment的1_onAttach()前調(diào)用。此時,在setUserVisibleHint()里面調(diào)用也不用害怕空指針的問題,因為有3個前條件。當(dāng)通過滑動ViewPger時,根據(jù)6.1知道,每次滑動都會調(diào)用setUserVisibleHint()這個方法,進(jìn)行預(yù)加載后,當(dāng)滑到Fragment_2,3,4時,就會調(diào)用里面的load()方法。

在Fragment的4_onCreateActivity()中調(diào)用load。我個人習(xí)慣把網(wǎng)絡(luò)請求放在這個生命周期。在Fragment_1和點擊Tab時,引起問題的原因就是setUserVisibleHint()先于1_onAttach()調(diào)用,不能滿足前提條件中的isCreate,所以load方法不會被調(diào)用。而4_onCreateActivity()中會再次調(diào)用load()方法,此時還滿足3個前提條件。這樣,遺留的問題也解決了。ViewPager中Fragment延遲加載這個需求也可以實現(xiàn)了。如果此時Fragment中有一個輪播圖的話,也可以通過getUserVisibleHint()這個方法來選擇關(guān)閉輪播圖線程的時機(jī)。

Fragment Api:

Fragment常用的三個類:

android.app.Fragment 主要用于定義Fragment

android.app.FragmentManager 主要用于在Activity中操作Fragment

android.app.FragmentTransaction 保證一些列Fragment操作的原子性

主要的操作都是FragmentTransaction的方法:

1 // v4包中,getSupportFragmentManager 2 FragmentManager fm = getFragmentManager(); 3 // 開啟一個事務(wù) (主要的操作都是FragmentTransaction的方法) 4 FragmentTransaction transaction = fm.benginTransatcion(); 5 6 // 往Activity中添加一個Fragment 7 transaction.add(Fragment fragment); 8 // 從Activity中移除一個Fragment,如果被移除的Fragment沒有添加到回退棧(回退棧后面會詳細(xì)說),這個Fragment實例將會被銷毀。 9 transaction.remove(Fragment fragment); 10 // 使用另一個Fragment替換當(dāng)前的,實際上就是remove()然后add()的合體 11 transaction.replace(R.id.XXX, Fragment fragment); 12 // 隱藏當(dāng)前的Fragment,僅僅是設(shè)為不可見,并不會銷毀 13 transaction.hide(Fragment fragment); 14 // 顯示之前隱藏的Fragment 15 transaction.show(Fragment fragment); 16 //提交一個事務(wù) 17 transatcion.commit();

//?會將view從UI中移除,和remove()不同,此時fragment的狀態(tài)依然由FragmentManager維護(hù)。

detach()

// 重建view視圖,附加到UI上并顯示。

attach();

判斷什么時候該使用什么方法:

(1)希望保留用戶操作的面板,可以使用hide和show。

(2)不希望保留用戶操作,可以使用remove(),然后add();或者直接使用replace(),效果相同。

(3)remove會銷毀整個Fragment實例,而detach則只是銷毀其視圖結(jié)構(gòu),實例并不會被銷毀。

(4)當(dāng)前Activity一直存在,那么在不希望保留用戶操作的時候,可以優(yōu)先使用detach。

參考地址:Android Fragment 真正的完全解析(上)? ? ?Android Fragment 真正的完全解析(下)

對于用法:

?(1)getActivity() 方法空指針問題:

在Fragment基類里設(shè)置一個Activity mActivity的全局變量,在onAttach(Activity activity)里賦值,使用mActivity代替getActivity(),保證Fragment即使在onDetach后,仍持有Activity的引用(有引起內(nèi)存泄露的風(fēng)險,但是異步任務(wù)沒停止的情況下,本身就可能已內(nèi)存泄漏,相比Crash,這種做法“安全”些),即: protected Activity mActivity;/** * API低于 23 的版本中不會去調(diào)用后者,只會去調(diào)用onAttach(Activity) */ @Override public void onAttach(Activity activity) {super.onAttach(activity);this.mActivity = activity; }/** * 如果用了support 23的庫,上面的方法會提示過時,且不會被調(diào)用,可以用下面的方法代替 */ @Override public void onAttach(Context context) {super.onAttach(context);this.mActivity = (Activity) context; }

如不需要使用getActivity():

1 /* 2 * onAttach(Context) is not called on pre API 23 versions of Android and onAttach(Activity) is deprecated 3 * Use onAttachToContext instead 4 */ 5 @TargetApi(23) 6 @Override 7 public void onAttach(Context context) { 8 super.onAttach(context); 9 onAttachToContext(context); 10 } 11 12 /* 13 * Deprecated on API 23 14 * Use onAttachToContext instead 15 */ 16 @SuppressWarnings("deprecation") 17 @Override 18 public void onAttach(Activity activity) { 19 super.onAttach(activity); 20 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { 21 onAttachToContext(activity); 22 } 23 } 24 25 /* 26 * Called when the fragment attaches to the context 27 */ 28 protected void onAttachToContext(Context context) { 29 //do something 30 }

(2)未必靠譜的出棧方法remove()

如果你想讓某一個Fragment出棧,使用remove()在加入回退棧時并不靠譜。

如果你在add的同時將Fragment加入回退棧:addToBackStack(name)的情況下,它并不能真正將Fragment從棧內(nèi)移除,如果你在2秒后(確保Fragment事務(wù)已經(jīng)完成)打印getSupportFragmentManager().getFragments(),會發(fā)現(xiàn)該Fragment依然存在,并且依然可以返回到被remove的Fragment,而且是空白頁面。

如果你沒有將Fragment加入回退棧,remove方法可以正常出棧。

如果你加入了回退棧,popBackStack()系列方法才能真正出棧,這也就引入下一個深坑,popBackStack(String tag,int flags)等系列方法的BUG。

(3)Fragment轉(zhuǎn)場動畫

如果你的Fragment沒有轉(zhuǎn)場動畫,或者使用setCustomAnimations(enter, exit)的話。

1 getFragmentManager().beginTransaction().setCustomAnimations(enter, exit); 3 // 如果通過tag/id同時出棧多個Fragment的情況時, 4 // 請謹(jǐn)慎使用.setCustomAnimations(enter, exit, popEnter, popExit) 5 // 在support-25.4.0之前出棧多Fragment時,伴隨出棧動畫,會在某些情況下發(fā)生異常 6 // 你需要搭配Fragment的onCreateAnimation()臨時取消出棧動畫,或者延遲一個動畫時間再執(zhí)行一次上面提到的Hack方法,排序 注意:如果你想給下一個Fragment設(shè)置進(jìn)棧動畫和出棧動畫,.setCustomAnimations(enter, exit)只能設(shè)置進(jìn)棧動畫,第二個參數(shù)并不是設(shè)置出棧動畫;
請使用.setCustomAnimations(enter, exit, popEnter, popExit),這個方法的第1個參數(shù)對應(yīng)進(jìn)棧動畫,第4個參數(shù)對應(yīng)出棧動畫,所以是.setCustomAnimations(進(jìn)棧動畫, exit, popEnter, 出棧動畫)

如果想讓出棧動畫運作正常的話,需要使用Fragment的onCreateAnimation中控制動畫:

1 @Override 2 public Animation onCreateAnimation(int transit, boolean enter, int nextAnim) { 3 // 此處設(shè)置動畫 4 }

pop多個Fragment時轉(zhuǎn)場動畫 帶來的問題:

在使用 pop(tag/id)出棧多個Fragment的這種情況下,將轉(zhuǎn)場動畫臨時取消或者延遲一個動畫的時間再去執(zhí)行其他事務(wù);

原因在于這種情景下,可能會導(dǎo)致棧內(nèi)順序錯亂(上文有提到),同時如果發(fā)生“內(nèi)存重啟”后,因為Fragment轉(zhuǎn)場動畫沒結(jié)束時再執(zhí)行其他方法,會導(dǎo)致Fragment狀態(tài)不會被FragmentManager正常保存下來。

2、進(jìn)入新的Fragment并立刻關(guān)閉當(dāng)前Fragment 時的一些問題
(1)如果你想從當(dāng)前Fragment進(jìn)入一個新的Fragment,并且同時要關(guān)閉當(dāng)前Fragment。由于數(shù)據(jù)結(jié)構(gòu)是棧,所以正確做法是先pop,再add,但是轉(zhuǎn)場動畫會有覆蓋的不正?,F(xiàn)象,你需要特殊處理,不然會閃屏!

如果你遇到Fragment的mNextAnim空指針的異常(通常是在你的Fragment被重啟的情況下),那么你首先需要檢查是否操作的Fragment是否為null;其次在你的Fragment轉(zhuǎn)場動畫還沒結(jié)束時,你是否就執(zhí)行了其他事務(wù)等方法;解決思路就是延遲一個動畫時間再執(zhí)行事務(wù),或者臨時將該Fragment設(shè)為無動畫

?

對于一些操作,Fragment發(fā)生的生命周期變化:

切換到該Fragment:onAttach() ->?onCreate() ->?onCreateView() ->?onActivityCreated() ->?onStart() ->?onResume()

屏幕滅掉或者回到桌面(Home):?onPause() ->?onSaveInstanceState() ->?onStop()

屏幕解鎖或者重新回到應(yīng)用:?onStart() ->?onResume()

切換到其他Fragment:?onPause() ->?onStop() ->?onDestroyView()

切換回本身的Fragment:?onCreateView() ->?onActivityCreated() ->?onStart() ->?onResume()

退出應(yīng)用:onPause() ->?onStop() ->?onDestroyView() ->?onDestroy() ->?onDetach()

?

參考:

Fragment全解析系列(一):那些年踩過的坑

轉(zhuǎn)載于:https://www.cnblogs.com/CharlesGrant/p/4876135.html

總結(jié)

以上是生活随笔為你收集整理的Android Fragment 生命周期及其正确使用(建议使用自定义View替换Fragment)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。