省略Fragment的生命周期
省略Fragment的靜態(tài)加載
1.動態(tài)添加Fragment的方法
-
添加有UI的Fragment
ExampleFragment fragment = new ExampleFragment(); fragmentTransaction.add(R.id.fragment_container, fragment); fragmentTransaction.commit();
-
添加沒有UI的Fragment
ExampleFragment fragment = new ExampleFragment(); fragmentTransaction.add(fragment,"ExampleFragment"); fragmentTransaction.commit();
由于它并不與 Activity 布局中的視圖關(guān)聯(lián),因此不會收到對
onCreateView()
的調(diào)用蒸其。因此蹋订,不需要實(shí)現(xiàn)該方法。對應(yīng)的可以通過 findFragmentByTag("ExampleFragment")獲取Fragment實(shí)例清寇。
2.兩個(gè)Fragment與Activity之間的通信(官方建議)
前提:
- 在Activity中有兩個(gè)Fragment,分別時(shí)LeftFragment和RightFragment
- RightFragment會隨著LeftFragment的變化而改變(eg:點(diǎn)擊左側(cè)Fragment后右側(cè)Fragment加載詳情)
實(shí)現(xiàn):
-
1.在LeftFragment中定義一個(gè)回調(diào)接口护蝶,Activity必須實(shí)現(xiàn)這個(gè)接口
public static class LeftFragment extends ListFragment { ... // Container Activity must implement this interface public interface OnArticleSelectedListener { public void onArticleSelected(Uri articleUri); } ... }
-
2.宿主Activity必須實(shí)現(xiàn)該接口
public class MainActivity extends Activity implements OnArticleSelectedListener{ //...省略若干代碼 @Override public void onArticleSelected(Uri articleUri){ } }
-
3.在LeftFragment中獲取Activity實(shí)現(xiàn)接口的實(shí)例
public static class FragmentA extends ListFragment { OnArticleSelectedListener mListener; ... @Override public void onAttach(Activity activity) { super.onAttach(activity); try { mListener = (OnArticleSelectedListener) activity; } catch (ClassCastException e) { throw new ClassCastException(activity.toString() + " must implement OnArticleSelectedListener"); } } ... }
3.當(dāng)Activity重啟時(shí)华烟,使用Fragment保存數(shù)據(jù)
當(dāng)Activity的配置發(fā)生變化導(dǎo)致重啟時(shí),為了提高用戶體驗(yàn)持灰,一般需要在Activity銷毀的時(shí)候保存界面上的一些數(shù)據(jù)盔夜,再次創(chuàng)建的時(shí)候恢復(fù)數(shù)據(jù)。
通常的做法是在
onSaveInstanceState()
回調(diào)時(shí)保存有關(guān)應(yīng)用狀態(tài)數(shù)據(jù)堤魁,然后喂链,可以在onCreate()
或onRestoreInstanceState()
期間恢復(fù) Activity 狀態(tài)。
通過系統(tǒng)回調(diào)
onSaveInstanceState()
方法將數(shù)據(jù)保存在Boundle
妥泉,但當(dāng)數(shù)據(jù)量較大時(shí)椭微,可能無法完全恢復(fù) Activity 狀態(tài),因?yàn)樗⒎窃O(shè)計(jì)用于攜帶大型對象(例如位圖Bitmap)盲链,而且其中的數(shù)據(jù)必須先序列化蝇率,再進(jìn)行反序列化,這可能會消耗大量內(nèi)存并使得配置變更速度緩慢刽沾。在這種情況下本慕,如果 Activity 因配置變更而重啟,則可通過保留
Fragment
來減輕重新初始化 Activity 的負(fù)擔(dān)侧漓。
步驟如下:
- 1.擴(kuò)展
Fragment
類并聲明對有狀態(tài)對象(即我們要保存的對象)的引用锅尘。 - 2.在創(chuàng)建片段后調(diào)用
setRetainInstance(boolean)
。 - 3.將片段添加到 Activity布蔗。
- 4.重啟 Activity 后藤违,使用
FragmentManager
檢索片段。
例如:
定義一個(gè)RetainedFragment
用來保存數(shù)據(jù)
public class RetainedFragment extends Fragment {
// data object we want to retain
private MyDataObject data;
// this method is only called once for this fragment
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// retain this fragment
setRetainInstance(true);
}
public void setData(MyDataObject data) {
this.data = data;
}
public MyDataObject getData() {
return data;
}
}
注意:盡管可以存儲任何對象纵揍,但是切勿傳遞與
Activity
綁定的對象纺弊,例如,Drawable
骡男、Adapter
淆游、View
或其他任何與Context
關(guān)聯(lián)的對象。否則隔盛,它將泄漏原始 Activity 實(shí)例的所有視圖和資源犹菱。 (泄漏資源意味著應(yīng)用將繼續(xù)持有這些資源,但是無法對其進(jìn)行垃圾回收吮炕,因此可能會丟失大量內(nèi)存腊脱。)
然后,使用 FragmentManager
將片段添加到 Activity龙亲。在運(yùn)行時(shí)配置變更期間再次啟動 Activity 時(shí)陕凹,就可以獲得片段中的數(shù)據(jù)對象悍抑。
public class MyActivity extends Activity {
private RetainedFragment dataFragment;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// find the retained fragment on activity restarts
FragmentManager fm = getFragmentManager();
dataFragment = (DataFragment) fm.findFragmentByTag(“data”);
// create the fragment and data the first time
if (dataFragment == null) {
// add the fragment
dataFragment = new DataFragment();
fm.beginTransaction().add(dataFragment, “data”).commit();
// load the data from the web
dataFragment.setData(loadMyData());
}
// the data is available in dataFragment.getData()
...
}
@Override
public void onDestroy() {
super.onDestroy();
// store the data in the fragment
dataFragment.setData(collectMyLoadedData());
}
}
4.向應(yīng)用欄添加項(xiàng)目
Fragment可以通過實(shí)現(xiàn) onCreateOptionsMenu()
向 Activity 的選項(xiàng)菜單(并因此向應(yīng)用欄)貢獻(xiàn)菜單項(xiàng)。不過杜耙,為了使此方法能夠收到調(diào)用搜骡,必須在 onCreate()
期間調(diào)用 setHasOptionsMenu()
,以指示Fragment想要向選項(xiàng)菜單添加菜單項(xiàng)(否則佑女,片段將不會收到對 onCreateOptionsMenu()
的調(diào)用)记靡。
從Fragment添加到選項(xiàng)菜單的任何菜單項(xiàng)都將追加到現(xiàn)有菜單項(xiàng)之后。 選定菜單項(xiàng)時(shí)团驱,F(xiàn)ragment還會收到對 onOptionsItemSelected()
的回調(diào)摸吠。
Fragment向應(yīng)用欄添加項(xiàng)目應(yīng)用十分廣泛,例如下面的效果
我們自己也可以動手實(shí)現(xiàn)這樣的效果嚎花,先看效果:
當(dāng)切換Fragment的時(shí)候寸痢,應(yīng)用欄不同的狀態(tài),so easy紊选!
-
step1.在Fragment的onCreate回調(diào)時(shí)轿腺,調(diào)用Fragment的
setHasOptionsMenu(true)
方法;@Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setHasOptionsMenu(true); }
-
step2.覆蓋
onCreateOptionsMenu()
方法根據(jù)不同位置加載不同的應(yīng)用欄菜單丛楚;@Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { super.onCreateOptionsMenu(menu, inflater); switch (mFragmentType) { case 0: break; case 1: inflater.inflate(R.menu.action, menu); break; case 2: default: inflater.inflate(R.menu.action0, menu); break; } }
-
step3.如果需要監(jiān)聽?wèi)?yīng)用欄的點(diǎn)擊族壳,只需要覆蓋
onOptionsItemSelected()
方法。@Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.navigation_home: Toast.makeText(getContext(), "home", Toast.LENGTH_SHORT).show(); break; case R.id.navigation_dashboard: Toast.makeText(getContext(), "dashboard", Toast.LENGTH_SHORT).show(); break; case R.id.navigation_notifications: Toast.makeText(getContext(), "notifications", Toast.LENGTH_SHORT).show(); break; } return super.onOptionsItemSelected(item); }
另外趣些,還可以通過調(diào)用 registerForContextMenu()
仿荆,在片段布局中注冊一個(gè)視圖來提供上下文菜單。用戶打開上下文菜單時(shí)坏平,片段會收到對 onCreateContextMenu()
的調(diào)用拢操。當(dāng)用戶選擇某個(gè)菜單項(xiàng)時(shí),片段會收到對 onContextItemSelected()
的調(diào)用舶替。
注:盡管Fragment會收到與其添加的每個(gè)菜單項(xiàng)對應(yīng)的菜單項(xiàng)選定回調(diào)令境,但當(dāng)用戶選擇菜單項(xiàng)時(shí),Activity 會首先收到相應(yīng)的回調(diào)顾瞪。 如果 Activity 對菜單項(xiàng)選定回調(diào)的實(shí)現(xiàn)不會處理選定的菜單項(xiàng)舔庶,則系統(tǒng)會將事件傳遞到片段的回調(diào)。 這適用于選項(xiàng)菜單和上下文菜單陈醒。