GVKun编程网logo

Android MainFragment中使用多个Fragment(android 一个activity多个fragment)

22

在这篇文章中,我们将为您详细介绍AndroidMainFragment中使用多个Fragment的内容,并且讨论关于android一个activity多个fragment的相关问题。此外,我们还会涉及

在这篇文章中,我们将为您详细介绍Android MainFragment中使用多个Fragment的内容,并且讨论关于android 一个activity多个fragment的相关问题。此外,我们还会涉及一些关于Android Fragment DialogFragment 合肥懒皮、Android Fragment FragmentTabHost 问题、android fragment replace 多个切换fragment时的遇到的焦点变化、Android Fragment 和 FragmentManager 的代码分析的知识,以帮助您更全面地了解这个主题。

本文目录一览:

Android MainFragment中使用多个Fragment(android 一个activity多个fragment)

Android MainFragment中使用多个Fragment(android 一个activity多个fragment)

当前 MainFragment中创添加多个Fragment代码如下:

MainFragment的Layout文件main_dialog_fragment

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/ll_root_view"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/white"
    android:clickable="true"
    android:fitsSystemWindows="true"
    android:focusableInTouchMode="true"
    android:orientation="vertical">
        //...省略无关代码
        <FrameLayout
            android:id="@+id/fragment_container"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="@android:color/white">
        </FrameLayout>
    </LinearLayout>
</LinearLayout>

MainFragment.Java文件如下:

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        initParams();
        View rootView = inflater.inflate(R.layout.main_dialog_fragment, container, false);
        initFragments(savedInstanceState);
        return rootView;
    }
    
 //初始化两个Fragment 并且显示第一个
    private void initFragments(@Nullable Bundle savedInstanceState) {
        FragmentActivity fragmentActivity = getActivity();
        if (fragmentActivity == null) {
            return;
        }
        //savedInstanceState是对Bundle对象的引用,可以使用此捆绑包中存储的数据将自身恢复到以前的状态
        if (savedInstanceState == null) {
            try {
                //初始化Fragment
                m_fragment1 = new PaymentSubFragment1();
                m_fragment2 = new PaymentSubFragment2();
                
                fragmentActivity.getSupportFragmentManager().beginTransaction()
                        .add(R.id.fragment_container, m_fragment1, kTagFragment1)
                        .add(R.id.fragment_container, m_fragment2, kTagFragment2)
                        .detach(m_fragment2)
                        .commit();
            }catch (Exception e){
                Utils.printBBException(e,279);
            }
            //设定当前的Fragment,知道下一次hide那个Fragment
            m_CurFragment = m_fragment1;
        } else {
            //由于FragmentManager已经存在了这些Fragment直接获取就可以了
            m_fragment1 = (PaymentSubFragment1) fragmentActivity.getSupportFragmentManager()
                    .findFragmentByTag(kTagFragment1);
            m_fragment2 = (PaymentSubFragment2) fragmentActivity.getSupportFragmentManager()
                    .findFragmentByTag(kTagFragment2);
        }
    }

这时运行会报出如下错误:

E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.xxx.android, PID: 29708
    java.lang.IllegalArgumentException: No view found for id 0x7f08030b (com.xxx.android:id/fragment_container) for fragment PaymentSubFragment1{3820d34 (412762d8-5144-47fd-9ff7-abf3ce161066) id=0x7f08030b kTagFragment1}
        at androidx.fragment.app.FragmentManagerImpl.movetoState(FragmentManagerImpl.java:875)
        at androidx.fragment.app.FragmentManagerImpl.moveFragmentToExpectedState(FragmentManagerImpl.java:1238)
        at androidx.fragment.app.FragmentManagerImpl.movetoState(FragmentManagerImpl.java:1303)
        at androidx.fragment.app.BackStackRecord.executeOps(BackStackRecord.java:439)
        at androidx.fragment.app.FragmentManagerImpl.executeOps(FragmentManagerImpl.java:2079)
        at androidx.fragment.app.FragmentManagerImpl.executeOpsTogether(FragmentManagerImpl.java:1869)
        at androidx.fragment.app.FragmentManagerImpl.removeRedundantOperationsAndExecute(FragmentManagerImpl.java:1824)
        at androidx.fragment.app.FragmentManagerImpl.execPendingActions(FragmentManagerImpl.java:1727)
        at androidx.fragment.app.FragmentManagerImpl$2.run(FragmentManagerImpl.java:150)
        at android.os.Handler.handleCallback(Handler.java:883)
        at android.os.Handler.dispatchMessage(Handler.java:100)
        at android.os.Looper.loop(Looper.java:264)
        at android.app.ActivityThread.main(ActivityThread.java:7581)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:980)

提示原因找不到View 名称为 fragment_container, 实际上Layout文件中是存在的,原因是在MainFragment中使用了getSupportFragmentManager方法,因为getSupportFragmentManager方法是属于FragmentActivity类的,因为查找的是Activity的Layout文件所以找不到这个View, 将其改为getChildFragmentManager就是当前MainFragment的Layout了,修改后代码如下:

    //初始化两个Fragment 并且显示第一个
    private void initFragments(@Nullable Bundle savedInstanceState) {
        if (savedInstanceState == null) {
            try {
                //初始化Fragment
                m_fragment1 = new PaymentSubFragment1();
                m_fragment2 = new PaymentSubFragment2();

                getChildFragmentManager().beginTransaction()
                        .add(R.id.fragment_container, m_fragment1, kTagFragment1)
                        .add(R.id.fragment_container, m_fragment2, kTagFragment2)
                        .detach(m_fragment2)
                        .commit();
            }catch (Exception e){
                Utils.printBBException(e,279);
            }
            //设定当前的Fragment,知道下一次hide那个Fragment
            m_CurFragment = m_fragment1;
        } else {
            //由于FragmentManager已经存在了这些Fragment直接获取就可以了
            m_fragment1 = (PaymentSubFragment1) getChildFragmentManager()
                    .findFragmentByTag(kTagFragment1);
            m_fragment2 = (PaymentSubFragment2) getChildFragmentManager()
                    .findFragmentByTag(kTagFragment2);
        }
    }

Android Fragment DialogFragment 合肥懒皮

Android Fragment DialogFragment 合肥懒皮

https://www.jianshu.com/p/971de3036bd1

Android Fragment FragmentTabHost 问题

Android Fragment FragmentTabHost 问题

今天需要做一个功能,实现 tab 切换功能,但是又不能向 viewpager 一样可以滑动,只能通过顶部的 tab 标签滑动,就是类似 ActionBar 的 tab 一样的切换。

然后我就去找例子,在 ApiDemos 中有 FragmentTabs(extends Activity),FragmentTabsFragment (extends Fragment),两个例子,特别说一下 FragmentTabsFragment,这个类中的 TabManager 是重写了 FragmentTabHost,自己实现的状态保存等等,值得参考一下,当然,这个类也参考了 FragmentTabHost 的实现。

在 Support4Demos 中,有 FragmentTabs (extends FragmentActivity),FragmentTabsFragmentSupport (extends Fragment);

我主要参考的是 FragmentTabsFragmentSupport,因为我想用 Fragment 去实现我的需求。

 遇到的几个问题:

1.FragmentTabHost 的顶部 tab 样式是系统的,不符合我的要求,那么如何定制这个样式呢?

你一定是这样使用的:

mTabHost.addTab(mTabHost.newTabSpec("simple").setIndicator(“simple”), ArrayListFragment.class, null);

如果要改这个 tab 的样式,可以这样:

Button simple = new Button(getActivity());
simple.setText("xxx");
simple.setTextColor(this.getResources().getColor(R.color.green));
// simple.setBackgroundColor(R.color.indicate);
simple.setBackgroundResource(R.drawable.ic_star_p);
// set padding
// simple.setPadding(150, 150, 0, 0);
// set margin
LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
0, LinearLayout.LayoutParams.MATCH_PARENT, 1);  // 1 是可选写的
lp.setMargins(150, 50, 0, 50);
simple.setLayoutParams(lp);

看到了吧,可以设置 padding, margin, background 等。。。

然后 -》setIndicator (View view), 看到了吧,有个方法是支持自定义 view 的,所以我们就可以自定义一个 view,比如,把上面定义的 Button simple 传进去就可以了。

还可以设置 TabWidget 的高度和背景:

mTabHost.getTabWidget().setBackgroundResource(R.drawable.ic_new_tab_p);

mTabHost.getTabWidget().setMinimumHeight(300);
mTabHost.getTabWidget().setDividerDrawable(null);

2. 多个 tab 切换的时候,每次都会从新执行:onCreateView,onDestroyView,导致比如 listview 这种无法保存浏览的位置?

我是这样解决的:

if (rootView == null) {
rootView = inflater.inflate(R.layout.fragment_pager_list, container, false);
}
ViewGroup parent = (ViewGroup) rootView.getParent();
if (parent != null) {
parent.removeView(rootView);
}

View tv = rootView.findViewById(R.id.text);
((TextView)tv).setText("Fragment #" + mNum);
return rootView;


测试代码下载地址:

http://download.csdn.net/detail/song_shi_chao/7168045

参考:

http://www.cnblogs.com/asion/archive/2013/09/25/3339313.html

http://ar.newsmth.net/thread-ffd9fb821607d1.html

http://www.eoeandroid.com/thread-322096-1-1.html

http://www.byywee.com/page/M0/S910/910755.html

http://blog.csdn.net/renpengben/article/details/12615487(我使用了这种方法)

http://www.2cto.com/kf/201309/242225.html

http://www.eoeandroid.com/thread-153696-1-1.html(ViewPager 与其中的子 View 滑动冲突该如何解决


android fragment replace 多个切换fragment时的遇到的焦点变化

android fragment replace 多个切换fragment时的遇到的焦点变化

 第一个fragment代码:

package com.example.liuyj.mstarsysseting.fragment;

import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import com.example.liuyj.mstarsysseting.R;

public class FragmentSysTools extends Fragment {
    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.layout_systools, container, false);

        view.findViewById(R.id.toolsReset).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
               getFragmentManager()
                        .beginTransaction()
                        .addToBackStack(null)
                        .replace(R.id.fragment, new FragmentSysToolsReset())
                        .commit();
            }
        });
        view.findViewById(R.id.toolsReset).requestFocus();
        return view;
    }

    @Override
    public void onStart() {
        Log.e("FragmentSysTools", "onStart");
        super.onStart();
    }

    @Override
    public void onResume() {
        Log.e("FragmentSysTools", "onResume");
        super.onResume();
    }

    @Override
    public void onPause() {
        Log.e("FragmentSysTools", "onPause");
        super.onPause();
    }

    @Override
    public void onStop() {
        Log.e("FragmentSysTools", "onStop");
        super.onStop();
    }

    @Override
    public void onDestroy() {
        Log.e("FragmentSysTools", "onDestroy");
        super.onDestroy();
    }
}

  

第二个fragment代码:

package com.example.liuyj.mstarsysseting.fragment;

import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.util.Log;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.Toast;

import com.example.liuyj.mstarsysseting.R;

import java.security.Key;

public class FragmentSysToolsReset extends Fragment {
    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.layout_systools_reset, container, false);

        Button button = view.findViewById(R.id.toolsRest_test);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                getFragmentManager().popBackStack();
            }
        });

        button.requestFocus();
        return view;
    }

    @Override
    public void onStart() {
        Log.e("FragmentSysToolsReset", "onStart");
        super.onStart();
    }

    @Override
    public void onResume() {
        Log.e("FragmentSysToolsReset", "onResume");
        super.onResume();
    }

    @Override
    public void onPause() {
        Log.e("FragmentSysToolsReset", "onPause");
        super.onPause();
    }

    @Override
    public void onStop() {
        Log.e("FragmentSysToolsReset", "onStop");
        super.onStop();
    }
    @Override
    public void onDestroy() {
        Log.e("FragmentSysTools", "onDestroy");
        super.onDestroy();
    }

}

  

 

切换代码:

getFragmentManager()
		.beginTransaction()
		.addToBackStack(null)      //入栈,默认按返回时将会返回到这个fragment。
		.replace(R.id.fragment, new FragmentSysToolsReset())  //使用的时replace函数切换fragment
		.commit();

  

遇到的问题:

  因为进入下一个fragment,和返回上一个fragment时。是先完全关闭了当前显示的fragment后再打开另一个fragment,

  -->所以页面上的焦点将会跳转到android页面的其他焦点过渡。

  -->若,焦点上存在焦点监听的事件也将会进行处理。

  

生命周期中查看,fragment的运行状态:

 

解决办法:使用 add() hide() show() 函数来处理: 切换时 hide() 函数放在 show() 函数后面

public void showFragment(Fragment fragmentTo) {
        FragmentManager fragmentManager = getSupportFragmentManager();
        FragmentTransaction transaction = fragmentManager.beginTransaction();

        if(fragmentCurr == fragmentTo) {
            return;
        }
        
        if (fragmentTo.isAdded()) {
            transaction.show(fragmentTo);
        } else {
            transaction.add(R.id.fragment, fragmentTo).show(fragmentTo);
        }

        if (null != fragmentCurr) {
            transaction.hide(fragmentCurr);   //hide()函数放在show()函数后面。保证焦点存在
        }

        fragmentCurr = fragmentTo;
        transaction.commit();
    }

  

Android Fragment 和 FragmentManager 的代码分析

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),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,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,transitionStyle);
      } break;
      case OP_HIDE: {
        Fragment f = op.fragment;
        f.mNextAnim = exitAnim;
        mManager.hideFragment(f,transitionStyle);
      } break;
      case OP_SHOW: {
        Fragment f = op.fragment;
        f.mNextAnim = enteranim;
        mManager.showFragment(f,transitionStyle);
      } break;
      case OP_DETACH: {
        Fragment f = op.fragment;
        f.mNextAnim = exitAnim;
        mManager.detachFragment(f,transitionStyle);
      } break;
      case OP_ATTACH: {
        Fragment f = op.fragment;
        f.mNextAnim = enteranim;
        mManager.attachFragment(f,transitionStyle);
      } break;
      default: {
        throw new IllegalArgumentException("UnkNown cmd: " + op.cmd);
      }
    }
    op = op.next;
  }
  // 最后还调用了movetoState() 这个方法。跟刚才的区别,看最后一个参数,一个true,一个false。
  // 而且注意,这行代码在 while 循环之后。
  mManager.movetoState(mManager.mCurState,transitionStyle,true);
  if (mAddToBackStack) {
    mManager.addBackStackState(this);
  }
}

以上所述是小编给大家介绍的Android Fragment 和 FragmentManager 的代码分析,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对编程小技巧网站的支持!

今天关于Android MainFragment中使用多个Fragmentandroid 一个activity多个fragment的讲解已经结束,谢谢您的阅读,如果想了解更多关于Android Fragment DialogFragment 合肥懒皮、Android Fragment FragmentTabHost 问题、android fragment replace 多个切换fragment时的遇到的焦点变化、Android Fragment 和 FragmentManager 的代码分析的相关知识,请在本站搜索。

本文标签: