Fragment可以在布局中直接使用
android:name属性或者使用
class属性来指定对应的
Fragment实现。
activity_fragment_static.xml布局文件
在
Activity中就直接使用布局就可以。
public class FragmentTestActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_fragment_static);//直接使用布局就好
}
}
二、Fragment的动态使用
Fragment除了在xml中使用
Fragment外,还可以直接通过代码的形式来动态添加
Fragment到xml布局中。
动态添加
Fragment到xml中,需要借助
FrameLayout布局,具体实现方式,看下面代码。
activity_fragment_dynamic.xml布局文件
<framelayout android:id="@+id/content_dynamic_fragment" android:layout_height="200dp" android:layout_width="match_parent">
</framelayout>
FragmentTestActivity中动态使用
Fragment替换
FrameLayout。
public class FragmentTestActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_fragment_dynamic);
dynamicAddFragment();
}
/**
* 动态的使用Fragment
*/
private void dynamicAddFragment() {
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction transaction = fragmentManager.beginTransaction();
// 使用LiftCycleFragment替换指定的 id 的 View
transaction.replace(R.id.content_dynamic_fragment, new DynamicFragment());
transaction.commit();
}
}
三、Fragment的生命周期
Fragment是依附于Activity的,所以生命周期和
Activity很多是保持一致的。当然也有一些不同的地方,让我们来看看吧。
Fragment的生命周期图:
Fragment的生命周期和Activity的生命周期对比图
对于对象的创建和销毁问题,最好保持在2个相对应的生命周期中。
四、Fragment && FragmentManager && FragmentTransaction 常用API介绍
Fragment的API介绍:
// 通过bundle传递数据,后面会将用法
setArguments(Bundle bundle);
getArguments();
// 判断Fragment状态
isAdded();
isDetached();
isVisible();
isHidden();
isInLayout();
isResumed();
isRemoving();
// 获取Fragment的标记和id
getId();
getTag();
//API 15
getUserVisibleHint();
setUserVisibleHint(true);
// API 17
getChildFragmentManager();
getParentFragment();
除了上述方法,还有Activity中的一些方法的封装和动画相关的方法。
例如关于MenuItem,Permission,动画等,这里列举几个。如:
MenuItem相关:
setHasOptionsMenu(boolean b);
onCreateOptionsMenu(Menu menu, MenuInflater inflater);
onOptionsItemSelected(MenuItem item);
Permission相关:
requestPermissions(String[] permissions, int requestCode);
onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults);
shouldShowRequestPermissionRationale(String permission);
动画相关:API 21
setEnterTransition(Transition transition);
setExitTransition(Transition transition);
setAllowEnterTransitionOverlap(boolean allow);
setAllowReturnTransitionOverlap(boolean allow);
FragmentManager介绍:
getFragmentManager();// 获取FragmentManager方法
findFragmentById();// 通过id获取对应的Fragment
findFragmentByTag();// 通过Tag获取对应的Fragment
beginTransaction();// 开启事务,返回FragmentTransaction对象
popBackStack();// 退出栈顶的Fragment
//退出指定id的Fragment
popBackStack(int id , int flag);// flag: 0 or FragmentManager.POP_BACK_STACK_INCLUSIVE
popBackStack(String tag , int flag);//退出指定Tag的Fragment
popBackStackImmediate();// 返回一个boolean值
popBackStackImmediate(int id , int flag);
popBackStackImmediate(String tag , int flag);
getBackStackEntryCount();// 获取返回栈中的数量
addOnBackStackChangedListener(); // 添加返回栈改变的监听
removeOnBackStackChangedListener();// 移除返回栈的监听
isDestroyed();// API 17 是否Activity走了OnDestory()生命周期方法
FragmentTransaction介绍:
FragmentTransaction是一个抽象类,具体的是现实类是
BackStackRecord。
常用API:
// 添加
add(Fragment fragment, String tag);
add(int containerViewId, Fragment fragment);
add(int containerViewId, Fragment fragment,String tag);
// 替换,相当于remove之后再add
replace(int containerViewId, Fragment fragment);
replace(int containerViewId, Fragment fragment,String tag);
// 移除
remove(Fragment fragment);
// 显示
show(Fragment fragment);
//隐藏
hide(Fragment fragment);
//依附
attach(Fragment fragment);
//分离
detach(Fragment fragment);
isEmpty();
addToBackStack(String name);// 添加到任务栈,参name:null或者一个标记tag
// 提交事务 API的具体差异,看源码解释
commit();
commitAllowingStateLoss();// 这是危险的,因为如果活动需要稍后从其状态恢复,则提交可能丢失
commitNow();
commitNowAllowingStateLoss();
五、Fragment的通信
Fragment常常会和
Activity或
Fragment会有数据传递,那么如何实现呢
实现方式肯定有多种,就举例说下
setArguments(Bundle bundle)的方式传递消息:
public class ArgumentFragment extends Fragment {
private String message;
/**
* 这种写法就是为了Activity或Fragment等向当前的Fragment传递消息
*/
public static ArgumentFragment getInstance(String message) {
//通过Bundle传递消息
Bundle bundle = new Bundle();
bundle.putString("message", message);
ArgumentFragment fragment = new ArgumentFragment();
fragment.setArguments(bundle);
return fragment;
}
@Override
public void onAttach(Context context) {
super.onAttach(context);
//获取bundle传递的消息
Bundle bundle = getArguments();
if (bundle != null) {
message = bundle.getString("message");
}
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_lift_cycle, container, false);
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
TextView textView = (TextView) view.findViewById(R.id.fragmnet_content_text);
if (!TextUtils.isEmpty(message)) {
textView.setText("ArgumentFragment message: "+message);
} else {
textView.setText("ArgumentFragment message is none");
}
}
}
在
Activity中的调用:
public class FragmentTestActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_fragment);
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction transaction = fragmentManager.beginTransaction();
// 建议使用(不要直接new对象),这样可以传递信息给Fragment
transaction.replace(R.id.content_dynamic_fragment, ArgumentFragment.getInstance("Argument"));
transaction.commit();
}
}
六、Fragment的回退栈
添加到Fragment返回栈是通过
transaction.addToBackStack(String name)方法,按返回键是,会从栈中一个个的退出。如果需要主动退出栈,可以调用
fragmentManager.popBackStack()退出返回栈。具体我们看代码:
public class FragmentTestActivity extends Activity {
String[] tags = {"One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine", "Ten"};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_fragment);
createFragment(0, false);
}
private void createFragment(final int i, boolean addBackStace) {
if (i >= tags.length) {
return;
}
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction transaction = fragmentManager.beginTransaction();
BackStackFragment fragment = BackStackFragment.getInstance(tags[i]);
fragment.setFragmentClickListener(new FragmentClickListener() {
@Override
public void onFragmentClick() {
createFragment(i + 1, true);
}
});
transaction.replace(R.id.content_dynamic_fragment, fragment, tags[i]);
if (addBackStace) {
transaction.addToBackStack(tags[i]);
}
transaction.commit();
}
@Override
protected void onResume() {
super.onResume();
computeClearBackStack(false);
}
@Override
protected void onPause() {
super.onPause();
computeClearBackStack(true);
}
private void computeClearBackStack(boolean clean) {
FragmentManager fragmentManager = getFragmentManager();
int backStackEntryCount = fragmentManager.getBackStackEntryCount();
Log.e("FragmentTestActivity", "onPause--> backStackEntryCount: " + backStackEntryCount);
for (int i = 0; i < backStackEntryCount; i++) {
FragmentManager.BackStackEntry backStackEntryAt = fragmentManager.getBackStackEntryAt(i);
String name = backStackEntryAt.getName();
Log.e("FragmentTestActivity", "onPause--> name: " + name);
if (clean) {
fragmentManager.popBackStack(name, FragmentManager.POP_BACK_STACK_INCLUSIVE);
}
}
}
}
BackStackFragment
public class BackStackFragment extends Fragment {
private String message;
private FragmentClickListener listener;
public void setFragmentClickListener(FragmentClickListener listener) {
this.listener = listener;
}
public static BackStackFragment getInstance(String message) {
//通过Bundle传递消息
Bundle bundle = new Bundle();
bundle.putString("message", message);
BackStackFragment fragment = new BackStackFragment();
fragment.setArguments(bundle);
return fragment;
}
@Override
public void onAttach(Context context) {
super.onAttach(context);
//获取bundle传递的消息
Bundle bundle = getArguments();
if (bundle != null) {
message = bundle.getString("message");
}
if (message == null) {
message = "";
}
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_content, container, false);
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
TextView textView = (TextView) view.findViewById(R.id.fragmnet_content_text);
if (!TextUtils.isEmpty(message)) {
textView.setText(message + " Fragment");
} else {
textView.setText("Fragment");
}
textView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (listener != null) {
listener.onFragmentClick();
}
}
});
}
}
具体效果如图:
七、Fragment懒加载方案
在
Fragment和
ViewPager结合使用时,
ViewPager会预加载下一页的内容,导致浪费用户的流量,所以需要通过懒加载的方式优化。当
Fragment的界面显示是,再去加载数据,具体实现如下:
LazyFragment
public abstract class LazyFragment extends Fragment {
protected boolean isVisible;
/**
* 在这里实现Fragment数据的缓加载.
*/
@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
if (getUserVisibleHint()) {
isVisible = true;
onVisible();
} else {
isVisible = false;
onInvisible();
}
}
protected void onVisible() {
lazyLoad();
}
protected abstract void lazyLoad();
protected void onInvisible() {
}
}
MyLazyFragment实现
public class MyLazyFragment extends LazyFragment {
private String message;
// 标志位,标志已经初始化完成。
private boolean isPrepared;
public static MyLazyFragment getInstance(String message) {
Bundle bundle = new Bundle();
bundle.putString("message", message);
MyLazyFragment firstFragment = new MyLazyFragment();
firstFragment.setArguments(bundle);
return firstFragment;
}
@Override
public void onAttach(Context context) {
super.onAttach(context);
Bundle bundle = getArguments();
if (bundle != null) {
message = bundle.getString("message");
}
if (message == null) {
message = "";
}
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_content, container, false);
// view.findViewById() 操作获取布局中的View对象
isPrepared = true;
lazyLoad();
return view;
}
@Override
protected void lazyLoad() {
if (!isPrepared || !isVisible) {
return;
}
//获取数据,填充控件
}
}
八、Fragment常见的异常和解决方案
前面讲的内容都是比较基础的知识,关于Fragment常见的异常和解决方案,可以参考下面的博客,总结的很好。
九、DialogFragment创建视图介绍
DialogFragment是
Fragment的子类,同时具有
Dialog的特性,Google官方推荐使用,替代
AlertDialog。
DialogFragment的使用和
Fragment是一样的,这里不做解释。这里讲讲
DialogFragment 创建一个视图的2种方式。
通过onCreateDialog()方法,创建Dialog的视图
public class AlertDiaolgFragment extends DialogFragment {
public static void showDialog(FragmentManager manager) {
FragmentTransaction transaction = manager.beginTransaction();
transaction.addToBackStack("Alert");
AlertDiaolgFragment diaolgFragment = new AlertDiaolgFragment();
diaolgFragment.show(transaction, "Alert");
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
View view = LayoutInflater.from(getActivity()).inflate(R.layout.dialog, null);
return new AlertDialog.Builder(getActivity())
.setTitle("Dialog")
.setMessage("今天星期五")
.setView(view)
.setPositiveButton("OK", null)
.setNegativeButton("Cancel", null)
.create();
}
}
通过onCreateView()方法,直接加载视图,这里的用法就完全是Fragment的用法
public class MyDialogFragment extends DialogFragment {
public static void showDialog(FragmentManager manager) {
FragmentTransaction transaction = manager.beginTransaction();
transaction.addToBackStack("My");
AlertDiaolgFragment diaolgFragment = new AlertDiaolgFragment();
diaolgFragment.show(transaction, "My");
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) {
return LayoutInflater.from(getActivity()).inflate(R.layout.dialog, container,false);
}
}
十、DialogFragment调用show()方法导致Can not perform this action after onSaveInstanceState异常的解决方案
在使用
DialogFragment的时候,偶尔会遇到如下异常,在
Activity的生命周期方法走了
onSaveInstanceState()方法后,在调用
DialogFragment的
show()方法,导致异常:
Can not perform this action after onSaveInstanceState。
关于
Can not perform this action after onSaveInstanceState异常问题,我们的处理方式是:确保是在
Activity或
Fragment的处于
onResume()状态调用。在
Fragment中有
isResume()方法,通过判断该方法,是否显示
Fragment。在
Activity中,通过在
onResume()和
onPause()设置变量量控制。
以上面的
MyDialogFragment为例,如:
在Fragment中,需要显示MyDialogFragment的视图调用
if(isResume()){
MyDialogFragment.showDialog(getFragmentManager);
}
在Activity中,需要显示MyDialogFragment的视图调用
private boolean mState;
if(mState){
MyDialogFragment.showDialog(getFragmentManager);
}
@Override
protected void onResume() {
super.onResume();
mState = true;
}
@Override
protected void onPause() {
super.onPause();
mState = false;
}