關於Fragment的基礎篇:Fragment基礎篇 官方指導地址:官方指地址 Github demo 地址:demo 使用Navigation能夠管理APP頁面跳轉。Navigation不部分狀況下做用於Fragment中,使用Navigation切換Fragment可使代碼簡潔,直觀。Navigation導航組件還支持:Fragment、Activity、導航圖和子圖、自定義目標等。node
def nav_dep = "2.0.0"
implementation "androidx.navigation:navigation-fragment:$nav_dep"
implementation "androidx.navigation:navigation-ui:$nav_dep"
複製代碼
<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
app:startDestination="@id/first_fragment">
<fragment
android:id="@+id/first_fragment"
android:name="com.jandroid.module_common.jetpack.navigation.FirstNavigationFragment"
android:label="first_fragment"
tools:layout="@layout/fragment_first_navigation">
<action
android:id="@+id/action_to_second_fragment"
app:destination="@id/second_fragment" />
</fragment>
<fragment
android:id="@+id/second_fragment"
android:name="com.jandroid.module_common.jetpack.navigation.SecondNavigationFragment"
android:label="second_fragment"
tools:layout="@layout/fragment_second_navigation">
<action
android:id="@+id/action_popup_to_first_fragment"
app:popUpTo="@id/first_fragment" />
<action
android:id="@+id/action_to_third_fragment"
app:destination="@id/third_fragment" />
<argument
android:name="title" app:argType="string" android:defaultValue="jetpack navigation"
/>
</fragment>
<fragment
android:id="@+id/third_fragment"
android:name="com.jandroid.module_common.jetpack.navigation.ThirdNavigationFragment"
android:label="third_navigation"
tools:layout="@layout/fragment_third_navigation" >
<action android:id="@+id/action_popup_to_first_fragment_from_third"
app:popUpTo="@id/first_fragment"/>
</fragment>
</navigation>
複製代碼
字段解析: (1)navigation根節點 startDestination 表示第一個顯示的fragment。即FirstNavigationFragment (2)fragment 節點中name屬性表示所屬的fragment類 (3)fragment 節點中action節點destination屬性用於指定下一個目標fragment (4)fragment 節點中argument 用於傳遞數據。表示的是傳遞到當前Fragment的數據,Key爲name屬性,默認數據是android:defaultValue,數據類型是argType。 3. 建立Fragment 以ThirdNavigationFragment爲例。onCreateView返回佈局View。onViewCreated設置點擊時間,執行相應的action,來完成Fragment的跳轉。在頁面跳歡時,會執行onDestroyView方法,重新回到該Fragment,會執行方法onCreateView方法。android
class ThirdNavigationFragment : Fragment(){
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return LayoutInflater.from(this.activity).inflate(R.layout.fragment_third_navigation,container,false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
btn_third_fragment.setOnClickListener{
Navigation.findNavController(it).navigate(R.id.action_popup_to_first_fragment_from_third)
}
}
}
複製代碼
<?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:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!--xml實現-->
<fragment
android:id="@+id/fragment_navigation"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:name="androidx.navigation.fragment.NavHostFragment"
app:defaultNavHost="false"
app:navGraph="@navigation/navigation_jetpack"/>
<!--代碼實現-->
<FrameLayout
android:id="@+id/ll_fragment_navigation"
android:layout_width="match_parent"
android:layout_height="match_parent"
></FrameLayout>
</LinearLayout>
複製代碼
佈局解析: (1)xml實現和代碼實如今使用時,請務必註解其中一個。 (2)若是使用xml實現,fragment務必設置id。navGraph 用來表示上面的導航意圖文件 navigation_jetpack.xml (3)name 必須指定爲如下值,這是切換fragment的容器 android:name="androidx.navigation.fragment.NavHostFragment" (4)defaultNavHost 表示是否攔截返回鍵,默認爲false。 4.2 Activity中使用 若是使用的是代碼實現的佈局文件,在Activity中使用以下代碼: (1)初始化NavHostFragment。 (2)將NavHostFragment綁定到佈局文件的FrameLayout中。git
class NavigationActivity : AppCompatActivity(){
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_navigation)
val finalHost = NavHostFragment.create(R.navigation.navigation_jetpack)
supportFragmentManager.beginTransaction()
.replace(R.id.ll_fragment_navigation, finalHost)
.setPrimaryNavigationFragment(finalHost)
.commit()
}
}
複製代碼
切換Fragment主要有一下兩種方式: (1)方式1:github
Navigation.findNavController(it).navigate(R.id.action_to_second_fragment)
複製代碼
(2)方式2:bash
NavHostFragment.findNavController(this).navigate(R.id.action_to_second_fragment,null)
複製代碼
這兩種實現方式其實都返回了一個 NavController 類,而後再經過調用navigate方法控制頁面導航,也就是說經過NavController 咱們能夠控制全部的Fragment導航行爲。 7. 數據傳遞 在navigation導航文件中能夠經過設置argument標籤,來設置fragment所接收的參數類型和默認值。app
<argument
android:name="title" app:argType="string" android:defaultValue="jetpack navigation"
/>
複製代碼
或者在代碼中使用傳統方式:ide
val bundle = Bundle()
bundle.putString("name","Blank")
bundle.putInt("number",10)
NavHostFragment.findNavController(this).navigate(R.id.action_to_second_fragment,bundle)
複製代碼
在代碼中,使用navigate() 方法並將Bundle並將其傳遞到目標。接受方Fragment中,使用getArguments()方法檢索包並使用其內容。 8. 嵌套導航圖 能夠將目的地分組爲導航圖中的子圖,子圖也被稱爲「 嵌套圖 」,包含圖稱爲「 根圖「。以下咱們創建子圖:third_navigation。源碼分析
<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
app:startDestination="@id/first_fragment">
<fragment
android:id="@+id/first_fragment"
android:name="com.jandroid.module_common.jetpack.navigation.FirstNavigationFragment"
android:label="first_fragment"
tools:layout="@layout/fragment_first_navigation">
<action
android:id="@+id/action_to_second_fragment"
app:destination="@id/second_fragment" />
</fragment>
<fragment
android:id="@+id/second_fragment"
android:name="com.jandroid.module_common.jetpack.navigation.SecondNavigationFragment"
android:label="second_fragment"
tools:layout="@layout/fragment_second_navigation">
<action
android:id="@+id/action_popup_to_first_fragment"
app:popUpTo="@id/first_fragment" />
<action
android:id="@+id/action_to_third_fragment"
app:destination="@id/third_navigation" />
<argument
android:name="title" app:argType="string" android:defaultValue="jetpack navigation"
/>
</fragment>
<navigation
android:id="@+id/third_navigation"
app:startDestination="@id/third_fragment">
<fragment
android:id="@+id/third_fragment"
android:name="com.jandroid.module_common.jetpack.navigation.ThirdNavigationFragment"
android:label="third_navigation"
tools:layout="@layout/fragment_third_navigation" >
<action android:id="@+id/action_popup_to_first_fragment_from_third"
app:popUpTo="@id/first_fragment"/>
</fragment>
</navigation>
</navigation>
複製代碼
<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/navigation_nested"
app:startDestination="@id/third_fragment">
<fragment
android:id="@+id/third_fragment"
android:name="com.jandroid.module_common.jetpack.navigation.ThirdNavigationFragment"
android:label="third_navigation"
tools:layout="@layout/fragment_third_navigation" >
<action android:id="@+id/action_popup_to_first_fragment_from_third"
app:popUpTo="@id/first_fragment"/>
</fragment>
</navigation>
複製代碼
在navigation_jetpack中include navigation_nested。佈局
<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
app:startDestination="@id/first_fragment">
<fragment
android:id="@+id/first_fragment"
android:name="com.jandroid.module_common.jetpack.navigation.FirstNavigationFragment"
android:label="first_fragment"
tools:layout="@layout/fragment_first_navigation">
<action
android:id="@+id/action_to_second_fragment"
app:destination="@id/second_fragment" />
</fragment>
<fragment
android:id="@+id/second_fragment"
android:name="com.jandroid.module_common.jetpack.navigation.SecondNavigationFragment"
android:label="second_fragment"
tools:layout="@layout/fragment_second_navigation">
<action
android:id="@+id/action_popup_to_first_fragment"
app:popUpTo="@id/first_fragment" />
<action
android:id="@+id/action_to_third_fragment"
app:destination="@id/navigation_nested" />
<argument
android:name="title" app:argType="string" android:defaultValue="jetpack navigation"
/>
</fragment>
<include app:graph="@navigation/navigation_nested"/>
</navigation>
複製代碼
Navigation的其餘用法能夠參考下面Blog,包含Deep Link等。動畫
cloud.tencent.com/developer/a…
cloud.tencent.com/developer/a…
經過上面的Navigation使用,咱們知道NavHostFragment做爲一個容器,全部的導航操做都是NavHostFragment中進行,在NavHostFragment中又委託給了NavController類。因此咱們下面主要看看NavController類是如何被建立出來的,以及在建立過程當中NavHostFragment類都作那些初始化工做。NavHostFragment的初始化主要有兩種實現方式,1:配置XML文件。2:代碼實現。下面咱們以代碼實現NavHostFragment.create爲入口來分析,NavHostFragment類。
val finalHost = NavHostFragment.create(R.navigation.navigation_jetpack)
supportFragmentManager.beginTransaction()
.replace(R.id.ll_fragment_navigation, finalHost)
.setPrimaryNavigationFragment(finalHost)
.commit()
複製代碼
public static NavHostFragment create(@NavigationRes int graphResId,
@Nullable Bundle startDestinationArgs) {
Bundle b = null;
if (graphResId != 0) {
b = new Bundle();
b.putInt(KEY_GRAPH_ID, graphResId);
}
if (startDestinationArgs != null) {
if (b == null) {
b = new Bundle();
}
b.putBundle(KEY_START_DESTINATION_ARGS, startDestinationArgs);
}
final NavHostFragment result = new NavHostFragment();
if (b != null) {
result.setArguments(b);
}
return result;
}
複製代碼
public void onInflate(@NonNull Context context, @NonNull AttributeSet attrs,
@Nullable Bundle savedInstanceState) {
super.onInflate(context, attrs, savedInstanceState);
final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.NavHostFragment);
final int graphId = a.getResourceId(R.styleable.NavHostFragment_navGraph, 0);
final boolean defaultHost = a.getBoolean(R.styleable.NavHostFragment_defaultNavHost, false);
if (graphId != 0) {
mGraphId = graphId;
}
if (defaultHost) {
mDefaultNavHost = true;
}
a.recycle();
}
複製代碼
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
final Context context = requireContext();
mNavController = new NavController(context);
mNavController.getNavigatorProvider().addNavigator(createFragmentNavigator());
Bundle navState = null;
if (savedInstanceState != null) {
navState = savedInstanceState.getBundle(KEY_NAV_CONTROLLER_STATE);
if (savedInstanceState.getBoolean(KEY_DEFAULT_NAV_HOST, false)) {
mDefaultNavHost = true;
requireFragmentManager().beginTransaction()
.setPrimaryNavigationFragment(this)
.commit();
}
}
if (navState != null) {
// Navigation controller state overrides arguments
mNavController.restoreState(navState);
}
if (mGraphId != 0) {
// Set from onInflate()
mNavController.setGraph(mGraphId);
} else {
// See if it was set by NavHostFragment.create()
final Bundle args = getArguments();
final int graphId = args != null ? args.getInt(KEY_GRAPH_ID) : 0;
final Bundle startDestinationArgs = args != null
? args.getBundle(KEY_START_DESTINATION_ARGS)
: null;
if (graphId != 0) {
mNavController.setGraph(graphId, startDestinationArgs);
}
}
}
複製代碼
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
FrameLayout frameLayout = new FrameLayout(inflater.getContext());
// When added via XML, this has no effect (since this FrameLayout is given the ID
// automatically), but this ensures that the View exists as part of this Fragment's View // hierarchy in cases where the NavHostFragment is added programmatically as is required // for child fragment transactions frameLayout.setId(getId()); return frameLayout; } 複製代碼
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
if (!(view instanceof ViewGroup)) {
throw new IllegalStateException("created host view " + view + " is not a ViewGroup");
}
// When added via XML, the parent is null and our view is the root of the NavHostFragment
// but when added programmatically, we need to set the NavController on the parent - i.e.,
// the View that has the ID matching this NavHostFragment.
View rootView = view.getParent() != null ? (View) view.getParent() : view;
Navigation.setViewNavController(rootView, mNavController);
}
複製代碼
public static void setViewNavController(@NonNull View view,
@Nullable NavController controller) {
view.setTag(R.id.nav_controller_view_tag, controller);
}
複製代碼
至此整個NavController對象和NavHostFragment的關係咱們已經梳理明白了。下面來看看 NavController是如何參與到導航事件的。
要想NavController參與到導航事件,必須獲取到該對象才能夠。在Fragment 中控制導航的時候,上面介紹了兩種實現方式。 (1)Navigation.findNavController(it).navigate(R.id.action_page) (2)NavHostFragment.findNavController(this).navigate(R.id.action) 其實不管是經過findNavController或者是findNavController返回的都是NavController對象。 在構建NavController對象的時候,咱們使用到了Navigation類,下面就從該類分析。findNavController方法形參是個View對象,因此是經過view就去查找就NavController,還記得上面用到的viewRoot嗎?。
public static NavController findNavController(@NonNull View view) {
NavController navController = findViewNavController(view);
if (navController == null) {
throw new IllegalStateException("View " + view + " does not have a NavController set");
}
return navController;
}
複製代碼
private static NavController findViewNavController(@NonNull View view) {
while (view != null) {
NavController controller = getViewNavController(view);
if (controller != null) {
return controller;
}
ViewParent parent = view.getParent();
view = parent instanceof View ? (View) parent : null;
}
return null;
}
複製代碼
private static NavController getViewNavController(@NonNull View view) {
Object tag = view.getTag(R.id.nav_controller_view_tag);
NavController controller = null;
if (tag instanceof WeakReference) {
controller = ((WeakReference<NavController>) tag).get();
} else if (tag instanceof NavController) {
controller = (NavController) tag;
}
return controller;
}
複製代碼
至此NavController的獲取過程已經分析完畢。
在實現導航的時候,咱們須要根據navigation配置文件生成NavGraph類,而後在根據每一個不一樣的action id,找到對應的NavDestination就能夠實現頁面導航跳轉了。
mNavController = new NavController(context);
mNavController.getNavigatorProvider().addNavigator(createFragmentNavigator());
複製代碼
(1)其中mNavigatorProvider是NavController中的全局變量,內部經過HashMap鍵值對的形式保存Navigator類。
private final NavigatorProvider mNavigatorProvider = new NavigatorProvider() {
@Nullable
@Override
public Navigator<? extends NavDestination> addNavigator(@NonNull String name,
@NonNull Navigator<? extends NavDestination> navigator) {
Navigator<? extends NavDestination> previousNavigator =
super.addNavigator(name, navigator);
if (previousNavigator != navigator) {
if (previousNavigator != null) {
previousNavigator.removeOnNavigatorBackPressListener(mOnBackPressListener);
}
navigator.addOnNavigatorBackPressListener(mOnBackPressListener);
}
return previousNavigator;
}
};
複製代碼
(2)createFragmentNavigator方法,構建了FragmentNavigator對象,其中抽象類Navigator還有個重要的實現類ActivityNavigator和NavGraphNavigator。這個兩個類的對象在NavController的構造方法中被添加。。
public class FragmentNavigator extends Navigator<FragmentNavigator.Destination>
複製代碼
(3)其中Navigator類的做用是:可以實例化對應的NavDestination,而且可以實現導航功能,擁有本身的回退棧。 2. 構建NavGraph 在構建NavController的時候,咱們還調用了NavController.setGraph(graphId)方法,該方法主要是構建NavGraph。 (1)調用getNavInflater方法建立NavInflater對象,用於解析navigation xml文件
public void setGraph(@NavigationRes int graphResId, @Nullable Bundle startDestinationArgs) {
setGraph(getNavInflater().inflate(graphResId), startDestinationArgs);
}
複製代碼
(2) NavInflater.inflate方法 根據傳入的XML資源id構建NavGraph,NavGraph組成Fragment路由的導航地圖,而NavDestination表明了導航的每個目的地。在解析完NavDestination後,須要要求NavDestination爲NavGraph,即NavGraph是NavDestination的子類。並且在NavGraph內部存儲了NavDestination信息。
public NavGraph inflate(@NavigationRes int graphResId) {
Resources res = mContext.getResources();
//拿到XML的解析器
XmlResourceParser parser = res.getXml(graphResId);
final AttributeSet attrs = Xml.asAttributeSet(parser);
try {
String rootElement = parser.getName();
//構建出NavDestination
NavDestination destination = inflate(res, parser, attrs, graphResId);
//合法性檢測
if (!(destination instanceof NavGraph)) {
throw new IllegalArgumentException("Root element <" + rootElement + ">"
+ " did not inflate into a NavGraph");
}
return (NavGraph) destination;
} catch (Exception e) {
throw new RuntimeException("Exception inflating "
+ res.getResourceName(graphResId) + " line "
+ parser.getLineNumber(), e);
} finally {
parser.close();
}
}
複製代碼
上面的inflate方法內部會繼續調用inflate方法。 (1)getNavigator方法獲取都Navigator實例,該實例在構建NavController是被添加進去,這裏獲取的是FragmentNavigator對象。 (2)createDestination方法,會調用FragmentNavigator的createDestination構建Destination對象。 (3)onInflate方法,調用FragmentNavigator.Destination的方法獲取設置的Fragment的類名。 (4)while循環內部經過遞歸構建導航圖。
private NavDestination inflate(Resources res, XmlResourceParser parser, AttributeSet attrs)
throws XmlPullParserException, IOException {
Navigator navigator = mNavigatorProvider.getNavigator(parser.getName());
final NavDestination dest = navigator.createDestination();
dest.onInflate(mContext, attrs);
final int innerDepth = parser.getDepth() + 1;
int type;
int depth;
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
&& ((depth = parser.getDepth()) >= innerDepth
|| type != XmlPullParser.END_TAG)) {
if (type != XmlPullParser.START_TAG) {
continue;
}
if (depth > innerDepth) {
continue;
}
final String name = parser.getName();
if (TAG_ARGUMENT.equals(name)) {
//解析參數,存儲在dest中
inflateArgument(res, dest, attrs);
} else if (TAG_DEEP_LINK.equals(name)) {
//解析深度連接
inflateDeepLink(res, dest, attrs);
} else if (TAG_ACTION.equals(name)) {
//解析Action
inflateAction(res, dest, attrs);
} else if (TAG_INCLUDE.equals(name) && dest instanceof NavGraph) {
//若是子節點爲graph,加載子節點的destination。即經過include方法。
final TypedArray a = res.obtainAttributes(attrs, R.styleable.NavInclude);
final int id = a.getResourceId(R.styleable.NavInclude_graph, 0);
((NavGraph) dest).addDestination(inflate(id));
a.recycle();
} else if (dest instanceof NavGraph) {
//若是子節點爲graph加載子節點的destination
//向每一個NavGraph中加入Destination
((NavGraph) dest).addDestination(inflate(res, parser, attrs));
}
}
return dest;
}
複製代碼
public void setGraph(@NonNull NavGraph graph, @Nullable Bundle startDestinationArgs) {
if (mGraph != null) {
// Pop everything from the old graph off the back stack
popBackStackInternal(mGraph.getId(), true);
}
mGraph = graph;
onGraphCreated(startDestinationArgs);
}
複製代碼
private void onGraphCreated(@Nullable Bundle startDestinationArgs) {
if (mNavigatorStateToRestore != null) {
ArrayList<String> navigatorNames = mNavigatorStateToRestore.getStringArrayList(
KEY_NAVIGATOR_STATE_NAMES);
if (navigatorNames != null) {
for (String name : navigatorNames) {
Navigator navigator = mNavigatorProvider.getNavigator(name);
Bundle bundle = mNavigatorStateToRestore.getBundle(name);
if (bundle != null) {
navigator.onRestoreState(bundle);
}
}
}
}
if (mBackStackIdsToRestore != null) {
for (int index = 0; index < mBackStackIdsToRestore.length; index++) {
int destinationId = mBackStackIdsToRestore[index];
Bundle args = (Bundle) mBackStackArgsToRestore[index];
NavDestination node = findDestination(destinationId);
if (node == null) {
throw new IllegalStateException("unknown destination during restore: "
+ mContext.getResources().getResourceName(destinationId));
}
if (args != null) {
args.setClassLoader(mContext.getClassLoader());
}
mBackStack.add(new NavBackStackEntry(node, args));
}
mBackStackIdsToRestore = null;
mBackStackArgsToRestore = null;
}
if (mGraph != null && mBackStack.isEmpty()) {
boolean deepLinked = mActivity != null && handleDeepLink(mActivity.getIntent());
if (!deepLinked) {
// Navigate to the first destination in the graph
// if we haven't deep linked to a destination navigate(mGraph, startDestinationArgs, null, null); } } } 複製代碼
在構建和獲取到NavController對象以及NavGraph以後。,下面是使用它來實現真正的導航了。下面從navigate開始分析。在navigate方法內部會查詢到NavDestination,而後根據不一樣的Navigator實現頁面導航。
public void navigate(@IdRes int resId, @Nullable Bundle args, @Nullable NavOptions navOptions,
@Nullable Navigator.Extras navigatorExtras) {
NavDestination currentNode = mBackStack.isEmpty()
? mGraph
: mBackStack.getLast().getDestination();
if (currentNode == null) {
throw new IllegalStateException("no current navigation node");
}
@IdRes int destId = resId;
final NavAction navAction = currentNode.getAction(resId);
Bundle combinedArgs = null;
if (navAction != null) {
if (navOptions == null) {
navOptions = navAction.getNavOptions();
}
destId = navAction.getDestinationId();
Bundle navActionArgs = navAction.getDefaultArguments();
if (navActionArgs != null) {
combinedArgs = new Bundle();
combinedArgs.putAll(navActionArgs);
}
}
if (destId == 0 && navOptions != null && navOptions.getPopUpTo() != -1) {
popBackStack(navOptions.getPopUpTo(), navOptions.isPopUpToInclusive());
return;
}
NavDestination node = findDestination(destId);
navigate(node, combinedArgs, navOptions, navigatorExtras);
}
private void navigate(@NonNull NavDestination node, @Nullable Bundle args,
@Nullable NavOptions navOptions, @Nullable Navigator.Extras navigatorExtras) {
boolean popped = false;
if (navOptions != null) {
if (navOptions.getPopUpTo() != -1) {
popped = popBackStackInternal(navOptions.getPopUpTo(),
navOptions.isPopUpToInclusive());
}
}
Navigator<NavDestination> navigator = mNavigatorProvider.getNavigator(
node.getNavigatorName());
Bundle finalArgs = node.addInDefaultArgs(args);
NavDestination newDest = navigator.navigate(node, finalArgs,
navOptions, navigatorExtras);
複製代碼
public NavDestination navigate(@NonNull Destination destination, @Nullable Bundle args,
@Nullable NavOptions navOptions, @Nullable Navigator.Extras navigatorExtras) {
if (mFragmentManager.isStateSaved()) {
Log.i(TAG, "Ignoring navigate() call: FragmentManager has already"
+ " saved its state");
return null;
}
String className = destination.getClassName();
if (className.charAt(0) == '.') {
className = mContext.getPackageName() + className;
}
final Fragment frag = instantiateFragment(mContext, mFragmentManager,
className, args);
frag.setArguments(args);
final FragmentTransaction ft = mFragmentManager.beginTransaction();
int enterAnim = navOptions != null ? navOptions.getEnterAnim() : -1;
int exitAnim = navOptions != null ? navOptions.getExitAnim() : -1;
int popEnterAnim = navOptions != null ? navOptions.getPopEnterAnim() : -1;
int popExitAnim = navOptions != null ? navOptions.getPopExitAnim() : -1;
if (enterAnim != -1 || exitAnim != -1 || popEnterAnim != -1 || popExitAnim != -1) {
enterAnim = enterAnim != -1 ? enterAnim : 0;
exitAnim = exitAnim != -1 ? exitAnim : 0;
popEnterAnim = popEnterAnim != -1 ? popEnterAnim : 0;
popExitAnim = popExitAnim != -1 ? popExitAnim : 0;
ft.setCustomAnimations(enterAnim, exitAnim, popEnterAnim, popExitAnim);
}
ft.replace(mContainerId, frag);
ft.setPrimaryNavigationFragment(frag);
ft.setReorderingAllowed(true);
ft.commit();
}
複製代碼
(1)NavHostFragment 做爲導航載體,在Activity的layout文件裏被引用(或者在代碼中動態),而且持有導航控制類NavController引用。 (2)NavController 將導航任務委託給Navigator類,Navigator類有兩個重要的子類FragmentNavigator和ActivityNavigator子類。NavController類持有NavInflater類引用。 (3)NavInflater 負責解析Navgation文件,負責構建NavGraph導航圖。 (4)NavDestination 存有各個目的地信息,在FragmentNavigator和ActivityNavigator內部分別對應一個Destination類,該類繼承NavDestination。 (5)在頁面導航時,fragment的操做仍是交由FragmentManager在操做,activity交由startActivity執行。
下面貼一下,網上總結的比較全的類圖信息: 來自圖片來源