类似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