關(guān)于Fragment,你可能不知道的一切

省略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.兩個Fragment與Activity之間的通信(官方建議)

前提:

  • 在Activity中有兩個Fragment,分別時LeftFragment和RightFragment
  • RightFragment會隨著LeftFragment的變化而改變(eg:點(diǎn)擊左側(cè)Fragment后右側(cè)Fragment加載詳情)

實(shí)現(xiàn):

  • 1.在LeftFragment中定義一個回調(diào)接口,Activity必須實(shí)現(xiàn)這個接口

    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重啟時,使用Fragment保存數(shù)據(jù)

當(dāng)Activity的配置發(fā)生變化導(dǎo)致重啟時,為了提高用戶體驗,一般需要在Activity銷毀的時候保存界面上的一些數(shù)據(jù),再次創(chuàng)建的時候恢復(fù)數(shù)據(jù)。

通常的做法是在 onSaveInstanceState()回調(diào)時保存有關(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ù)量較大時,可能無法完全恢復(fù) Activity 狀態(tài),因為它并非設(shè)計用于攜帶大型對象(例如位圖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 檢索片段。

例如:

定義一個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)行時配置變更期間再次啟動 Activity 時,就可以獲得片段中的數(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)用欄添加項目

Fragment可以通過實(shí)現(xiàn) onCreateOptionsMenu() 向 Activity 的選項菜單(并因此向應(yīng)用欄)貢獻(xiàn)菜單項。不過,為了使此方法能夠收到調(diào)用,必須在 onCreate() 期間調(diào)用 setHasOptionsMenu(),以指示Fragment想要向選項菜單添加菜單項(否則,片段將不會收到對 onCreateOptionsMenu() 的調(diào)用)。

從Fragment添加到選項菜單的任何菜單項都將追加到現(xiàn)有菜單項之后。 選定菜單項時,F(xiàn)ragment還會收到對 onOptionsItemSelected() 的回調(diào)。

Fragment向應(yīng)用欄添加項目應(yīng)用十分廣泛,例如下面的效果

我們自己也可以動手實(shí)現(xiàn)這樣的效果,先看效果:

當(dāng)切換Fragment的時候,應(yīng)用欄不同的狀態(tài),so easy!

  • step1.在Fragment的onCreate回調(diào)時,調(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(),在片段布局中注冊一個視圖來提供上下文菜單。用戶打開上下文菜單時,片段會收到對 onCreateContextMenu() 的調(diào)用。當(dāng)用戶選擇某個菜單項時,片段會收到對 onContextItemSelected() 的調(diào)用。

:盡管Fragment會收到與其添加的每個菜單項對應(yīng)的菜單項選定回調(diào),但當(dāng)用戶選擇菜單項時,Activity 會首先收到相應(yīng)的回調(diào)。 如果 Activity 對菜單項選定回調(diào)的實(shí)現(xiàn)不會處理選定的菜單項,則系統(tǒng)會將事件傳遞到片段的回調(diào)。 這適用于選項菜單和上下文菜單。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Fragment 表示 Activity中的行為或用戶界面部分。您可以將多個片段組合在一個 Activity 中來...
    鹿小純0831閱讀 450評論 0 0
  • 片段 Fragment表示 Activity中的行為或用戶界面部分。您可以將多個片段組合在一個 Activity ...
    岳小川閱讀 934評論 0 3
  • 參考書籍:《第一行代碼》 第二版 郭霖如有錯漏,請批評指出! Activity 定義:Activity是Andro...
    CCCode1997閱讀 1,314評論 0 5
  • ¥開啟¥ 【iAPP實(shí)現(xiàn)進(jìn)入界面執(zhí)行逐一顯】 〖2017-08-25 15:22:14〗 《//首先開一個線程,因...
    小菜c閱讀 7,317評論 0 17
  • 第一個12歲的孩子 語言智能 培養(yǎng)閱讀習(xí)慣:家里閱讀氛圍,外界好玩 的閱讀環(huán)境,例書店,圖書館 繪畫:體驗顏色,結(jié)...
    婷婷_409c閱讀 225評論 0 2

友情鏈接更多精彩內(nèi)容