fragent的使用總結

前言

fragment自動3.0推出以后,在碎片化處理方面一直很受歡迎,平時在項目中也在頻繁使用,自從看了CSDN上郭大神和鴻洋大神對fragment的詳細總結后,自己學習做個筆記。
  郭大神:http://blog.csdn.net/guolin_blog/article/details/8881711
 鴻洋大神:http://blog.csdn.net/lmj623565791/article/details/42628537

fragment的常用方法

(1) 靜態使用

在布局文件xml中使用

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  android:layout_width="match_parent"  
  android:layout_height="match_parent"  
  android:baselineAligned="false" >  

  <fragment  
      android:id="@+id/fragmentOne"  
      android:name="com.ydscience.FragmentOne"  
      android:layout_width="0dp"  
      android:layout_height="match_parent"  
      android:layout_weight="1" />  
  <fragment  
      android:id="@+id/fragmentTwo"  
      android:name="com.ydscience.FragmentTwo"  
      android:layout_width="0dp"  
      android:layout_height="match_parent"  
      android:layout_weight="1" />  

</LinearLayout>  

具體的fragmentOne和fragmentTwo的代碼就不粘貼啦,都是繼承Fragment去實現的。

(2)動態使用

動態使用分為四個步驟
  (a)獲取FragmentManager,通過方法getSupportFragmentManager()獲取。
  (b)開啟一個事物,通過beginTransaction方法開啟。
  (c)向容器內加入Fragment,默認第一個是通過add()方法添加,后面再替換時通過replace方法實現,需要傳入容器的id和Fragment的實例。
  (d)提交事務,調用commit方法提交。
xml中的代碼為

<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.ydsciernce.studytest.MainActivity">
    <FrameLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/content_fragment"/>
</RelativeLayout>

Activity中的代碼為

public class MainActivity extends AppCompatActivity implements FragementOne.FOneListener{
    FragmentTwo mFragmentTwo;
    FragementOne mFragmentOne;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        if (savedInstanceState == null){
            Log.i("TAG","saveInstanece數據為空");
            FragmentManager manager = getSupportFragmentManager();
            FragmentTransaction transaction = manager.beginTransaction();
            mFragmentOne = new FragementOne();
            transaction.add(R.id.content_fragment,mFragmentOne,"ONE");
            transaction.commit();
        }else {
            Log.i("TAG","saveInstanece數據為"+savedInstanceState.toString());
        }
    }
    @Override
    public void onOneClick() {
        if (mFragmentTwo == null){
            mFragmentTwo =  new FragmentTwo();
        }
        FragmentManager manager = getSupportFragmentManager();
        FragmentTransaction transaction = manager.beginTransaction();
        //transaction.hide(mFragmentOne);
        //transaction.add(R.id.content_fragment,mFragmentTwo,"TWO");
        transaction.replace(R.id.content_fragment,mFragmentTwo,"TWO");
        transaction.addToBackStack(null);
        transaction.commit();
    }
}

FragmentOne的代碼為

public class FragementOne extends Fragment implements View.OnClickListener{

    private Button mButton;
    EditText test;
    public interface FOneListener{
        void onOneClick();
    }
    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) {
        Log.i("TAG"," on createview");
        View view = inflater.inflate(R.layout.content_one_fragment,null);
        mButton = (Button) view.findViewById(R.id.buttonOne);
        mButton.setOnClickListener(this);
        test = (EditText) view.findViewById(R.id.editText);
        Log.i("TAG","edit datda"+test.getText().toString());
        return view;
    }
     @Override
    public void onClick(View v) {
        if(getActivity() instanceof FOneListener){
            ((FOneListener)getActivity()).onOneClick();
        }
    }
}

注意事項:

a.在設置默認的fragment時,不能調用addToBackStack(null)方法,如果添加了在退出應用時會在Activity頁面出現一個空白頁面。
  b.在代碼中有兩個Fragment,分別為FrangmentOne和FragmentTwo,FragmentOne為默認的,從FragmentOne中的Button 去啟動FragmentTwo,在鴻洋大神的分析中當我們從FragmentOne啟動到FragmentTwo時使用的是replace方法,replace方法的實現過程是remove方法和add方法的合體,當我們在調用該方法時,如果不添加事務到回退棧,前一個Fragment實例會被銷毀,調用了addToBackStack(null);將當前的事務添加到了回退棧,所以FragmentOne實例不會被銷毀,但是視圖層次依然會被銷毀,即會調用onDestoryView和onCreateView,在這種情況下,再次返回到FragmentOne時等于新建了一個FragmentOne實例對象,在之前Fragment中保存的數據將不會存在,而在真實的案例中當我們從FragmentTwo返回到FragmentOne時希望數據還在,因此此時就不能使用replace方法,使用hide方法將FragmentOne隱藏起來,當FragmengTwo返回時會調用show方法顯示,相應的數據也會被保存。
  c.當fragment遇到屏幕自動旋轉時,會導致Activity和Fragment的重建在這種情況下可能會導致兩個FragmentOne的實例對象存在,界面上也會存在重疊效果,導致這種現象的原因是當Activity重建時我們的fragment會被保存下來,但是會創建新的FragmentManager,新的FragmentManager會首先會去獲取保存下來的fragment隊列,重建fragment隊列,從而恢復之前的狀態。解決方法是在創建實例和獲取FragmentManager時判斷saveInstanceState狀態,當我們第一次啟動Activity時,saveInstanceState為空的,當因異常情況導致Activity重建時,自動會調用saveInstanceState會保存一些信息,因此通過判斷saveInstanceState狀態可以避免這種情況。
  d.在參考了大神的博客后自己嘗試技能滿足保存數據又可以避免在屏幕旋轉后避免創建多個Fragment實例對象,實現方法為創建實例前對saveInstanceState狀態進行判斷,同時在啟動其他的Fragment時不調用replace方法使用hide方法,但是出現nullPointerException,目前還沒解決。

(3)Activity與Fragment以及Fragment與Fragment之間的通信。

a.Activity與Fragment

實現方式有以下幾種
    ①.handler通信
    ②.接口回調 例如上面代碼中在FragmentTwo 實現方式,在
     FragmentTwo中的點擊事件通過接口回調交給Activity去處理。

聲明接口
public interface FOneListener{
        void onOneClick();
    }
點擊事件傳遞
 public void onClick(View v) {
        if(getActivity() instanceof FOneListener){
            ((FOneListener)getActivity()).onOneClick();
        }
    }
父類繼承去實現
public class MainActivity extends AppCompatActivity implements FragementOne.FOneListener
@Override
public void onOneClick() {
    //處理點擊事件
}

③.使用EventBus去實現。
   ④.使用廣播BroadcastReceiver去實現。

b.同時存在同一個Activity中的頁面中的兩個Fragment之間的通信

在查看郭大神的博客后發現這種情況適用于存在于同一個頁面之間FragmentA 去獲取FragmentB(或者FragmentB 去獲取FragmentA)中某個組件的信息。主要都是通過getActivity這個方法實現的,getActivity方法可以讓Fragment獲取到關聯的Activity,然后再調用Activity的findViewById方法,就可以獲取到和這個Activity關聯的其它Fragment的視圖,從而可以獲取這個視圖的數據。

 @Override  
    public void onActivityCreated(Bundle savedInstanceState) {  
        super.onActivityCreated(savedInstanceState);  
        Button button = (Button) getActivity().findViewById(R.id.button);  
        button.setOnClickListener(new OnClickListener() {  
            @Override  
            public void onClick(View v) {  
                TextView textView = (TextView) getActivity().findViewById(R.id.fragment1_text);  
                Toast.makeText(getActivity(), textView.getText(), Toast.LENGTH_LONG).show();  
            }  
        });  
    }  

(4)Fragment的復用以及與Activity之間的解耦

在我們項目想法中肯定會經常遇到ViewPager與Fragment之間的結合使用,使用Viewpager來切換不同的fragment,當第一次使用時可能會針對每一個主題都會創建一個Fragment去實現,這種實現方式在網上有很多案例,但是這種實現方式創建了很多的fragment,代碼有太多的耦合性,自從Google官網給出了Tablayout這個組件時,它也是結合fragmen和viewpager去實現的。在這個具體實現時很好的復用了fragment。具體實現見代碼吧,口頭敘述態度都是扯淡,只有代碼才是王道。

布局代碼(content_history_record.xml)
<LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:layout_centerInParent="true">
    <android.support.design.widget.TabLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:id="@+id/tabLayout"
            app:tabBackground="@color/historyColorAccent"
            app:tabSelectedTextColor="@color/tabSelected"
            app:tabTextColor="@color/tabUnSelected"
            app:tabMode="scrollable"/>
        <android.support.v4.view.ViewPager
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="1"
            android:background="@color/label"
            android:id="@+id/viewpager_history"
            />
 </LinearLayout>
MainActivity的代碼
public class HistoryRecordActivity extends AppCompatActivity{
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.content_history_record);
       init();
    }
    private void init(){
        HistoryFragmentPreferenceAdapter adapter = new HistoryFragmentPreferenceAdapter(getSupportFragmentManager(),this);
        ViewPager historyPager = (ViewPager) findViewById(R.id.viewpager_history);
        historyPager.setAdapter(adapter);
        TabLayout historyTabLayout = (TabLayout) findViewById(R.id.tabLayout);
        historyTabLayout.setupWithViewPager(historyPager);
        historyTabLayout.setTabGravity(TabLayout.GRAVITY_FILL);
        historyTabLayout.setTabMode(TabLayout.MODE_FIXED);
    }
}
適配器的代碼(HistoryFragmentPreferenceAdapter.java)
public class HistoryFragmentPreferenceAdapter extends FragmentPagerAdapter {
    private Context mContext;
    private final int coutnt = 5;
    private String [] titles ;
    public HistoryFragmentPreferenceAdapter(FragmentManager fm, Context context) {
        super(fm);
        this.mContext = context;
        titles = context.getResources().getStringArray(R.array.history_title);
    }
    @Override
    public Fragment getItem(int position) {
        return PageFragment.getIntance(position+1);
    }
    @Override
    public int getCount() {
        return coutnt;
    }
    @Override
    public CharSequence getPageTitle(int position) {

        return titles[position];
    }
}
Fragment的代碼(PageFragment.java)
public class PageFragment extends Fragment {
    public static final String TRANSFER_PAGE = "page";
    private int mPage;
    public static Fragment getIntance(int page){
        Bundle bundle = new Bundle();
        bundle.putInt(TRANSFER_PAGE,page);
        PageFragment pageFragment = new PageFragment();
        pageFragment.setArguments(bundle);
        return  pageFragment;
    }
    public void onCreate(Bundle savedInstanceState)  
    {  
        super.onCreate(savedInstanceState); 
        Bundle bundle = getArguments();  
        if (bundle != null)  
            mArgument = bundle.getString(TRANSFER_PAGE);  
    }  

給Fragment添加newInstance方法,將需要的參數傳入,設置到bundle中,然后setArguments(bundle),最后在onCreate中進行獲取通過getArguments()去獲取一個fragment的實例,通過這種方式可以實現Fragment的復用。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,182評論 6 543
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,489評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,290評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,776評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,510評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,866評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,860評論 3 447
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,036評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,585評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,331評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,536評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,058評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,754評論 3 349
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,154評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,469評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,273評論 3 399
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,505評論 2 379

推薦閱讀更多精彩內容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,734評論 25 708
  • Fragment概述 Fragment是Activity中用戶界面的一個行為或者說是一部分。主要是支持大屏幕上動態...
    wangling90閱讀 11,573評論 5 75
  • 前言 Fragment想必大家不陌生吧,在日常開發中,對于Fragment的使用也很頻繁,現在主流的APP中,基本...
    斜杠時光閱讀 2,590評論 4 22
  • 作品簡介: 魏曉天高中開學沒多久喜歡上了校廣播站的學姐江欣怡,江欣怡溫柔大方,時常和他發信息并且一起見面。那時的他...
    溫玉言閱讀 591評論 2 2
  • 如果用一首歌記錄2015,我想會是SkeeterDavis的《the end of the world》,因為這是...
    孟繁錦閱讀 413評論 0 1