使用するシーン:
ナビゲーションを使用して、フラグメント間のジャンプ操作を完了します。
問題の説明:
ナビゲーションは、replace()メソッドを使用してフラグメント間のジャンプを実装します。このメソッドは、元のフラグメントを削除して新しいフラグメントを追加します。したがって、前のフラグメントに戻ったら、ライフサイクルプロセスを再度実行してデータを再ロードする必要があります。
解決:
NavControllerクラスのナビゲートソースコードを分析します
private void navigate(@NonNull NavDestination node, @Nullable Bundle args,
@Nullable NavOptions navOptions, @Nullable Navigator.Extras navigatorExtras) {
...
Navigator<NavDestination> navigator = mNavigatorProvider.getNavigator(
node.getNavigatorName()); 根据节点名称生成不同的navigator
Bundle finalArgs = node.addInDefaultArgs(args);
NavDestination newDest = navigator.navigate(node, finalArgs,
navOptions, navigatorExtras); 调用navigator 中的 navigate方法
...
}
getNavigatorのソースコードは次のとおりです
private final HashMap<String, Navigator<? extends NavDestination>> mNavigators =
new HashMap<>();
public <T extends Navigator<?>> T getNavigator(@NonNull String name) {
if (!validateName(name)) {
throw new IllegalArgumentException("navigator name cannot be an empty string");
}
Navigator<? extends NavDestination> navigator = mNavigators.get(name); // 根据传入的node获取不同的navigator
if (navigator == null) {
throw new IllegalStateException("Could not find Navigator with name \"" + name
+ "\". You must call NavController.addNavigator() for each navigation type.");
}
return (T) navigator;
}
したがって、カスタムのnavigate()メソッドを呼び出す場合は、Navigatorクラスをカスタマイズすると同時に、フラグメントノードの名前を変更し、フラグメントノード名とNavigatorクラスをキーと値としてHashMapタイプのmNavigatorに追加する必要があります。
カスタムナビゲーター
@Navigator.Name("custom_fragment") // 节点名称定义为custom_fragment,作为 mNavigatorProvider 变量的 key
class CustomNavigator( //作为 mNavigatorProvider 变量的 value
private val context: Context,
private val manager: FragmentManager,
private val containerId: Int
) : FragmentNavigator(context, manager, containerId) {
override fun navigate( // 重写 navigate 方法
destination: Destination,
args: Bundle?,
navOptions: NavOptions?,
navigatorExtras: Navigator.Extras?
): NavDestination? {
val tag = destination.id.toString() // 跳转目的地
val transaction = manager.beginTransaction() // 开启fragment事务
val currentFragment = manager.primaryNavigationFragment // navigation 顶层fragment
if (currentFragment != null) {
transaction.hide(currentFragment) // 隐藏当前fragment
}
var fragment = manager.findFragmentByTag(tag) // 找到目的地fragment
if (fragment == null) {
// fragment未被初始化
val className = destination.className
fragment = manager.fragmentFactory.instantiate(context.classLoader, className) // 实例化 fragment
transaction.add(containerId, fragment, tag) // 将碎片添加到容器中
} else {
// fragment 已经初始化过了
transaction.show(fragment) // 显示fragment
}
transaction.setPrimaryNavigationFragment(fragment) //将fragment 设置为顶层fragment
transaction.setReorderingAllowed(true)
transaction.commitNow() // 提交事务
return destination // 返回目的地,用于监听
}
}
ノード名を変更する
ノード名はcustom_fragmentとして定義されているため、<custom_fragment>に変更されます。
<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/my_nav"
app:startDestination="@id/home_dest"
tools:ignore="UnusedNavigation">
<custom_fragment
android:id="@+id/home_dest"
android:name="com.cl.androidstudy.ui.home.HomeFragment"
android:label="fragment_home"
tools:layout="@layout/fragment_home" />
<custom_fragment
android:id="@+id/system_dest"
android:name="com.cl.navicationtest.SystemFragment"
android:label="fragment_system"
tools:layout="@layout/fragment_system" />
<custom_fragment
android:id="@+id/square_dest"
android:name="com.cl.navicationtest.SquareFragment"
android:label="fragment_square"
tools:layout="@layout/fragment_square" />
<custom_fragment
android:id="@+id/me_dest"
android:name="com.cl.androidstudy.ui.me.MeFragment"
android:label="fragment_me"
tools:layout="@layout/fragment_me" />
</navigation>
ロジックコード
val navController = Navigation.findNavController(this, R.id.fragment) // 创建navController
val navHostFragment = supportFragmentManager.findFragmentById(R.id.fragment)!!
val navigator = CustomNavigator(
this,
navHostFragment.childFragmentManager,
R.id.fragment
)// 生成自定义Navigator对象
navController.navigatorProvider.addNavigator("custom_fragment", navigator) // 添加 key, value
navController.setGraph(R.navigation.my_nav) // 要在 CustomNavigator 类被加载之后添加graph,不然找不到 custom_fragment节点
リファレンスブログ:https://juejin.im/post/6844903896104747022#heading-2