Android MVVM fragmenty JAVA

0

Pisze drobną aplikacje androidową (jedno activity, 3-4 fragmenty) chciałem na niej nauczyć się MVVM... Męczę się już z tym sporo czasu i sporo przeczytałem. Nie bardzo wiem jak poradzić sobie z przesyłaniem danych między fragmentami i ogólnie zmianą fragmentów tworze w activity interfejs zmieniający fragmenty tylko nie wiem jak go przesłać do view modelu fragmentu. Jeśli tworze własny konstruktor fragmentu wyświetla żeby użyć bundle a przez bundle albo ja nie wiem jak przesłać interfejs albo się nie bardzo da... Proszę o wyrozumiałość i będę wdzięczny za jakiekolwiek porady...

0

Fragmenty mogą mieć tylko bezargumentowe konstruktory. Jeżeli chcesz przekazać jakieś dane typu ID wybranego produktu, to powinny być przekazane, jak zauważyłeś, w Bundle do metody setArguments. Obiekt służący do nawigacji, powinien być pobierany np. z Activity w odpowiednim momencie cyklu życia Fragmentu i raczej nie należy go pchać do ViewModelu.

Wklej jakiś minimalny przykład z dwoma Fragmentami, bo inaczej ciężko będzie poradzić coś konkretnego.

0
Michał Sikora napisał(a):

Fragmenty mogą mieć tylko bezargumentowe konstruktory. Jeżeli chcesz przekazać jakieś dane typu ID wybranego produktu, to powinny być przekazane, jak zauważyłeś, w Bundle do metody setArguments. Obiekt służący do nawigacji, powinien być pobierany np. z Activity w odpowiednim momencie cyklu życia Fragmentu i raczej nie należy go pchać do ViewModelu.

Wklej jakiś minimalny przykład z dwoma Fragmentami, bo inaczej ciężko będzie poradzić coś konkretnego.

Kod jest obecnie nieco rozgrzebany przez dziesiątki różnych moich prób i błędów a w zasadzie głównie błędów ale postaram się wydobyć co najważniejsze:

IFragMenager

public interface IFragMenager {
    void goMenu();
    void goResult(int points);
    void goGame();
}

MainActivity

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
                WindowManager.LayoutParams.FLAG_FULLSCREEN);
        setContentView(R.layout.activity_main);
        ButterKnife.bind(this);
        goMenu();
        }
    @Override
    public void goMenu() {
        MenuFragment newFragment = new MenuFragment ();
        FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
        transaction.replace(R.id.frame, newFragment);
        transaction.commit();
    }

    @Override
    public void goResult(int points) {
        //TODO: goResult
    }

    @Override
    public void goGame() {
        //TODO:goGame
    }
}

MenuFragment

public class MenuFragment extends Fragment{
    IFragMenager iFragMenager;
    MenuViewModel menuViewModel;
    
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        FragmentMenuBinding binding = DataBindingUtil.inflate(inflater,R.layout.fragment_menu,container,false);
        View view = binding.getRoot();
        ButterKnife.bind(this,view);
        //menuViewModel=MenuViewModel.getInstance();
        menuViewModel=new MenuViewModel();
        binding.setMenuViewModel(menuViewModel);
        
        return view;
    }

}

MenuViewModel


public class MenuViewModel extends BaseObservable{
    public void onClickGame(View view){
        Log.i("ML","GameClick");
    }
}

To takei co istotniejsze wycinki kodu mam nadzieje że nic istotnego nie pominąłem... I chodzi mi o to aby przycisk po naciśnięciu którego wykonuje się metoda onClickGame z MenuViewModel powodował zmianę fragmentu na inny w tym przypadku metoda goGame() z interfejsu.

1

Szczerze, to trochę kiepski przykład. ViewModel powineń służyć, żeby oddzielić logikę domenową od kontrolerów typu Fragment czy Activity i nie powinien zawierać referencji do klas androidowych takich jak View. Nawigacja pomiędzy ekranami należy jak najbardziej do warstwy widoku i tam powinna zostać.

Pomijając to, to w swoim przykładnie musiałbyś zrobić coś w tym stylu.

public class MenuFragment extends Fragment {
  @Override
  public View onCreateView(LayoutInflater inflater, ViewGroup parent, Bundle inState) {
    FragmentMenuBinding binding = DataBindingUtil.inflate(
        inflater,
        R.layout.fragment_menu,
        parent,
        false
    );
    IFragMenager fragmentManager = (IFragMenager) getActivity();
    MenuViewModel menuViewModel = new MenuViewModel(fragmentManager);
    binding.setMenuViewModel(menuViewModel);
    return binding.getRoot();
  }
}

public class MenuViewModel extends BaseObservable {
  private final IFragMenager fragmentManager;

  public MenuViewModel(IFragMenager fragmentManager) {
    this.fragmentManager = fragmentManager;
  }

  public void onClickGame(View view) {
    fragmentManager.goMenu();
  }
}

Ponieważ MainActivity implementuje interfejs IFragMenager, to musisz pobrać go we fragmencie i zrzutować na ten interfejs. Inaczej się w Twoim przykładzie nie da. Niesie to ze sobą trochę problemów, ale myślę, że w tej chwili nie powinny Cię one obchodzić. Aczkolwiek wydaje mi się, że ten przykład, to bardziej nauka nastawiona na DataBinding niż ViewModel.

1 użytkowników online, w tym zalogowanych: 0, gości: 1