Navigation(Android Architecture Components)のサンプル

Navigation(Android Architecture Components)のサンプルを作ってみました。
複数のNavigation設定をLiveDataを使って連携しています。

# GitHub

https://github.com/mitchibu/NavSample

# Navigationの導入

### Gradleの設定
Navigationを使用するための設定を追加します。

```build.gradle(Project)
dependencies {
    classpath 'android.arch.navigation:navigation-safe-args-gradle-plugin:1.0.0-alpha09'
}
```

```build.gradle(Module)
apply plugin: 'androidx.navigation.safeargs'

dependencies {
    implementation 'android.arch.navigation:navigation-fragment:1.0.0-alpha09'
    implementation 'android.arch.navigation:navigation-ui:1.0.0-alpha09'
}
```

### Navigation Editorを使う
リソースにnavigationファイルを追加します。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/103857/c2fcb786-f53e-8e90-0283-063db556350f.png)

MainActivityのnavigation設定です。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/103857/78b6b22e-91f3-fcef-749e-b0f11df9a614.png)

MainFragmentのnavigation設定です。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/103857/61c0b1c8-2a2d-7c43-8a8f-28ce6174be5f.png)

### MainActivityでNavigationにToolbar・DrawerLayout+NavigationViewを連携させる

```MainActivity.java
@Override
protected void onCreate(Bundle savedInstanceState) {
	super.onCreate(savedInstanceState);
	setSupportActionBar(getBinding().toolBar);

	// NavHostFragmentからNavControllerを取得する
	NavHostFragment host = (NavHostFragment)getSupportFragmentManager().findFragmentById(R.id.nav_host);
	NavController controller = NavHostFragment.findNavController(Objects.requireNonNull(host));

	// ToolbarとDrawerLayoutを連携させる
	NavigationUI.setupActionBarWithNavController(this, controller, getBinding().drawer);
	// NavigationViewを連携させる
	NavigationUI.setupWithNavController(getBinding().navigation, controller);
}

@Override
public void onBackPressed() {
	// Drawerが開いているときにBackした場合にはDrawerを閉じる
	if(getBinding().drawer.isDrawerOpen(GravityCompat.START)) {
		getBinding().drawer.closeDrawer(GravityCompat.START);
	} else {
		super.onBackPressed();
	}
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
	// NavigationViewとNavigationを連携させる
	return NavigationUI.onNavDestinationSelected(item, controller) || super.onOptionsItemSelected(item);
}

@Override
public boolean onSupportNavigateUp() {
	// ToolbarとNavigationを連携させる
	return NavigationUI.navigateUp(controller, getBinding().drawer) || super.onSupportNavigateUp();
}
```

### MainFragmentでNavigationにBottomNavigationViewを連携させる

```MainFragment.java
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
	super.onViewCreated(view, savedInstanceState);

	// NavHostFragmentからNavControllerを取得する
	NavHostFragment host = (NavHostFragment)getChildFragmentManager().findFragmentById(R.id.nav_host);
	NavController controller = NavHostFragment.findNavController(Objects.requireNonNull(host));

	// BottomNavigationViewを連携させる
	NavigationUI.setupWithNavController(getBinding().bottomNavigation, controller);
}
```

### HomeFragmentからSubFragmentを開くために
Navigationの設定では、HomeFragmentとSubFragmentは繋がっていないため直接開くことはできません。RxやMessenger等を使って連携させる方法があるらしいですが、私はLiveDataを使って連携させてみました。

```ShareViewModel.java
public class ShareViewModel extends ViewModel {
	public static ShareViewModel get(Fragment fragment) {
		return ViewModelProviders.of(Objects.requireNonNull(fragment.getActivity())).get(ShareViewModel.class);
	}

	// 今回の肝になるLiveDataです
	private final MutableLiveData<Long> showSubFragment = new MutableLiveData<>();

	// SubFragmentを開く場合にコールします
	public void showSubFragment() {
		showSubFragment.postValue(System.currentTimeMillis());
	}

	// SubFragmentを開くためにイベントを登録します
	public void setOnShowSubFragment(LifecycleOwner owner, final NavController controller, final NavDirections directions) {
		final Observer<Long> observer = new OnChangedObserver<Long>(showSubFragment.getValue()) {
			@Override
			public void onChangedValue(@Nullable Long value) {
				controller.navigate(directions);
			}
		};
		owner.getLifecycle().addObserver(new LifecycleObserver() {
			@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
			void onStop() {
				showSubFragment.removeObserver(observer);
			}
		});
		showSubFragment.observe(owner, observer);
	}
}
```

```MainFragment.java
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
	super.onActivityCreated(savedInstanceState);

	// MainFragmentはSubFragmentと繋がっているのでShareViewModelに登録します
	ShareViewModel.get(this).setOnShowSubFragment(this, Navigation.findNavController(Objects.requireNonNull(getView())), MainFragmentDirections.actionMainFragmentToSubFragment());
}
```

```HomeFragment.java
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
	super.onActivityCreated(savedInstanceState);

	getBinding().test.setOnClickListener(new View.OnClickListener() {
		@Override
		public void onClick(View v) {
			// SubFragmentを開きたいのでShareViewModel.showSubFragmentをコールします
			ShareViewModel.get(HomeFragment.this).showSubFragment();
		}
	});
}
```

以上、Navigationのサンプルでした。詳しい人がいましたら、突っ込みお願いします。