님의 에러의 원인은 로그에도 나와있듯이 널인 오브젝트의 insert메소드를 호출했기 때문입니다. WritingViewModel이 널인 상태에서 insert를 호출한 모양이네요. 아마 ViewModel 이 제대로 공유가 안된 것 같습니다.
하나의 액티비티에 프레그먼트를 여러개 사용할 때는 앱의 성능은 향상되지만, 복잡도는 증가합니다. 특히 백스택관리가 많이 복잡해집니다.
개인적으로는 왜 B의 입력값은 메인액티비티에 전달해서 저장하는지 좀 의아합니다. 코드의 복잡도가 증가하고 님의 경우처럼 발생하지 않았어야 할 에러가 발생하고 있으니까요. 저 같으면 처리하는 방식을 바꿀 것 같습니다.
실제 저장하는 동작을 B에서 처리한 후 처리결과만 A에 전달해주고, A는 성공일 경우만 화면을 다시 갱신하는 거죠. 성공이 아닐경우는 저장된 값을, ViewModel에 캐쉬됭 현재 리스트를 다시 복구해줍니다. 제 기억으로는 프레그먼트의 replace를 사용하실 경우는 다른 프레그먼트로 이동한 후 돌아오는 경우 프레그먼트가 초기화됩니다. 이걸 원하는게 아니면 백스택에 add한 후 show/hide로 처리하시면 됩니다.
B에서 저장을 하는 주된 이유는 에러 처리와 플로우의 복잡함을 줄이기 위해서입니다. 먼저, 에러처리의 경우 님의 예처럼, B에서 입력한 데이터를 A에서 처리하다 에러가 발생할 경우, 에러메세지를 보여주기 위해서는 B프레그먼트를 다시 띄워야 합니다. 그래야 사용자가 입력값을 수정하거나 한 후 다시 시도해 볼 수 있으니까요. 그리고 저장을 하는 동작은 화면의 흐름상 A프레그먼의 역할이 아닙니다. 이렇게 분리하면 굳이 ViewModel을 공유할 필요가 없습니다.
저도 MVVM를 주로 사용하고 있는 개인적은 ViewModel을 공유하는 방법은 초기에는 좀 사용했다가 다 리팩토링했습니다. 나중에 가면, 코드를 파악하기가 ViewModel을 화면당 하나씩 쓰는 것보다 훨씬 어렵더군요. 물론 코드가 아주 짧다면 전혀 상관이 없지만, 저같은 경우는 대부분의 화면이 복잡했기 때문에 이 방법은 적합하지 않았습니다. 그리고 ViewModel을 공유한다는 아이디어 자체가 서로의 의존관계를 증가시키기 때문에 분리할 수 있으면 분리하는게 더 깔끔하다고 생각합니다. 님의 경우는 TODO는 저장공간에 저장해서 이 저장소를 공유하면 되기 때문에 굳이 ViewModel 을 공유할 필요가 없다고 보여집니다.
프레그먼트 간에 통신은 여러가지 방법으로 가능합니다. 개발자 사이트에 자세히 나와있구요.
https://developer.android.com/guide/fragments/communicate
저같은 경우는 네비게이션 컴포넌트를 쓰기 때문에 백스택에 saveSate의 liveData를 통해 하고 있습니다.