Android Fragment 和 FragmentManager 的代码分析
这两天在研究插件化编程,在使用 fragment 碰到了一些问题,于是查看源码,顺便分析了一下 fragment 和 fragmentmanager 以及其他几个 api 的原代码,看看他们是怎么工作的。
我们知道 fragment 有个 oncreateview() 方法,这个方法在 fragment 创建 view 的时候被调用,并且返回一个 view 对象。那么 oncreateview 在什么时候被调用呢,咱们在 fragment 这个类里找到了一个方法,performcreateview() 方法。
fragment.java public view oncreateview(layoutinflater inflater, @nullable viewgroup container, @nullable bundle savedinstancestate) { return null; }
performcreateview 这个方法在什么时候会被调用呢,在 fragment 里找不到调用它的代码。咱们可以猜测一下,大概会在 fragmentmanager 里。
view performcreateview(layoutinflater inflater, viewgroup container, bundle savedinstancestate) { if (mchildfragmentmanager != null) { mchildfragmentmanager.notestatenotsaved(); } return oncreateview(inflater, container, savedinstancestate); }
在 fragmentmanager 里,咱们找到了调用 fragment.performcreateview 的代码,在 movetostate() 方法里,这个方法有点大,我只粘贴了部分代码。可以看到,它会在 fragment 初始化或者创建的时候被调用。并且我们知道,创建的view 被赋值给 fragment 的 mview 成员变量了。
fragmentmanager.java void movetostate(fragment f, int newstate, int transit, int transitionstyle, boolean keepactive) { switch (f.mstate) { case fragment.initializing: if (f.mfromlayout) { f.mview = f.performcreateview(f.getlayoutinflater( f.msavedfragmentstate), null, f.msavedfragmentstate); } break; case fragment.created: if (!f.mfromlayout) { f.mview = f.performcreateview(f.getlayoutinflater( f.msavedfragmentstate), container, f.msavedfragmentstate); } break; } }
接下来,咱们要看什么时候会调用 movetostate() 这个方法。找了一下,发现很 n 多的地方调用了这个方法。这样给咱们逆推找代码造成了一定的难度。于是咱们换个思路,正推来分析。怎么正推了,看咱们怎么使用 fragment 和 fragmentmanager 来分析。
一般咱们都是 getfragmentmanager() 或者 getsupportfragmentmanager() 的方法来获取 fragmentmanager.以 fragmentactivity 为例,一般情况下,咱们在这个类的子类里调用这两个方法之一。
咱们在 fragmentactivity 里找到了相应的代码。fragmentmanager 是一个抽象类,fragmentmanagerimpl 是 fragmentmanager 的子类,在 fragmentmanager 同一个 java 文件内,是一个内部类。它是 fragmentmanager 的实现。
fragmentactivity.java //fragmentmanagerimpl is subclass of fragmentmanager final fragmentmanagerimpl mfragments = new fragmentmanagerimpl(); public fragmentmanager getsupportfragmentmanager() { return mfragments; }
获取到 fragmentmanager 后,咱们一般就会调用 begintransaction() 方法,返回一个 fragmenttransaction 。咱们看代码去。
fragmentmanager.java public abstract fragmenttransaction begintransaction(); fragmentmanagerimpl extends fragmentmanager @override public fragmenttransaction begintransaction() { return new backstackrecord(this); } /** * static library support version of the framework's {@link android.app.fragmenttransaction}. * used to write apps that run on platforms prior to android 3.0. when running * on android 3.0 or above, this implementation is still used; it does not try * to switch to the framework's implementation. see the framework sdk * documentation for a class overview. */ public abstract class fragmenttransaction
我们发现 fragmentmanager 是一个抽象方法,实现在 fragmentmanagerimpl。fragmentmanagerimpl.begintransaction() 返回的是一个backstackrecord,而 fragmenttransaction 是一个抽象类。那么 backstackrecord 是个什么鬼。
我们找到了 backstackrecord 这个类。我们注意到,它继承于 fragmenttransaction,并且实现了 runable 接口。它的方法有很多,咱们就分析一个咱们比较常用的,比如 add() 方法。
backstackrecord.java final class backstackrecord extends fragmenttransaction implements fragmentmanager.backstackentry, runnable final fragmentmanagerimpl mmanager; public backstackrecord(fragmentmanagerimpl manager) { mmanager = manager; }
add() 方法其实没干啥,咱们一路追下去看。
public fragmenttransaction add(fragment fragment, string tag) { doaddop(0, fragment, tag, op_add); return this; } private void doaddop(int containerviewid, fragment fragment, string tag, int opcmd) { fragment.mfragmentmanager = mmanager; 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.mcontainerid = fragment.mfragmentid = containerviewid; } 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++; }
一直追到 addop() 就断了,好像啥事也没干。不过它大概是在一个 add 操作添加到一个链表上了。那咱们怎么办呢?一般咱们add 完后会 commit 一下,咱们看看 commit 都干了啥。
public int commit() { return commitinternal(false); } int commitinternal(boolean allowstateloss) { if (mcommitted) throw new illegalstateexception("commit already called"); mcommitted = true; if (maddtobackstack) { mindex = mmanager.allocbackstackindex(this); } else { mindex = -1; } mmanager.enqueueaction(this, allowstateloss); return mindex; }
commit 好像也没干啥特殊的事情,不过可以看到这么一行代码 mmanager.enqueueaction(this, allowstateloss); 看 enqueueaction 这个方法名,应该会做点事情的。
同样,咱们在 fragmentmanagerimpl 里找到了这个方法。
public void enqueueaction(runnable action, boolean allowstateloss) { if (!allowstateloss) { checkstateloss(); } synchronized (this) { if (mdestroyed || mactivity == null) { throw new illegalstateexception("activity has been destroyed"); } if (mpendingactions == null) { mpendingactions = new arraylist<runnable>(); } mpendingactions.add(action); if (mpendingactions.size() == 1) { mactivity.mhandler.removecallbacks(mexeccommit); mactivity.mhandler.post(mexeccommit); } } }
这个方法把咱们的 backstackrecord -- 其实是 fragmenttransaction,也是 runnable -- 添加到一个 mpendingactions 的 arraylist 里了。然后调用 mactivity.mhandler.post(mexeccommit); mexeccommit 又是什么鬼?
runnable mexeccommit = new runnable() { @override public void run() { execpendingactions(); } }; mactivity.mhandler.post(mexeccommit); 说明它在主线程里执行了 mexeccommit 的 run 方法。别问我咋知道的。 execpendingactions() 方法稍微比较大,我把注释写在代码里。 public boolean execpendingactions() { if (mexecutingactions) { throw new illegalstateexception("recursive entry to executependingtransactions"); } //如果不是在主线程,抛出一个异常。 if (looper.mylooper() != mactivity.mhandler.getlooper()) { throw new illegalstateexception("must be called from main thread of process"); } boolean didsomething = false; // 这里有一个 while true 循环。 while (true) { int numactions; // 这里在一个同步语句块里,把上次 mpendingactions 里的元素转移到 mtmpactions 数组里。并且执行 run方法。执行谁的 run 方法呢?!就是 backstackrecord , 也就是 fragmenttransaction 。我在最后面贴了 backstackrecord 的 run 方法。 synchronized (this) { if (mpendingactions == null || mpendingactions.size() == 0) { break; } numactions = mpendingactions.size(); if (mtmpactions == null || mtmpactions.length < numactions) { mtmpactions = new runnable[numactions]; } mpendingactions.toarray(mtmpactions); mpendingactions.clear(); mactivity.mhandler.removecallbacks(mexeccommit); } mexecutingactions = true; for (int i=0; i<numactions; i++) { mtmpactions[i].run(); mtmpactions[i] = null; } mexecutingactions = false; didsomething = true; } // 这里有好几行代码,不知道干啥的,反正就是做了一些判断,最后可能会调用 startpendingdeferredfragments() 方法。 if (mhavependingdeferredstart) { boolean loadersrunning = false; for (int i=0; i<mactive.size(); i++) { fragment f = mactive.get(i); if (f != null && f.mloadermanager != null) { loadersrunning |= f.mloadermanager.hasrunningloaders(); } } if (!loadersrunning) { mhavependingdeferredstart = false; startpendingdeferredfragments(); } } return didsomething; }
startpendingdeferredfragments 方法又是一坨不知道啥意思的代码。最后可能调用了 performpendingdeferredstart()
void startpendingdeferredfragments() { if (mactive == null) return; for (int i=0; i<mactive.size(); i++) { fragment f = mactive.get(i); if (f != null) { performpendingdeferredstart(f); } } }
在 这个方法里,咱们看到了很熟悉的 movetostate() 方法。接着就是上面的分析,fragment 的 oncreateview 会被调用。
public void performpendingdeferredstart(fragment f) { if (f.mdeferstart) { if (mexecutingactions) { // wait until we're done executing our pending transactions mhavependingdeferredstart = true; return; } f.mdeferstart = false; movetostate(f, mcurstate, 0, 0, false); } }
咱们在回来看 backstackrecord 的 run 方法。这坨代码有点大,我还是写注释在代码里。
public void run() { if (fragmentmanagerimpl.debug) log.v(tag, "run: " + this); if (maddtobackstack) { if (mindex < 0) { throw new illegalstateexception("addtobackstack() called after commit()"); } } bumpbackstacknesting(1); transitionstate state = null; sparsearray<fragment> firstoutfragments = null; sparsearray<fragment> lastinfragments = null; if (supports_transitions) { firstoutfragments = new sparsearray<fragment>(); lastinfragments = new sparsearray<fragment>(); calculatefragments(firstoutfragments, lastinfragments); state = begintransition(firstoutfragments, lastinfragments, false); } int transitionstyle = state != null ? 0 : mtransitionstyle; int transition = state != null ? 0 : mtransition; // 注意这里要开始 while 循环了,要遍历刚才咱们说的链表了。 op op = mhead; while (op != null) { int enteranim = state != null ? 0 : op.enteranim; int exitanim = state != null ? 0 : op.exitanim; switch (op.cmd) { // op_add 很简单,mmanager.addfragment(f, false); 其他的几个也类似,调用 mmanager 相应的方法。 case op_add: { fragment f = op.fragment; f.mnextanim = enteranim; mmanager.addfragment(f, false); } break; case op_replace: { fragment f = op.fragment; if (mmanager.madded != null) { for (int i=0; i<mmanager.madded.size(); i++) { fragment old = mmanager.madded.get(i); if (fragmentmanagerimpl.debug) log.v(tag, "op_replace: adding=" + f + " old=" + old); if (f == null || old.mcontainerid == f.mcontainerid) { 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; if (fragmentmanagerimpl.debug) log.v(tag, "bump nesting of " + old + " to " + old.mbackstacknesting); } mmanager.removefragment(old, transition, transitionstyle); } } } } if (f != null) { f.mnextanim = enteranim; mmanager.addfragment(f, false); } } break; case op_remove: { fragment f = op.fragment; f.mnextanim = exitanim; mmanager.removefragment(f, transition, transitionstyle); } break; case op_hide: { fragment f = op.fragment; f.mnextanim = exitanim; mmanager.hidefragment(f, transition, transitionstyle); } break; case op_show: { fragment f = op.fragment; f.mnextanim = enteranim; mmanager.showfragment(f, transition, transitionstyle); } break; case op_detach: { fragment f = op.fragment; f.mnextanim = exitanim; mmanager.detachfragment(f, transition, transitionstyle); } break; case op_attach: { fragment f = op.fragment; f.mnextanim = enteranim; mmanager.attachfragment(f, transition, transitionstyle); } break; default: { throw new illegalargumentexception("unknown cmd: " + op.cmd); } } op = op.next; } // 最后还调用了movetostate() 这个方法。跟刚才的区别,看最后一个参数,一个true,一个false。 // 而且注意,这行代码在 while 循环之后。 mmanager.movetostate(mmanager.mcurstate, transition, transitionstyle, true); if (maddtobackstack) { mmanager.addbackstackstate(this); } }
以上所述是小编给大家介绍的android fragment 和 fragmentmanager 的代码分析,希望对大家有所帮助
上一篇: Android仿微信进度弹出框的实现方法
推荐阅读
-
Android Activity中onStart()和onResume()的区别分析
-
从源代码分析Android Universal ImageLoader的缓存处理机制
-
Android Fragment 和 FragmentManager 的代码分析
-
android开发之蜂鸣提示音和震动提示的实现原理与参考代码
-
Android系统的智能指针(轻量级指针、强指针和弱指针)的实现原理分析【转】
-
android fm单体声和立体声的切换示例代码
-
android主线程和子线程的区别深入分析
-
android 震动和提示音的实现代码
-
PHP获取客户端真实IP地址的5种情况分析和实现代码_php实例
-
10_Android中通过HttpUrlConnection访问网络,Handler和多线程使用,读取网络html代码并显示在界面上,ScrollView组件的使用_html/css_WEB-ITnose