歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux編程 >> Linux編程 >> Android Fragment講解

Android Fragment講解

日期:2017/3/1 9:09:14   编辑:Linux編程

Fragment是依賴於Activity存在的,Fragment也有自己的生命周期,首先來看下Fragment的生命周期:

這是官網的圖,可以看到Fragment比activity多了幾個生命周期函數:
public void onAttach(Context context),當Fragment與Activity發生關聯時調用
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
創建fragment的視圖
public void onActivityCreated(Bundle savedInstanceState) 當Activity的onCreate方法返回時調用
public void onDestroyView() 當fragment的視圖被銷毀時調用
public void onDetach() 當fragment於Activity失去關聯時調用
生命周期就說到這裡,下面看下靜態的fragment怎麼用:

package com.fq.myapplication;


import Android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

/**
 * Created by Administrator on 2016/9/30.
 */
public class MyFragment extends Fragment {
    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        return inflater.inflate(R.layout.myfragment_layout,container,false);
    }
}

先定義一個MyFragment ,看下布局文件:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent"
    >
    <TextView
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:text="MyFragment1"
        android:textSize="20dp"
        android:gravity="center"/>
    <EditText
        android:layout_width="match_parent"
        android:layout_height="50dp" />
    <Button
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:textSize="20dp"
        android:text="next"/>
</LinearLayout>

然後是Activity的布局:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin">

  <fragment
      android:id="@+id/fragment"
      android:name="com.fq.myapplication.MyFragment"
      android:layout_width="match_parent"
      android:layout_height="match_parent"></fragment>
</RelativeLayout>

直接靜態寫在Activity的布局文件中即可,注意要寫id和name,否則會有問題,效果圖如下:

接下來看下動態Fragment怎麼玩,直接看代碼:

MyFragment fragment1 = new MyFragment();
FragmentManager fm = getFragmentManager();
FragmentTransaction fragmentTransaction = fm.beginTransaction();
fragmentTransaction.add(R.id.content, fragment1);
fragmentTransaction.commit();

getFragmentManager獲取到一個FragmentManager ,然後FragmentManager 調用beginTransaction開啟一個事務,保證原子操作,然後add,最後commit提交事物,除了add,還有其他幾個方法,這裡說明下:
fragmentTransaction.add 往activity中添加一個fragment
fragmentTransaction.remove 銷毀一個fragment
fragmentTransaction.replace 替換一個fragment,也就是先後執行remove和add操作
fragmentTransaction.hide 隱藏一個fragment,如果跳轉到另外一個fragment後,不希望當前的fragment被remove,那麼hide是絕佳選擇
fragmentTransaction.show,顯示一個fragment,接下來我們在fragment1 裡的按鈕點擊next的時候再新建一個fragment:

MyFragment2 fragment2 = new MyFragment2();
FragmentManager fm = getFragmentManager();
FragmentTransaction fragmentTransaction = fm.beginTransaction();
fragmentTransaction.hide(MyFragment.this);
fragmentTransaction.add(R.id.content,fragment2);
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();

注意這句fragmentTransaction.addToBackStack(null);,加入回退棧的意思,如果希望在點返回按鈕的時候,能夠類似activity一樣,返回到剛才的fragment,那麼就需要加入回退棧,否則點擊返回鍵,無法回到上一個fragment,而是全部銷毀了。

好,接下來說一個當年面試被問到的問題,當我們旋轉屏幕的時候,activity的生命周期重新執行,那麼fragment的生命周期也重新執行,比如現在在fragment2的界面,旋轉屏幕後,發現fragment1也出現了,怎麼解決這個問題呢,其實很簡單,在屏幕旋轉的時候或者資源不夠被殺的時候,Activity中的protected void onCreate(Bundle savedInstanceState)函數裡savedInstanceState會保存一些值,也就是不為null,所以解決這個問題的辦法,加入savedInstanceState為null判斷即可,如下:

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        if(savedInstanceState == null) {
            MyFragment fragment1 = new MyFragment();
            FragmentManager fm = getFragmentManager();
            FragmentTransaction fragmentTransaction = fm.beginTransaction();
            fragmentTransaction.add(R.id.content, fragment1);
            fragmentTransaction.commit();
        }
    }
}

接下來講下Activity向fragment數據傳遞,在activity裡獲取到fragment,然後調用fragment的setArguments方法進行傳遞,參數是Bundle,然後在Fragment通過getArguments獲取到剛才的Bundle,就可以得到傳遞的值了。

FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
MyFragment2 myFragment2 = new MyFragment2();
String argument = getIntent().getStringExtra(MyFragment.ARGUMENT);
Bundle bundle = new Bundle();
bundle.putString(MyFragment.ARGUMENT,argument);
myFragment2.setArguments(bundle);
fragmentTransaction.add(R.id.content2,myFragment2);
fragmentTransaction.commit();
Bundle bundle = getArguments();
        if(bundle != null){
            mArgument = bundle.getString(MyFragment.ARGUMENT);
            Intent intent = new Intent();
            intent.putExtra(MyFragment.RESPONSE,"From OhterActivity");
            getActivity().setResult(MyFragment.REQUEST,intent);
        }

這兩段代碼只關注我剛才說的點即可,其余代碼是用在另外一個場景,現在就說:
Fragment中可以類似activity一樣調用startActivityForResult來啟動另外一個Activity,並且有自己的onActivityResult函數,但是沒有setResult函數,其實也很好解決,用Activity的setResult即可,在Fragment中可以調用getActivity()得到當前的Activity,下面是這樣一個場景,在Fragment調用startActivityForResult啟動一個OtherActivity,然後在OtherActivity裡還有一個Fragment2,在Fragment2裡調用OtherActivity.setResult返回,最後fragment1中的回調onActivityResult執行,下面貼出關鍵代碼:

mButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(getActivity(),OtherActivity.class);
                intent.putExtra(ARGUMENT,"from MainActivity");
                startActivityForResult(intent,REQUEST);
            }
        });

在第一個Fragment中startActivityForResult啟動OtherActivity:

public class OtherActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main2);
        if(savedInstanceState == null){
            FragmentManager fragmentManager = getFragmentManager();
            FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
            MyFragment2 myFragment2 = new MyFragment2();
            String argument = getIntent().getStringExtra(MyFragment.ARGUMENT);
            Bundle bundle = new Bundle();
            bundle.putString(MyFragment.ARGUMENT,argument);
            myFragment2.setArguments(bundle);
            fragmentTransaction.add(R.id.content2,myFragment2);
            fragmentTransaction.commit();
        }
    }
}

在OtherActivity 中把得到的數據傳遞給MyFragment2 ,下面看MyFragment2的onCreate函數

 @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.e(TAG,"MyFragment2   onCreate");
        Bundle bundle = getArguments();
        if(bundle != null){
            mArgument = bundle.getString(MyFragment.ARGUMENT);
            Intent intent = new Intent();
            intent.putExtra(MyFragment.RESPONSE,"From OhterActivity");
            getActivity().setResult(MyFragment.REQUEST,intent);
        }
    }

調用getArguments得到傳遞的數據,然後getActivity().setResult返回,最後看下第一個fragment的onActivityResult:

@Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        Log.e(TAG,"MyFragment1  onActivityResult");
        Log.e(TAG,"requestCode = " + requestCode);
        if(requestCode == REQUEST){
            mTextView.setText(data.getStringExtra(RESPONSE));
        }
    }

完整過程結束。
下面說另外一個問題,剛才是啟動另外一個Activity,然後再跟另外一個Activity中的fragment進行數據傳遞,如果是一個Activity呢,fragment中用setTargetFragment和getTargetFragment進行數據傳遞,下面看例子代碼:

mButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                MyFragment2 fragment2 = new MyFragment2();

                FragmentManager fm = getFragmentManager();
                FragmentTransaction fragmentTransaction = fm.beginTransaction();
                fragment2.setTargetFragment(MyFragment.this,REQUEST);
                fragmentTransaction.hide(MyFragment.this);
                fragmentTransaction.add(R.id.content,fragment2);
                fragmentTransaction.addToBackStack(null);
                fragmentTransaction.commit();

            }
        });
        return view;

我們看到這裡多了一句fragment2.setTargetFragment(MyFragment.this,REQUEST);,然後看fragment2中的代碼:

 public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        Log.e(TAG,"MyFragment2  onCreateView");
        View view = inflater.inflate(R.layout.myfragment_layout2,container,false);
        Intent intent = new Intent();
        intent.putExtra(MyFragment.RESPONSE,"fragment回傳參數");
        getTargetFragment().onActivityResult(MyFragment.REQUEST, Activity.RESULT_OK,intent);
        return view;
    }

getTargetFragment得到剛才setTargetFragment的fragment,然後調用了fragment的onActivityResult方法進行數據回傳。
好了, Fragment就分析到這裡,寫的比較倉促,如有問題,歡迎指正,謝謝。

更多Android相關信息見Android 專題頁面 http://www.linuxidc.com/topicnews.aspx?tid=11

Copyright © Linux教程網 All Rights Reserved