編輯:關於Android編程
至於fragment的使用就不多說了,直奔主題,
布局文件:
//導航欄
//內容區域
<framelayout android:background="#EEE" android:id="@+id/content" android:layout_height="match_parent" android:layout_width="match_parent">
</framelayout>
布局預覽圖:
<喎?/kf/ware/vc/" target="_blank" class="keylink">vcD4NCjxwPjxiciAvPg0KPGJyIC8+DQo8YnIgLz4NCjxiciAvPg0K0tTHsNC0tuC49mZyYWdtZW50x9C7u8rHvq2zo8q508PV4tbWt723qMfQu7tmcmFnbWVudKO6PGJyIC8+DQombmJzcDs8L3A+DQo8cHJlIGNsYXNzPQ=="brush:java;">
/**
* 使用replace切換頁面
* 顯示fragment
*/
private void showFragment(Fragment fg){
FragmentTransaction transaction = fragmentManager.beginTransaction();
transaction.replace(R.id.content, fg);
transaction.commit();
}
replace():該方法只是在上一個Fragment不再需要時采用的簡便方法,弊端就是如果需要重復使用該fragment時,需要每次都要重新加載一次。比如我在第一個fragment輸入信息後,切換第二個fragment後再切換回去,就會造成數據丟失,如下:
而且,如果每切換一次就實例化一次的話,FragmentManager管理下的棧也會爆滿,最終會導致手機卡頓,這很明顯不是正確的Fragment使用姿勢,這時,我們就需要使用show()、hide()、add()了,正確的切換方式是add(),切換時hide(),add()另一個Fragment;再次切換時,只需hide()當前,show()另一個就行了,代碼修改如下:
/**
* 使用show() hide()切換頁面
* 顯示fragment
*/
private void showFragment(Fragment fg){
FragmentTransaction transaction = fragmentManager.beginTransaction();
//如果之前沒有添加過
if(!fg.isAdded()){
transaction
.hide(currentFragment)
.add(R.id.content,fg);
}else{
transaction
.hide(currentFragment)
.show(fg);
}
//全局變量,記錄當前顯示的fragment
currentFragment = fg;
transaction.commit();
}
效果:
有上圖,可以看出,即使切換到別的fragment,再切換回來,數據還依然存在,這就避免了Fragment切換時布局重新實例化。
安卓app有一種特殊情況,就是 app運行在後台的時候,系統資源緊張的時候導致把app的資源全部回收(殺死app的進程),這時把app再從後台返回到前台時,app會重啟。這種情況下文簡稱為:“內存重啟”。(屏幕旋轉等配置變化也會造成當前Activity重啟,本質與“內存重啟”類似)
在系統要把app回收之前,系統會把Activity的狀態保存下來,Activity的FragmentManager負責把Activity中的Fragment保存起來。在“內存重啟”後,Activity的恢復是從棧頂逐步恢復,Fragment會在宿主Activity的onCreate方法調用後緊接著恢復
當我們不退出軟件,只是後台掛著去干別的事,當系統內存不足回收我們這個app時,再切換回來,app的這幾個Fragment界面會重疊。,如下圖:
由上圖可以看出,三個fragment全部疊在了一起,而且點擊上面菜單也不能消除重疊。顯然,這並不是我們想要的,沒事,繼續解決問題,使用findFragmentByTag:即在add()或者replace()時綁定一個tag,一般我們是用fragment的類名作為tag,然後在發生“內存重啟”時,通過findFragmentByTag找到對應的Fragment,並hide()需要隱藏的fragment。,修改如下:
/**
* 使用show() hide()切換頁面
* 顯示fragment
*/
private void showFragment(Fragment fg){
FragmentTransaction transaction = fragmentManager.beginTransaction();
//如果之前沒有添加過
if(!fg.isAdded()){
transaction
.hide(currentFragment)
.add(R.id.content,fg,fg.getClass().getName()); //第三個參數為當前的fragment綁定一個tag,tag為當前綁定fragment的類名
}else{
transaction
.hide(currentFragment)
.show(fg);
}
currentFragment = fg;
transaction.commit();
}
別急,還沒完,在當前Activity的onCreate()
方法裡面添加一下代碼:
if (savedInstanceState != null) { // “內存重啟”時調用
//從fragmentManager裡面找到fragment
fgOne = (OneFragment) fragmentManager.findFragmentByTag(OneFragment.class.getName());
fgTwo = (TwoFragment) fragmentManager.findFragmentByTag(TwoFragment.class.getName());
fgThree = (ThreeFragment) fragmentManager.findFragmentByTag(ThreeFragment.class.getName());
//解決重疊問題show裡面可以指定恢復的頁面
fragmentManager.beginTransaction()
.show(fgOne)
.hide(fgTwo)
.hide(fgThree)
.commit();
//把當前顯示的fragment記錄下來
currentFragment = fgOne;
}else{ //正常啟動時調用
fgOne = new OneFragment();
fgTwo = new TwoFragment();
fgThree = new ThreeFragment();
showFragment(fgOne);
}
OK,當app後台時遇到“內存重啟”的情況下,再返回我們的app,就會恢復到show(fgOne)
頁面,而且還不會造成重疊問題!
很顯然,這樣結束是不道德的,因為有人會問了,如果想記錄當前退出的狀態以至於下次恢復時直接顯示之前的fragment頁面怎麼辦,恩,對於這個問題,我們可以在activity的onSaveInstanceState()
方法中記錄一下“內存重啟”之前的Fragment的頁面,然後在oncreate()
中取出來,根據保存的頁面來顯示到指定的fragment,代碼如下:
@Override
protected void onSaveInstanceState(Bundle outState) {
//“內存重啟”時保存當前的fragment名字
outState.putString(STATE_FRAGMENT_SHOW,currentFragment.getClass().getName());
super.onSaveInstanceState(outState);
}
然後在oncreate()
方法中添加(修改上面的那個代碼)
if (savedInstanceState != null) { // “內存重啟”時調用
//獲取“內存重啟”時保存的fragment名字
String saveName = savedInstanceState.getString(STATE_FRAGMENT_SHOW);
//從fragmentManager裡面找到fragment
fgOne = (OneFragment) fragmentManager.findFragmentByTag(OneFragment.class.getName());
fgTwo = (TwoFragment) fragmentManager.findFragmentByTag(TwoFragment.class.getName());
fgThree = (ThreeFragment) fragmentManager.findFragmentByTag(ThreeFragment.class.getName());
//如果為空就默認操作
if(TextUtils.isEmpty(saveName)){
//解決重疊問題
fragmentManager.beginTransaction()
.show(fgOne)
.hide(fgTwo)
.hide(fgThree)
.commit();
//把當前顯示的fragment記錄下來
currentFragment = fgOne;
}else{
if(saveName.equals(fgOne.getClass().getName())){ //如果推出之前是OneFragment
//解決重疊問題
fragmentManager.beginTransaction()
.show(fgOne)
.hide(fgTwo)
.hide(fgThree)
.commit();
//把當前顯示的fragment記錄下來
currentFragment = fgOne;
}else if(saveName.equals(fgTwo.getClass().getName())){ //如果推出之前是TwoFragment
//解決重疊問題
fragmentManager.beginTransaction()
.show(fgTwo)
.hide(fgOne)
.hide(fgThree)
.commit();
//把當前顯示的fragment記錄下來
currentFragment = fgTwo;
}else{ //如果推出之前是ThreeFragment
//解決重疊問題
fragmentManager.beginTransaction()
.show(fgThree)
.hide(fgTwo)
.hide(fgOne)
.commit();
//把當前顯示的fragment記錄下來
currentFragment = fgThree;
}
}
}else{ //正常啟動時調用
fgOne = new OneFragment();
fgTwo = new TwoFragment();
fgThree = new ThreeFragment();
showFragment(fgOne);
}
OK,這樣就可以了,我們通過保存當前顯示的fragment的類名,當我們在第二個fragment頁面時後台,等到“內存重啟”後返回該app時,就根據之前保存的類名來判斷加載指定的fragment,而且,重疊的問題也解決了!
本章代碼及apk:點擊免費下載
最後在說一點:
getActivity()空指針
可能你遇到過getActivity()返回null,或者平時運行完好的代碼,在“內存重啟”之後,調用getActivity()的地方卻返回null,報了空指針異常。
大多數情況下的原因:你在調用了getActivity()時,當前的Fragment已經onDetach()了宿主Activity。
比如:你在pop了Fragment之後,該Fragment的異步任務仍然在執行,並且在執行完成後調用了getActivity()方法,這樣就會空指針。
解決辦法:
更”安全”的方法:(對於Fragment已經onDetach這種情況,我們應該避免在這之後再去調用宿主Activity對象,比如取消這些異步任務,但我們的團隊可能會有粗心大意的情況,所以下面給出的這個方案會保證安全)
在Fragment基類裡設置一個Activity mActivity的全局變量,在onAttach(Activity activity)裡賦值,使用mActivity代替getActivity(),保證Fragment即使在onDetach後,仍持有Activity的引用(有引起內存洩露的風險,但是相比空指針閃退,這種做法“安全”些),即:
protected Activity mActivity;
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
this.mActivity = activity;
}
/**
* 如果你用了support 23的庫,上面的方法會提示過時,有強迫症的小伙伴,可以用下面的方法代替
*/
@Override
public void onAttach(Context context) {
super.onAttach(context);
this.mActivity = (Activity)context;
}
1、 概述 DialogFragment在android 3.0時被引入。是一種特殊的Fragment,用於在Activity的內容之上展示一個模態的對
實現了浏覽器的返回 前進 主頁 退出 輸入網址的功能注釋的很清楚啦 就不多說了首先是布局文件 <linearlayout xmlns:android=&q
實現了一個有趣的小東西:使用自定義View繪圖,一邊畫線,畫出的線條漸漸變淡,直到消失。效果如下圖所示:用屬性動畫或者漸變填充(Shader)可以做到一筆一筆的變化,但要
https://github.com/ddwhan0123/Useful-Open-Source-Android往常我們經常會用到SP,大致代碼像這樣:SharedPre