类似Actrivity的任务站,Activity也可以为Fragment的每一次事务维护一个回退栈。当我们将fragment的事物添加到回退栈后,当点击回退键时,将会返回到前一次添加的Fragment。当所有被添加的Fragment都被弹出后,再次点击后退键则推出当前ACTIVITY.

 

下面结合一个简单的例子来讲解一下Fragment的回退栈到底是怎么一会事。

这个例子里面有三个fragment,FirstFragment 、SecondFragment 、ThirdFragment,在跳转的时候我们会将前一个Fragment放入回退栈。

FirstFragment 中有一个按钮跳转到SecondFragment,还有一个checkBox, 此checkBox用来验证回退的时候是否重建UI



SecondFragment中有一个按钮跳转到ThirdFragment,还有一个EditText用来验证回退的时候是否重建UI

 

我们运行到手机后,首先选上checkBox,然后点击First fragment按钮 此时会切换到 SecondFragment

,我们在SecondFragment的输入框中输入一些内容例如:hello ,然后点击second fragment按钮,我们会切换到ThirdFragment,此时我们的回退栈中就有两个Fragment,此时我们按返回键此时我们有会切换回SecondFragment,并且发现其输入框中输的内容hello还在,然后在按返回键,此时我们会切换到FirstFragment,但是checkBox并未选上。这是什么原因呢?这是应为我们在切换Fragment的时候用了不同的切换方式。

从FirstFragment切换到SecondFragment,我们直接用了replace方法,此方法的实质是先remove(),再add(),remove()会将Fragment的UI视图销毁,所以在回退时,就会重新创建视图,重新调用onCreateView()方法。

而从SecondFragment切换到ThirdFragment,我们只是将SecondFragment进行了hide(),hide()只是将视图不可见,UI视图并没有销毁,所以回退时不会重走onCreateView()方法。

 

下面看源代码;

 

FirstFragment:

package com.example.liaoli.fragmentdemo.fragment;

        import android.app.Activity;
        import android.app.FragmentTransaction;
        import android.net.Uri;
        import android.os.Bundle;
        import android.app.Fragment;
        import android.view.LayoutInflater;
        import android.view.View;
        import android.view.ViewGroup;
        import android.widget.Button;

        import com.example.liaoli.fragmentdemo.R;


public class FirstFragment extends Fragment {

    private SecondFragment secondFragment;

    public static FirstFragment newInstance(String param1, String param2) {
        FirstFragment fragment = new FirstFragment();
        return fragment;
    }

    public FirstFragment() {

    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        View v = inflater.inflate(R.layout.fragment_first, container, false);

        Button bt = (Button) v.findViewById(R.id.bt);

        bt.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                secondFragment =new SecondFragment();

                FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction();

                //此处实质是先remove再add,所以FirstFragment的UI视图会销毁,回退时会重新创建视图重走onCreateView方法,
                fragmentTransaction.replace(R.id.fragment_layout,secondFragment,"two");
                //将FirstFragment放入回退栈
                fragmentTransaction.addToBackStack(null);

                fragmentTransaction.commit();
            }
        });

        return v;

    }


}

 

fragment_first.xml

<FrameLayout 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:background="#ff5a81"
    tools:context="com.example.liaoli.fragmentdemo.fragment.FirstFragment">



    <Button
        android:id="@+id/bt"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:text="@string/hello_blank_fragment" />

    <CheckBox
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

</FrameLayout>

 

SecondFragment

package com.example.liaoli.fragmentdemo.fragment;

import android.app.Activity;
import android.app.FragmentTransaction;
import android.net.Uri;
import android.os.Bundle;
import android.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;

import com.example.liaoli.fragmentdemo.R;

public class SecondFragment extends Fragment {
    private ThirdFragment thirdFragment;

    public static SecondFragment newInstance(String param1, String param2) {
        SecondFragment fragment = new SecondFragment();
        return fragment;
    }

    public SecondFragment() {
        // Required empty public constructor
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        View v =  inflater.inflate(R.layout.fragment_second, container, false);


        Button bt = (Button) v.findViewById(R.id.bt);

        bt.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction();

                thirdFragment =new ThirdFragment();

                //fragmentTransaction.replace(R.id.fragment_layout,secondFragment);
                //此处是隐藏了SecondFragment,所以SecondFragment的UI视图不会销毁,只是不可见了,回退时不会重走onCreateView方法
                fragmentTransaction.hide(SecondFragment.this);

                //
                fragmentTransaction.add(R.id.fragment_layout,thirdFragment,"three");

                //将SecondFragment放入回退栈
                fragmentTransaction.addToBackStack(null);

                fragmentTransaction.commit();
            }
        });

        return v;
    }

}

fragment_second.xml

<FrameLayout 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:background="#67ff79"
    tools:context="com.example.liaoli.fragmentdemo.fragment.SecondFragment">

    <EditText
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

    <Button
        android:id="@+id/bt"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"

        android:layout_gravity="center"
        android:text="second fragment" />

</FrameLayout>

 

ThirdFragment

package com.example.liaoli.fragmentdemo.fragment;

import android.app.Activity;
import android.app.FragmentTransaction;
import android.net.Uri;
import android.os.Bundle;
import android.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.Toast;

import com.example.liaoli.fragmentdemo.R;

public class ThirdFragmentextends Fragment {
    public static ThirdFragmentnewInstance(String param1, String param2) {
        ThirdFragment fragment = new ThirdFragment();
        return fragment;
    }

    public ThirdFragment() {
        // Required empty public constructor
    }


    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        View v = inflater.inflate(R.layout.fragment_third, container, false);

        Button bt = (Button) v.findViewById(R.id.bt);

        bt.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                Toast.makeText(getActivity(),"fragment3 is clicked ",Toast.LENGTH_SHORT).show();

            }
        });

        return v;
    }


}

fragment_third.xml

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:background="#5579ff"
    android:layout_height="match_parent"
    tools:context="com.example.liaoli.fragmentdemo.fragment.ThirdFragment">

    <!-- TODO: Update blank fragment layout -->
    <Button
        android:id="@+id/bt"
        android:layout_width="wrap_content"
        android:layout_gravity="center"
        android:layout_height="wrap_content"
        android:text="third fragment" />

</FrameLayout>

 

FragmentBackStackActivity

package com.example.liaoli.fragmentdemo;

import android.app.Activity;
import android.app.Fragment;
import android.app.FragmentManager;
import android.app.FragmentTransaction;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;

import com.example.liaoli.fragmentdemo.fragment.FirstFragment;

public class FragmentBackStackActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_fragment_back_stack);

        FragmentManager fragmentManager = getFragmentManager();
        FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();

        fragmentTransaction.add(R.id.fragment_layout,new FirstFragment(),"one");

        fragmentTransaction.commit();

    }


}

activity_fragment_back_stack.xml

<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"
    tools:context="com.example.liaoli.fragmentdemo.FragmentBackStackActivity">

    <FrameLayout
        android:id="@+id/fragment_layout"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</RelativeLayout>

 

2.fragment与Activity

fragment中可以通过getActivity()方法得到当前Activity的实例,然后通过此实例进行一系列操作。

如果Activity有Fragment的实例引用,可以同过此引用直接针对此Fragment实例进行一系列操作。

Activity中还可以通过getFragmentManager.findFragmentByTag()或者findFragmentById()获得任何Fragment实例的引用,然后通过引用去进行一系列操作

如果在Fragment中要使用Context的话,可以直接使用getActivity(),如果要求在Activity销毁后,Context还能使用的话,则可以通过getActivity().getApplicationContext()获取。

 

通过回调的方式进行通信,这也是比较推荐的一种方式。这种方式可以降低Activity和Fragment的耦合,同时Fragment中也不应该直接处理其他的Fragment,因为这样会耦合性会剧增,而应该都交给Fragment的维护者来处理。和接下来我们对上面的简单例子进行重构。

FirstFragment_Optimization的源码(fragment_first.xml与上面的例子一样)

package com.example.liaoli.fragmentdemo.fragment;

import android.app.Activity;
import android.app.Fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;

import com.example.liaoli.fragmentdemo.R;


public class FirstFragment_Optimization extends Fragment implements  View.OnClickListener{

   //回调接口
   public  interface PerformFirstFragmentClick{
        void PerFormFirstFragmentClick(View view);
    }

    public static FirstFragment_Optimization newInstance(String param1, String param2) {
        FirstFragment_Optimization fragment = new FirstFragment_Optimization();
        return fragment;
    }

    public FirstFragment_Optimization() {

    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        View v = inflater.inflate(R.layout.fragment_first, container, false);

        Button bt = (Button) v.findViewById(R.id.bt);

        bt.setOnClickListener(this);

        return v;

    }


    @Override
    public void onClick(View v) {

        Activity activity = getActivity();

        if(activity instanceof PerformFirstFragmentClick ){
            ((PerformFirstFragmentClick)activity).PerFormFirstFragmentClick(v);
        }


    }
}

 

SecondFragment_Optimization (fragment_second.xml与上面的例子一样)

package com.example.liaoli.fragmentdemo.fragment;

import android.app.Fragment;
import android.app.FragmentTransaction;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;

import com.example.liaoli.fragmentdemo.R;

public class SecondFragment_Optimization extends Fragment implements  View.OnClickListener{
    private ThirdFragment thirdFragment;

    private PerformSecondFragmentClick performSecondFragmentClick;

    @Override
    public void onClick(View v) {

        performSecondFragmentClick.performSecondFragmentClick(v);
    }

    public interface  PerformSecondFragmentClick{
        void performSecondFragmentClick(View view);
    }


    public void setPerformSecondFragmentClick(PerformSecondFragmentClick performSecondFragmentClick) {
        this.performSecondFragmentClick = performSecondFragmentClick;
    }

    public static SecondFragment_Optimization newInstance(String param1, String param2) {
        SecondFragment_Optimization fragment = new SecondFragment_Optimization();
        return fragment;
    }

    public SecondFragment_Optimization() {
        // Required empty public constructor
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        View v =  inflater.inflate(R.layout.fragment_second, container, false);

        Button bt = (Button) v.findViewById(R.id.bt);

        bt.setOnClickListener(this);

        return v;
    }

}

 

OptimizationFragmentBackStackActivity(activity_fragment_back_stack.xml与上面例子一样)

package com.example.liaoli.fragmentdemo;

import android.app.Activity;
import android.app.FragmentManager;
import android.app.FragmentTransaction;
import android.os.Bundle;
import android.view.View;

import com.example.liaoli.fragmentdemo.fragment.FirstFragment_Optimization;
import com.example.liaoli.fragmentdemo.fragment.SecondFragment_Optimization;
import com.example.liaoli.fragmentdemo.fragment.ThirdFragment;

public class OptimizationFragmentBackStackActivity extends Activity implements FirstFragment_Optimization.PerformFirstFragmentClick ,SecondFragment_Optimization.PerformSecondFragmentClick{

    private SecondFragment_Optimization secondFragment;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_fragment_back_stack);

        FragmentManager fragmentManager = getFragmentManager();
        FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();

        fragmentTransaction.add(R.id.fragment_layout,new FirstFragment_Optimization(),"one");

        fragmentTransaction.commit();

    }


    /**
     * FirstFragment_Optimization中的所有View的点击事件都在此处理
     * @param view
     */
    @Override
    public void PerFormFirstFragmentClick(View view) {

        if (secondFragment == null) {
            secondFragment =new SecondFragment_Optimization();
            secondFragment.setPerformSecondFragmentClick(this);
        }

        FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction();

        fragmentTransaction.replace(R.id.fragment_layout, secondFragment, "two");
        fragmentTransaction.addToBackStack(null);

        fragmentTransaction.commit();
    }


    /**
     * SecondFragment_Optimization中的所有View的点击事件都在此处理
     * @param view
     */
    @Override
    public void performSecondFragmentClick(View view) {

        FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction();

        ThirdFragment thirdFragment = new ThirdFragment();

        //fragmentTransaction.replace(R.id.fragment_layout,secondFragment);
        fragmentTransaction.hide(secondFragment);

        fragmentTransaction.add(R.id.fragment_layout, thirdFragment, "three");

        fragmentTransaction.addToBackStack(null);

        fragmentTransaction.commit();
    }
}

可以发现FirstFragment_Optimization、 SecondFragment_Optimization不和任何Activity、Fragm耦合,可以被任意的Activity使用,

FirstFragment_Optimization中我们定义了一个借口,只要Activity实现了此接口,就可以处理FirstFragment_Optimization中的所有的Viewde 点击事件。

SecondFragment_Optimization与FirstFragment_Optimization其实是类似的,只不过多了一个

public void setPerformSecondFragmentClick(PerformSecondFragmentClick performSecondFragmentClick) {
    this.performSecondFragmentClick = performSecondFragmentClick;
}

方法。由于多了此方法,所以在Activity中我们必须手动给我们的SecondFragment_Optimization设置一个PerformSecondFragmentClick的实例。

if (secondFragment == null) {
    secondFragment =new SecondFragment_Optimization();
    secondFragment.setPerformSecondFragmentClick(this);
}

代码实现的效果与上面的例子是一模一样的,FirstFragment_Optimization和SecondFragment_Optimization中两种设置回调的方法都是可以的,并且是推荐的。我们可以根据自己的喜好来选择。

 

虽然Fragment可以通过getActivity()、findFragmentByTag或findFragmentById进行任何可行的操作,甚至在Fragment里面操作Fragment,但是如果没有特殊需求一般绝对不提倡。Activity担任的是Fragment的维护管理者的角色。所以应当有Activity来统一管理Fragment的操作。另外虽然Fragment不能相应Intent的打开,但是Activity可以。Activity接收Intent后,可以根据不同的参数,去决定显示哪一个Fragment。

源码下载链接: http://pan.baidu.com/s/1mgjbJFa 密码: h8yp