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