View-Fragment
1.fragmentPagerAdapter和fragmentStatePagerAdapter的区别
都是继承PagerAdapter,viewpager的setAdapter()就可以传它们做参数。多一个state是将fragment彻底移除。
作用:通过传给它们一个FragmentManager,它就可以帮我们绑定和删除fragment。它们的的构造函数就是传一个fragmentManager,如果当前fragment的宿主是activity,那么它的fragmentManager就是getSupportFragmentManager(),如果宿主是fragment,那么它的fragmentManager就是getChildFragmentManager()。通常给viewpager做适配器。
它们的区别:fragmentPagerAdapter适合数据量小,在删除数据时只调用了detach()将fragment与宿主解绑,没有将fragment删除。
fragmentStatePagerAdapter适合数据量大,在绑定数据时有一个List来缓存fragment,但是在删除时则直接调用remove()将fragment删除,所以在滑动下一个fragment之后,它就会被彻底删除。
2.FragmentTransaction的replace、add、remove方法?
protected void initData() {
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
mHomeFragment = new HomeFragment();
fragmentTransaction.add(R.id.main_tab_fl, mHomeFragment);
fragmentTransaction.commit();
}
add:就是将fragment一层一层叠加到frameLayout。
public FragmentTransaction add(int containerViewId, Fragment fragment) {
doAddOp(containerViewId, fragment, null, OP_ADD);
return this;
}
private void doAddOp(int containerViewId, Fragment fragment, String tag, int opcmd) {
fragment.mFragmentManager = mManager;
// tag可以说是唯一标识我们可以通过它从FragmentManager中找到对应的Fragment
if (tag != null) {
if (fragment.mTag != null && !tag.equals(fragment.mTag)) {
throw new IllegalStateException("Can't change tag of fragment "
+ fragment + ": was " + fragment.mTag
+ " now " + tag);
}
fragment.mTag = tag;
}
if (containerViewId != 0) {
if (fragment.mFragmentId != 0 && fragment.mFragmentId != containerViewId) {
throw new IllegalStateException("Can't change container ID of fragment "
+ fragment + ": was " + fragment.mFragmentId
+ " now " + containerViewId);
}
// 把Fragment的ContainerId和FragmentId指定为我们传递过来的布局中的ViewGroup的id。
fragment.mContainerId = fragment.mFragmentId = containerViewId;
}
// 见名思意 Op是什么?就当是一些基本参数吧
Op op = new Op();
op.cmd = opcmd;
op.fragment = fragment;
addOp(op);
}
void addOp(Op op) {
if (mHead == null) {
mHead = mTail = op;
} else {
op.prev = mTail;
mTail.next = op;
mTail = op;
}
op.enterAnim = mEnterAnim;
op.exitAnim = mExitAnim;
op.popEnterAnim = mPopEnterAnim;
op.popExitAnim = mPopExitAnim;
mNumOp++;
}
commite()方法才真正执行,添加操作
void moveToState(Fragment f, int newState, int transit,
int transitionStyle, boolean keepActive){
// ... 省略部分代码
f.onAttach(mHost.getContext());
// 这个方法一调用就会执行Fragment的onAttach(Activity activity)这个生命周期方法
if (f.mParentFragment == null) {
mHost.onAttachFragment(f);
}
if (!f.mRetaining) {
f.performCreate(f.mSavedFragmentState);
// 执行生命周期onCreate(savedInstanceState);
}
f.mRetaining = false;
if (f.mFromLayout) {
ViewGroup container = null;
if (f.mContainerId != 0) {
//从activity中找到我们需要存放Fragment的ViewGroup布局
container = (ViewGroup)mContainer.onFindViewById(f.mContainerId);
if (container == null && !f.mRestored) {
throwException(new IllegalArgumentException(
"No view found for id 0x"
+ Integer.toHexString(f.mContainerId) + " ("
+ f.getResources().getResourceName(f.mContainerId)
+ ") for fragment " + f));
}
}
// For fragments that are part of the content view
// layout, we need to instantiate the view immediately
// and the inflater will take care of adding it.
f.mView = f.performCreateView(f.getLayoutInflater(
f.mSavedFragmentState), null, f.mSavedFragmentState);
// 这个方法过后会执行onCreateView()生命周期且f.mView就是我们自己覆盖Fragment返回的View
if (f.mView != null) {
f.mInnerView = f.mView;
// v4包兼容11以下的版本我还是没说错啊
if (Build.VERSION.SDK_INT >= 11) {
ViewCompat.setSaveFromParentEnabled(f.mView, false);
} else {
f.mView = NoSaveStateFrameLayout.wrap(f.mView);
}
if (container != null) {
Animation anim = loadAnimation(f, transit, true,
transitionStyle);
if (anim != null) {
setHWLayerAnimListenerIfAlpha(f.mView, anim);
f.mView.startAnimation(anim);
}
// 如果ViewGroup不等于null就把从onCreateView()生命周期中获得的View添加到该布局中
// 最主要的就是这个方法,其实我们可以把Fragment理解成一个自定义的类
// 通过onCreateView()获取的到View添加到一个FragmentActivity的一个ViewGroup中
// 只不过它有自己的生命周期而已......
container.addView(f.mView);
}
// 如果是隐藏那就设置为不可见
if (f.mHidden) f.mView.setVisibility(View.GONE);
// 执行onViewCreated()生命周期方法
f.onViewCreated(f.mView, f.mSavedFragmentState);
} else {
f.mInnerView = null;
}
f.performActivityCreated(f.mSavedFragmentState);
if (f.mView != null) {
f.restoreViewState(f.mSavedFragmentState);
}
f.mSavedFragmentState = null;
}
// 代码省略......
}
}
// 后面的我们就不看了,这上面的代码我自己做了一些整合,把它连贯起来了
// 因为我们把add方法写在了Activity中的onCreate()方法中所以做了一些处理......
remove:将frameLayout的fragment一层层去掉
replace:将replace相当于执行了remove和add,会remove相同id的所有Fragment,然后再把这个Fragment放进去
public FragmentTransaction replace(int containerViewId, Fragment fragment, String tag) {
if (containerViewId == 0) {
throw new IllegalArgumentException("Must use non-zero containerViewId");
}
doAddOp(containerViewId, fragment, tag, OP_REPLACE);
return this;
}
if (mManager.mAdded != null) {
for (int i = mManager.mAdded.size() - 1; i >= 0; i--) {
Fragment old = mManager.mAdded.get(i);
if (old.mContainerId == containerId) {
if (old == f) {
op.fragment = f = null;
} else {
if (op.removed == null) {
op.removed = new ArrayList<Fragment>();
}
op.removed.add(old);
old.mNextAnim = exitAnim;
if (mAddToBackStack) {
old.mBackStackNesting += 1;
}
mManager.removeFragment(old, transition, transitionStyle);
}
}
}
}
if (f != null) {
f.mNextAnim = enterAnim;
mManager.addFragment(f, false);
}
image.png
3.碎片的生命周期
有11个方法,其中活动的6个方法都有(除了restart),
onAttach()碎片与活动关联,
onCreate()
onCreateView()创建碎片布局,
onActivtyCreated()碎片与活动都创建好
onstart(),
onResume(),
onPause(),
onStop,
onDestoryView()碎片视图被移除
onDestroy(),
onDetach()碎片与活动解除关联。
4.fragment的通信
Bundle和setArguments(bundle)1.handler、2.广播、3.EventBus、4.接口回调、
1.handler:在activity/fragment实例handler,然后在fragment拿到actvity的handler,然后通过handler发送消息。fragment可以通过getActivity()拿到宿主activity。(只能单向传输数据)
image示意图
2.广播:fragment发送广播,activity/fragment接收广播(不能传输数据)
在要接收的activity/fragmen注册广播,不过不能向它传播数据。
image示意图
3.EventBus:在要接收的activity/frament中注册/反注册事件,并通过注解方法接收对象并处理。(单向传输一个对象)
image示意图
在发送frgment:
EventBus.getDefault().post(对象);
4.接口回调:activity通过继续接口,同时实现实现接口的抽象方法,抽象的方法的参数就是传递过来的数据,发送的fragment通过拿到接口的实例,通过接口的实例调用方法,写入参数。
在fragment中定义接口和在onattach()方法在获取activity的实例
image示意图
在activity中实现接口:
image示意图
5.Bundle和setArguments(bundle):如果有实例化的fragment时,可以通过setArguments(bundle)来给fragment来传输数据。(单向传输数据)
image示意图
image示意图
5.fragment的懒加载: