Android Fragment 最佳實(shí)踐

所謂知之者不如好之者,好之者不如樂之者售滤。要想持之以恒,最佳的狀態(tài)便是樂在其中。本文圖文并茂,帶你從Android Fragment最佳實(shí)踐的“全世界”路過完箩。
P.S. 這應(yīng)該是你能找到的關(guān)于Fragment小型實(shí)踐的最全分析了

先貼上效果圖:

效果圖

這是一個(gè)關(guān)于水果的項(xiàng)目(麻雀雖小赐俗,五臟俱全嘛(;???)=3????):
整個(gè)界面分為兩個(gè)部分,左半部分是一個(gè)列表弊知,用于顯示水果的名稱阻逮。
右半部分則用來顯示水果的名稱及簡介。

既然是面向?qū)ο缶幊蹋?br> 我們首先就需要建立一個(gè)水果的實(shí)體類Fruit來模擬這些水果秩彤。
不過叔扼,由于我們需要對(duì)這些水果進(jìn)行管理,所以這里我們考慮建立一個(gè)名為AllFruit的外部類來對(duì)這些水果進(jìn)行管理漫雷。
當(dāng)然瓜富,并不是說非得建立這種內(nèi)外部類的關(guān)系,只是這樣的設(shè)計(jì)更加自然降盹,符合邏輯食呻。
代碼如下:

public class AllFruit {

//定義內(nèi)部類Fruit
    public static class Fruit{//Fruit類開始
//Fruit類的成員變量
        public Integer id;
        public String name;
        public String description;

        //Fruit類的構(gòu)造器
        public Fruit(Integer id, String name, String description){
            this.id = id;
            this.name = name;
            this.description = description;
        }

//toString方法可以理解為水果對(duì)自己的介紹。這里我們重寫之后澎现,
//當(dāng)直接輸出水果對(duì)象時(shí)會(huì)調(diào)用此方法仅胞,此處輸出水果的name屬性
        @Override
        public String toString() {
            return name;
        }
    }//Fruit類結(jié)束

    //用list集合來記錄所有的水果對(duì)象
    public  static List<Fruit> FRUIT_LIST_ITEMS = new ArrayList<>();
    //使用map集合來記錄所有的水果對(duì)象
    public static Map<Integer,Fruit> FRUIT_MAP_ITEMS = new HashMap<>();

    static {
        //通過靜態(tài)初始化塊來事先定義List和Map集合中的內(nèi)容
        //添加Fruit對(duì)象的方法是:用封裝好的addItem()方法來添加:
        addItem(new Fruit(1,"Apple","蘋果" +
                "是薔薇科蘋果亞科蘋果屬植物,其樹為落葉喬木剑辫。" +
                "蘋果的果實(shí)富含礦物質(zhì)和維生素干旧,是人們最常食用的水果之一。"));
        addItem(new Fruit(2,"Pear","梨是一種水果的名稱妹蔽,薔薇科梨屬植物椎眯," +
                "多年生落葉喬木果樹,葉子卵形胳岂,花多白色编整," +
                "一般梨的顏色為外皮呈現(xiàn)出金黃色或暖黃色," +
                "里面果肉則為通亮白色乳丰,鮮嫩多汁掌测,口味甘甜," +
                "核味微酸产园,是很好的水果汞斧。很多分布在華北、東北什燕、西北及長江流域各省粘勒。"));
        addItem(new Fruit(3,"Banana","香蕉,又稱甘蕉屎即、芎蕉庙睡、芽蕉事富,弓蕉," +
                "為芭蕉科芭蕉屬小果野蕉的人工栽培雜交種乘陪,為多年生草本植物统台。" +
                "果實(shí)長有棱;果皮黃色暂刘,果肉白色饺谬,味道香甜捂刺。" +
                "主要生長在熱帶谣拣、亞熱帶地區(qū)。原產(chǎn)于亞洲東南部熱帶族展、亞熱帶地區(qū)森缠。"));
        addItem(new Fruit(4,"grape","葡萄為葡萄科葡萄屬木質(zhì)藤本植物,小枝圓柱形仪缸,有縱棱紋贵涵," +
                "無毛或被稀疏柔毛,葉卵圓形恰画,圓錐花序密集或疏散宾茂,基部分枝發(fā)達(dá)," +
                "果實(shí)球形或橢圓形拴还,花期4-5月跨晴,果期8-9月。"+
                "葡萄是世界最古老的果樹樹種之一片林,葡萄的植物化石發(fā)現(xiàn)于第三紀(jì)地層中端盆," +
                "說明當(dāng)時(shí)已遍布于歐、亞及格陵蘭费封。[1]  葡萄原產(chǎn)亞洲西部焕妙,世界各地均有栽培,[2]  " +
                "世界各地的葡萄約95%集中分布在北半球弓摘。"));
    }
//封裝在集合中添加水果對(duì)象的方法
    private static void addItem(Fruit fruit){
        FRUIT_LIST_ITEMS.add(fruit);
        FRUIT_MAP_ITEMS.put(fruit.id,fruit);
    }

}

用圖示來說明的話焚鹊,其邏輯是醬嬸兒的:

圖一:關(guān)于水果類的說明

一目了然,外部類AllFruit管理著內(nèi)部類Fruit韧献。

  • AllFruit將Fruit類的信息以兩種方式保存:List和Map寺旺;
  • 如果別人來找AllFruit要Fruit的信息,則AllFruit就會(huì)根據(jù)具體情況來選擇不同的方式以交付信息
注:關(guān)于靜態(tài)初始化塊的說明:
  1. Java 中可以通過初始化塊進(jìn)行數(shù)據(jù)賦值势决;
  2. 靜態(tài)初始化塊只在類(本例中是AllFruit類)加載時(shí)執(zhí)行阻塑,且只會(huì)執(zhí)行一次,同時(shí)靜態(tài)初始化塊只能給靜態(tài)變量賦值果复,不能初始化普通的成員變量陈莽。
第二步:

既然已經(jīng)定義好了實(shí)體類,那我們就要開始考慮項(xiàng)目的兩個(gè)部分了。

項(xiàng)目的結(jié)構(gòu)

這里我們先考慮右半部分的實(shí)現(xiàn):
這部分實(shí)際是一個(gè)包含兩個(gè)文本框的Fragment:
先貼出其布局文件:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <!--定義一個(gè)TextView來顯示水果名稱-->
    <TextView
        android:id="@+id/fruit_name"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textSize="40sp"
        android:layout_marginBottom="5dp"
        android:padding="20dp"
        android:textColor="@color/colorAccent"/>

    <!--再定義一個(gè)TextView來顯示水果的簡介-->
    <TextView
        android:id="@+id/fruit_desc"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textSize="16sp"
        android:padding="30dp"/>

就定義了兩個(gè)文本框而已走搁。十分簡單独柑,不再贅述。
重點(diǎn)是我們要怎樣將布局文件引入Fragment呢私植?
Android已經(jīng)為我們做好了安排:

public class FruitTitleAndDescFragment extends android.app.Fragment {
    public static final String ITEM_ID = "item_id";
    //在全局變量中保存 這個(gè)Fragment將要顯示的Fruit對(duì)象
    AllFruit.Fruit fruit;

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if (getArguments().containsKey(ITEM_ID)){
            fruit = AllFruit.FRUIT_MAP_ITEMS
.get(getArguments().getInt(ITEM_ID));
        }

    }

    //重寫onCreateView()方法忌栅,此方法返回的view將作為Fragment顯示的組件
    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater,
 @Nullable ViewGroup container, 
@Nullable Bundle savedInstanceState) {
        View parentView = inflater.inflate(
R.layout.fruit_name_and_desc,
container,
false);
//fruit為之前定義的全局變量
        if (fruit!= null){
            //讓id為fruit_name的文本框顯示水果的name
            //注意setText()方法前面有幾個(gè)括號(hào)
            ((TextView)parentView
.findViewById(R.id.fruit_name))
.setText(fruit.name);
            //讓id為fruit_desc的文本框顯示水果的desc(描述信息)
            ((TextView)parentView
.findViewById(R.id.fruit_desc))
.setText(fruit.description);
        }
        return parentView;
    }
}

這里我們定義了一個(gè)FruitTitleAndDescFragment類,并讓其繼承自Fragment類曲稼。
并且重寫了onCreate()方法和onCreateView()方法索绪。
其中,onCreateView()方法就是用來將Fragment的實(shí)現(xiàn)類與其布局進(jìn)行綁定的贫悄。

具體方法為:
  • 調(diào)用onCreateView方法傳入的inflater對(duì)象的inflate方法瑞驱,
    傳入三個(gè)參數(shù),其中后兩個(gè)一般都是container和false窄坦,而本例子中的R.layout.fruit_name_and_desc正是我們想要加載的布局唤反。這樣我們就得到了根布局,這里我們將其命名為parentView鸭津。
  • 再通過parentView的findViewById()方法就可以得到各個(gè) 子view
  • 然后我們讓得到的兩個(gè)文本框分別顯示Fruit對(duì)象的name和description屬性
  • 從這里我們也可以看出來 onCreateView()方法和單純的setContentView()方法的區(qū)別:
    調(diào)用后者只是為了加載布局彤侍,而調(diào)用前者則是要兼顧加載布局和對(duì)布局中組件的行為進(jìn)行設(shè)置。比如此處我們便設(shè)置了文本框顯示的內(nèi)容逆趋。
    有一定英語基礎(chǔ)的童鞋應(yīng)該很好理解:所謂onCreateView所表達(dá)的盏阶,正是view被Create之后,該做什么父泳!
  • 最后般哼,別忘了要將parentView返回。

而onCreate()方法則是在創(chuàng)建Fragment對(duì)象時(shí)被調(diào)用惠窄。
因?yàn)榕c后面的邏輯聯(lián)系較緊密蒸眠,因此其中的代碼我們稍后再作討論。

第三步:

現(xiàn)在我們?cè)賮砜紤]左半部分的實(shí)現(xiàn)杆融。
左半部分是一個(gè)列表楞卡。可能有童鞋的第一反應(yīng)就是用ListView來實(shí)現(xiàn)脾歇。但其實(shí)Android中已經(jīng)為我們準(zhǔn)備好了一個(gè)ListFragment類蒋腮。讓我們的活動(dòng)繼承自這個(gè)類,就能輕松實(shí)現(xiàn)列表的形式:

//直接繼承自ListFragment
public class FruitListFragment extends ListFragment{

//接口的實(shí)例    
private Callback myCallback;

//在FruitListFragment中定義一個(gè)接口
    public interface Callback{ 
        void onItemClicked (Integer id);
    }//接口結(jié)束


    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //為該ListFragment設(shè)置Adapter
       setListAdapter(new ArrayAdapter<AllFruit.Fruit>(
getActivity(),
               android.R.layout.simple_list_item_activated_1,
               android.R.id.text1,
AllFruit.FRUIT_LIST_ITEMS));
    }//onCreate()方法結(jié)束

//    當(dāng)Fragment被添加藕各、顯示到Activity中時(shí)池摧,回調(diào)此方法
    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
//        如果Activity沒有實(shí)現(xiàn)Callback接口,則拋出異常
        if (!(context instanceof Callback)){
            throw new IllegalStateException(
                    "FruitListFragment 所在的Activity必須實(shí)現(xiàn)Callback接口"
            );
        }
        //把該Activity當(dāng)做Callback對(duì)象
        myCallback = (Callback) context;
    }//onAttach()結(jié)束

//    當(dāng)該Fragment從它所屬的Activity中被刪除時(shí)回調(diào)此方法
    @Override
    public void onDetach() {
        super.onDetach();
//        給myCallback賦空值
        myCallback = null;
    }//onDetach()結(jié)束

    @Override
    public void onListItemClick(ListView l, View v, int position, long id) {
        super.onListItemClick(l, v, position, id);
//        觸發(fā)myCallback的onItemclicked()方法
        myCallback.onItemClicked(AllFruit.FRUIT_LIST_ITEMS.get(position).id);
    }//onListItemClick()結(jié)束
}

這里我們定義了一個(gè)FruitListFragment類激况。
并重寫了四個(gè)方法作彤。
下面一一講解:

  • onCreate()方法很好理解:
  1. 其規(guī)定了本ListFragment被創(chuàng)建時(shí)應(yīng)該執(zhí)行那些操作膘魄。
  2. 這里我們只做了一件事: 就是調(diào)用setListAdapter()方法,為要顯示的列表指定了Adapter竭讳,以綁定數(shù)據(jù)源创葡。
  3. 為setListAdapter()方法傳入的是ArrayAdapter的實(shí)例:
ArrayAdapter的構(gòu)造器(image from Google

可以看到,ArrayAdapter共有5個(gè)重載的構(gòu)造器绢慢,我們選用的正是第五個(gè)灿渴。

  1. 第一個(gè)參數(shù)是context。這個(gè)是自然胰舆;
    第二個(gè)參數(shù)是resource骚露,其實(shí)也就是列表中每一項(xiàng)的Layout;
    第三個(gè)參數(shù)是textViewResourceId思瘟,指的是列表中每一項(xiàng)所包含的TextView的樣子(我們的水果名正是用TextView顯示出來的)荸百。
    第二個(gè)和第三個(gè)參數(shù)闻伶,在本例中都是引用的Android內(nèi)置的主題滨攻。
  2. 最后一個(gè)參數(shù)最重要,因?yàn)槠涮峁┝藬?shù)據(jù)的來源蓝翰。這里我們指定為AllFruit.FRUIT_LIST_ITEMS光绕。也就是先前在AllFruit中定義的list集合。
  • onAttach()方法在Fragment被添加畜份、顯示到Activity中時(shí)回調(diào)诞帐。
  1. “Attach”表示附著。正體現(xiàn)了Fragment與Activity的聯(lián)系爆雹。
  2. 可以看到类溢,回調(diào)時(shí)傳入了一個(gè)context對(duì)象洽损,由于Activity是Context的子類,所以可以此處傳入的context對(duì)象所指代的,正是該Fragment所依附的Activity译暂。
  3. 并且這里我們將這個(gè)傳入的活動(dòng)賦給了一個(gè)接口對(duì)象,關(guān)于這樣做的目的乓搬,以及在FruitListFragment內(nèi)部定義一個(gè)名為Callback接口的意義商源,稍后再做闡釋。現(xiàn)在先記住驻子,myCallback是一個(gè)全局變量灿意,也就是說它的作用域?yàn)檎麄€(gè)類。
  • onDetach()方法與onAttach()方法正相反
  1. 所以崇呵,正因?yàn)樵趏nAttach()方法中將當(dāng)前與Fragment產(chǎn)生聯(lián)系的Activity賦給了myCallback缤剧。在onDetach()方法中,當(dāng)Fragment與Activity不再發(fā)生聯(lián)系時(shí)域慷,就為myCallback賦空值以示關(guān)系的脫離荒辕。
  • onListItemClick()方法顧名思義司顿,應(yīng)當(dāng)在FruitListFragment中的list的子項(xiàng)被點(diǎn)擊時(shí)被回調(diào)。
...
  @Override
    public void onListItemClick(ListView l, View v, int position, long id) {
        super.onListItemClick(l, v, position, id);
//        觸發(fā)myCallback的onItemclicked()方法
        myCallback.onItemClicked(
AllFruit.FRUIT_LIST_ITEMS.get(position).id);
    }//onListItemClick()結(jié)束

可以看到兄纺,我們?cè)谄浞椒w中調(diào)用了 Callback 接口中定義的方法:

onItemClicked(Integer id)

旨在設(shè)置當(dāng)list的子項(xiàng)被點(diǎn)擊時(shí)應(yīng)該執(zhí)行的邏輯大溜。

那么問題就來了。

既然onItemClicked(Integer id)方法被定義在接口中估脆,那么它自然是一個(gè)抽象方法钦奋。
那么這個(gè)抽象方法應(yīng)該由誰來實(shí)現(xiàn)呢?當(dāng)然是由實(shí)現(xiàn)了接口的那個(gè)類來實(shí)現(xiàn)了疙赠。
那么又由誰來實(shí)現(xiàn)該接口呢付材?

答案是:MainActivity

(跑得太遠(yuǎn),都快忘了還有MainActivity存在了)
那么這就關(guān)系到MainActivity存在的初衷了圃阳。
我們需要MainActivity來做什么呢厌衔?
先看看其布局文件:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:divider="?dividerHorizontal"
    android:orientation="horizontal">

    <fragment
        android:id="@+id/fruit_list"    android:name="com.example.feverdg.fragmenttest.FruitListFragment"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="1" />

    <FrameLayout
        android:id="@+id/fruit_desc_container"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="3" />
</LinearLayout>

可以看到,這其中包括我們事先定義好的FruitListFragment片段捍岳。用于顯示列表項(xiàng)富寿。
而下面這個(gè)卻不是fragment標(biāo)簽,而是一個(gè)FrameLayout的標(biāo)簽
等等锣夹,那我們之前

public class FruitTitleAndDescFragment extends android.app.Fragment { ... }

定義FruitTitleAndDescFragment片段定義了半天是為了什么页徐?
當(dāng)然是為了顯示了∫迹可是為什么不用fragment標(biāo)簽來引用呢变勇?
這是因?yàn)槲覀儾⒉皇窍胍苯訉⑦@個(gè)類顯示在MainActivity中。
而是要通過點(diǎn)擊不同的FruitListFragment的子項(xiàng)來動(dòng)態(tài)地生成FruitTitleAndDescFragment 片段贴唇。
也正是為了完成這個(gè)點(diǎn)擊事件的回調(diào)方法搀绣,我們才定義了Callback接口,并讓MainActivity必須實(shí)現(xiàn)這個(gè)接口:

public class MainActivity extends AppCompatActivity implements FruitListFragment.Callback {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
//實(shí)現(xiàn)Callback接口中定義的抽象方法
    @Override
    public void onItemClicked(Integer id) {
//創(chuàng)建一個(gè)Bundle戳气,以向因?yàn)辄c(diǎn)擊事件而將要生成的Fragment中傳入?yún)?shù)
        Bundle arg = new Bundle();
        arg.putInt(FruitTitleAndDescFragment.ITEM_ID, id);
//        創(chuàng)建FruitTitleAndDescFragment對(duì)象
        FruitTitleAndDescFragment fragment = new FruitTitleAndDescFragment();
//        向fragment中傳入?yún)?shù)
        fragment.setArguments(arg);
//        用fragment替換fruit_desc_container中正在顯示的Fragment
        android.app.FragmentManager fragmentManager = getFragmentManager();
        android.app.FragmentTransaction transaction = fragmentManager.beginTransaction();
        transaction.replace(R.id.fruit_desc_container,fragment);
        transaction.addToBackStack(null);
        transaction.commit();
    }
}

可以看到:

  • 我們首先創(chuàng)建一個(gè)Bundle链患,以向因?yàn)辄c(diǎn)擊事件而將要生成的Fragment中傳入?yún)?shù);
  • 然后調(diào)用Bundle類的putInt()方法向該Bundle對(duì)象中傳入數(shù)據(jù)物咳。
putInt()方法 (image from Google)

可以看到putInt()方法接收的其實(shí)就是鍵值對(duì): String類型的鍵锣险,int類型的值。
這里傳入的

arg.putInt(FruitTitleAndDescFragment.ITEM_ID, id);

FruitTitleAndDescFragment.ITEM_ID看上去好像很復(fù)雜览闰,其實(shí)各位童鞋如果記性好的話芯肤,會(huì)發(fā)現(xiàn)這不過個(gè)定義在FruitTitleAndDescFragment類中的字符串常量:

public class FruitTitleAndDescFragment extends android.app.Fragment {
    public static final String ITEM_ID = "item_id";
...

鍵值對(duì)的鍵有了,那這個(gè)int類型的id值又是打哪兒來呢压鉴?
還記得我們?cè)贔ruitListFragment中重寫的onListItemClick()方法嗎崖咨?

public void onListItemClick(ListView l, View v, int position, long id) {
        super.onListItemClick(l, v, position, id);
//        觸發(fā)myCallback的onItemclicked()方法
        myCallback.onItemClicked(AllFruit.FRUIT_LIST_ITEMS
.get(position).id);
    }

我們首先用Fruit類對(duì)象的list集合 AllFruit.FRUIT_LIST_ITEM 調(diào)用get()方法;
為get()方法傳入重寫onListItemClick()方法時(shí)傳入的position參數(shù)油吭;
這就得到了具體是哪一個(gè)Fruit子項(xiàng)被點(diǎn)擊击蹲,然后再得到該子項(xiàng)的id署拟。

...
//        創(chuàng)建FruitTitleAndDescFragment對(duì)象
        FruitTitleAndDescFragment fragment = new FruitTitleAndDescFragment();
//        向fragment中傳入?yún)?shù)
        fragment.setArguments(arg);
//        用fragment替換fruit_desc_container中正在顯示的Fragment
        android.app.FragmentManager fragmentManager = getFragmentManager();
        android.app.FragmentTransaction transaction = fragmentManager.beginTransaction();
        transaction.replace(R.id.fruit_desc_container,fragment);
//將片段加入返回棧,也就是當(dāng)按下back鍵后歌豺,會(huì)顯示先前被replace掉的片段
        transaction.addToBackStack(null);
        transaction.commit();

準(zhǔn)備就緒之后推穷,我們便創(chuàng)建一個(gè)新的FruitTitleAndDescFragment的對(duì)象。并調(diào)用setArguments(arg)方法為其指定了參數(shù)类咧,也就是那個(gè)帶著id信息的Bundle對(duì)象馒铃。
現(xiàn)在知道前面FruitTitleAndDescFragment類中onCreate()方法的作用了吧:

 @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if (getArguments().containsKey(ITEM_ID)){
            fruit = AllFruit.FRUIT_MAP_ITEMS
.get(getArguments().getInt(ITEM_ID));
        }
    }

只要是有新的FruitTitleAndDescFragment對(duì)象被Create,onCreate()方法就會(huì)執(zhí)行痕惋。
然后我們就能夠通過Bundle對(duì)象的getArguments()和getInt()方法接收到被點(diǎn)擊的水果對(duì)象的id信息区宇。
最后再以該id為鍵在之前定義的水果對(duì)象的map集合中查到對(duì)應(yīng)的值。

另外值戳,替換Fragment的操作其實(shí)很簡單:
無非就是先得到FragmentManager议谷,然后再由它創(chuàng)建FragmentTransaction。FragmentTransaction對(duì)象再調(diào)用replace方法替換和commit方法執(zhí)行就可以了堕虹。
唯一需要注意的就是replace()方法的參數(shù)卧晓。R.id.fruit_desc_container指的就是FrameLayout的id。也很簡單鲫凶,不再贅述禀崖。

當(dāng)然衩辟,最重要的也最精彩的部分還是Callback接口的創(chuàng)建螟炫。

其巧妙之處就在于:

  • MainActivity實(shí)現(xiàn)Callback接口之后,它就可以被視作是一個(gè)Callback對(duì)象了艺晴。
  • 所以MainActivity自然能調(diào)用接口中的onItemCliked()方法昼钻。
  • 而這個(gè)所謂的MainActivity正是我們念叨了半天的會(huì)與被創(chuàng)建出來的FruitTitleAndDescFragment對(duì)象不斷產(chǎn)生和失去關(guān)聯(lián)的那個(gè)Activity。
  • 所以我們?cè)趏nAttach()和onDetach()方法中都可以引用到這個(gè)Activity
//    當(dāng)Fragment被添加封寞、顯示到Activity中時(shí)然评,回調(diào)此方法
    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
//        如果Activity沒實(shí)現(xiàn)Callback接口,則拋出異常
        if (!(context instanceof Callback)){
            throw new IllegalStateException(
                    "FruitListFragment 所在的Activity必須實(shí)現(xiàn)Callback接口"
            );
        }
        //把該Activity當(dāng)做Callback對(duì)象
        myCallback = (Callback) context;
    }//onAttach()結(jié)束

//    當(dāng)該Fragment從它所屬的Activity中被刪除時(shí)回調(diào)此方法
    @Override
    public void onDetach() {
        super.onDetach();
//        給myCallback賦空值
        myCallback = null;
    }//onDetach()結(jié)束
  • 而也正是因?yàn)槲覀冊(cè)趏nAttach()方法中通過
 //把該Activity當(dāng)做Callback對(duì)象
        myCallback = (Callback) context;

獲得了對(duì)MainActivity的引用狈究,我們才得以在onListItemClick()方法中通過myCallback來調(diào)用接口中定義的onItemCliked()方法碗淌。

  • 如此,我們才得以在每次點(diǎn)擊FruitListFragment列表中的子項(xiàng)時(shí)都能在MainActivity的FrameLayout布局部分生成一個(gè)新的FruitTitleAndDescFragment的實(shí)例抖锥。
  • 看上去也就像是亿眠,點(diǎn)擊左邊列表中的水果名,就能在右邊列表顯示其相關(guān)的name和description信息磅废。

--- The End

事無巨細(xì)地分析纳像,不知不覺就有點(diǎn)長篇累牘了。但愿能為各位同道中人填點(diǎn)坑吧拯勉!
水平有限竟趾,難免紕漏文中如有不當(dāng)之處歡迎批評(píng)指正憔购。
諸君共勉:)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市岔帽,隨后出現(xiàn)的幾起案子玫鸟,更是在濱河造成了極大的恐慌,老刑警劉巖犀勒,帶你破解...
    沈念sama閱讀 218,036評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件鞋邑,死亡現(xiàn)場離奇詭異,居然都是意外死亡账蓉,警方通過查閱死者的電腦和手機(jī)枚碗,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,046評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來铸本,“玉大人肮雨,你說我怎么就攤上這事∠溏瑁” “怎么了怨规?”我有些...
    開封第一講書人閱讀 164,411評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長锡足。 經(jīng)常有香客問我波丰,道長,這世上最難降的妖魔是什么舶得? 我笑而不...
    開封第一講書人閱讀 58,622評(píng)論 1 293
  • 正文 為了忘掉前任掰烟,我火速辦了婚禮,結(jié)果婚禮上沐批,老公的妹妹穿的比我還像新娘纫骑。我一直安慰自己,他們只是感情好九孩,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,661評(píng)論 6 392
  • 文/花漫 我一把揭開白布先馆。 她就那樣靜靜地躺著,像睡著了一般躺彬。 火紅的嫁衣襯著肌膚如雪煤墙。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,521評(píng)論 1 304
  • 那天宪拥,我揣著相機(jī)與錄音仿野,去河邊找鬼。 笑死江解,一個(gè)胖子當(dāng)著我的面吹牛设预,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播犁河,決...
    沈念sama閱讀 40,288評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼鳖枕,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼魄梯!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起宾符,我...
    開封第一講書人閱讀 39,200評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤酿秸,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后魏烫,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體辣苏,經(jīng)...
    沈念sama閱讀 45,644評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,837評(píng)論 3 336
  • 正文 我和宋清朗相戀三年哄褒,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了稀蟋。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,953評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡呐赡,死狀恐怖退客,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情链嘀,我是刑警寧澤萌狂,帶...
    沈念sama閱讀 35,673評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站怀泊,受9級(jí)特大地震影響茫藏,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜霹琼,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,281評(píng)論 3 329
  • 文/蒙蒙 一务傲、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧碧囊,春花似錦树灶、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,889評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽泊窘。三九已至熄驼,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間烘豹,已是汗流浹背瓜贾。 一陣腳步聲響...
    開封第一講書人閱讀 33,011評(píng)論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留携悯,地道東北人祭芦。 一個(gè)月前我還...
    沈念sama閱讀 48,119評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像憔鬼,于是被迫代替她去往敵國和親龟劲。 傳聞我的和親對(duì)象是個(gè)殘疾皇子胃夏,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,901評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,129評(píng)論 25 707
  • Fragment Fragment,碎片昌跌,是 Android 3.0 開始引入的仰禀,其目的在于同時(shí)兼容手機(jī)和平板的開...
    AshengTan閱讀 1,729評(píng)論 0 4
  • 我是第一次看到初生兒,覺得可真丑安戏摺答恶!小臉蛋上全是褶子和脂肪粒,被產(chǎn)道擠壓的腦袋像胡蘿卜萍诱。但我想這是我的寶貝女...
    一霏姐姐學(xué)寫作閱讀 308評(píng)論 0 1
  • https://openreview.net/group?id=ICLR.cc/2017/conference O...
    FinlayLiu閱讀 948評(píng)論 0 1
  • 在寫文章之前,先問問各位做銷售的朋友碍庵,當(dāng)客戶拒絕你的時(shí)候映企,你是如何對(duì)待這客戶的拒絕的呢? 一般來說静浴,大部分的銷售新...
    SI玲閱讀 366評(píng)論 0 1