Android fragment 重疊問題的解決方法
阿新 • • 發佈:2019-02-04
由於這個專案的首頁是類似微信的那種 tab 有四個介面 聯絡人,訊息,動態,設定四個介面,因為有頻繁的切換,所以就沒有使用replace 和 remve方法。而是通過hide,show方式,這樣雖然不會重複建立Fragment了,節省了view重繪的效能問題。
但是這樣就容易導致一個問題:就是程式長時間後臺導致fragment重疊。
問題描述:
app執行的時候,按下home鍵,然後清理記憶體。
或者,按下home之後,開啟其他的一些佔記憶體的app,然後把本app的記憶體擠掉了。
解決方案: (這個問題google了很多帖子,發現寫的很亂,沒幾個好用的,後來我就一個個的試驗,從兩個帖子中找到有用的方法。綜合如下:)
1:給每個Fragment加一個Tag;
2.在onCreate(Bundle savedInstanceState)中判斷Bundle savedInstanceState是否不為空;
3.不為空則進行find Tag,重新給幾個frament賦值。
1.
switch (index) {
case 0:
// 當點選了訊息tab時,改變控制元件的圖片和文字顏色
messageImage.setImageResource(R.drawable.message_selected);
messageText.setTextColor(Color.WHITE);
if (messageFragment == null) {
// 如果MessageFragment為空,則建立一個並新增到介面上
messageFragment = new MessageFragment();
transaction.add(R.id.content, messageFragment, FRAGMENT_TAG[index]);
} else {
// 如果MessageFragment不為空,則直接將它顯示出來
transaction.show(messageFragment);
}
break;
2. 3.
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_main);
// 初始化佈局元素
initViews();
fragmentManager = getFragmentManager();
if (savedInstanceState != null) {
//讀取上一次介面Save的時候tab選中的狀態
selindex=savedInstanceState.getInt(PRV_SELINDEX,selindex);
messageFragment = (MessageFragment) fragmentManager.findFragmentByTag(FRAGMENT_TAG[0]);
contactsFragment = (ContactsFragment) fragmentManager.findFragmentByTag(FRAGMENT_TAG[1]);
newsFragment = (NewsFragment) fragmentManager.findFragmentByTag(FRAGMENT_TAG[2]);
settingFragment = (SettingFragment) fragmentManager.findFragmentByTag(FRAGMENT_TAG[3]);
}
// 選中index
setTabSelection(selindex);
}
//那麼文中有幾處藍色高亮的程式碼 請看如下
/**
* Fragment的TAG 用於解決app記憶體被回收之後導致的fragment重疊問題
*/
private static final String[] FRAGMENT_TAG = {"msgfrag","contacfrag","actfrag","settfrag"};
PS:
補充一點:PRV_SELINDEX,selindex 是用於恢復上一次介面Save的時候tab選中的狀態
@Override
protected void onSaveInstanceState(Bundle outState) {
//儲存tab選中的狀態
outState.putInt(PRV_SELINDEX,selindex);
super.onSaveInstanceState(outState);
}
/**
* 上一次介面 onSaveInstanceState 之前的tab被選中的狀態 key 和 value
*/
private static final String PRV_SELINDEX="PREV_SELINDEX";
private int selindex=0;
OK,當你配置好了tag之後,再addfrag的時候使用了tag,Act執行saveInstancestates 的時候就會自動按tag給你儲存frag的狀態了。
那麼,你如果覺得這種方式不是很好,你這tag也可以不要在add的時候使用,你可以在Act onSAveInstancestate的時候,用FragmentMange手動儲存,
然後在act,oncreate的時候bundle不為空 就用之前記錄的幾個tag手動開啟。
這是這個act裡面的Frag的問題。
2.那麼frag中巢狀frag的時候,也是需要儲存與恢復的呢?
frag中的frag是子frag,外層的frag是主frag。先這麼叫吧,這樣好區分。
一樣的道理 ,程式碼都很像,你把主frag當成act,只是getSurpportFragmentManager的時候 ,不用這個方法,有個getChildFragmentManger,大概是這麼寫的吧,我記不清是getChildFfragmentMnager還是getSurpportChildFragmentmanager了,反正你找下就行了。
這裡就不貼程式碼了,畢竟很act中潛逃frag程式碼都很像,邏輯都是一樣的。
3.有點要注意的是viewpager中潛逃frag,這樣的話 記得把Viewpager的快取數設定為 frag 數目減一。viewpager有個方法是setoffscreenpagelimit方法,可以設定快取數目,這個方法看viewpager的原始碼,意思是快取下來未顯示的子控制元件,所以viewpager肯定是有一個是顯示的,其他的要快取,那麼快取數是 子控制元件的數目減一。 而且從viewpager的原始碼上看,這個方法裡,最小的數字是1。
快取數 預設也是1,你不改的話 他會 有一些問題,就是你這邊的frag因為沒有被快取 會被自動釋放,然後重新新建,有些邏輯執行的就比較多了 。
viewpager內巢狀frag之後,每次pagerAdapger 執行notifychange的時候會有個問題就是特麼的,原來的舊的fragment會先釋放,執行ondettach ondestory方法 ,然後重新建立,要注意。
無恥的奉上我的公眾號二維碼,沒事聽我給你扯扯段子。