Search code examples
androidandroid-fragmentsandroid-databinding

Android DataBinding method called from ViewModel is not executed with onClick in fragment


I want to call a Method from my ViewModel Class with onClick(), but the call is just not executed. DataBinding is working fine otherwise.

android:onClick="@{() -> ViewModel.test()}"

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/androidxmlns:bind="http://schemas.android.com/apk/res-auto"
    xmlns:card_view="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools">

    <data>

        <variable
            name="Project"
            type="de.umr.studipro3000.model.Project" />

        <variable
            name="ViewModel"
            type="de.umr.studipro3000.viewmodel.ProjectOverviewViewModel" />
    </data>



        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:clickable="true"
            android:focusable="true"
            android:background="?attr/selectableItemBackground"
            android:onClick="@{() -> ViewModel.test()}"
            android:padding="8dp">

            <TextView
                android:id="@+id/text_view_projectName"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@{Project.name}"
                android:textAppearance="@style/TextAppearance.AppCompat.Large" />
        </RelativeLayout>


</layout>

Strange thing is, this is executed just fine.

android:onClick="@{() -> System.out.println(Project.name)}"

<data>

    <variable
        name="Project"
        type="de.umr.studipro3000.model.Project" />

    <variable
        name="ViewModel"
        type="de.umr.studipro3000.viewmodel.ProjectOverviewViewModel" />
</data>



    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:clickable="true"
        android:focusable="true"
        android:background="?attr/selectableItemBackground"
        android:onClick="@{() -> System.out.println(Project.name)}"
        android:padding="8dp">

        <TextView
            android:id="@+id/text_view_projectName"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{Project.name}"
            android:textAppearance="@style/TextAppearance.AppCompat.Large" />
    </RelativeLayout>

This is the ViewModel:

public class ProjectOverviewViewModel extends ViewModel {
  private Repository repository;
  private AuthService authService;

  private MutableLiveData<List<Project>> projectsLiveData;

  private String errorMessage;

  private ProjectOverViewNavigator navigator;

  public void setNavigator(ProjectOverViewNavigator navigator) {
    this.navigator = navigator;
  }

  public ProjectOverviewViewModel() {
    this.repository = Repository.getInstance();
    this.authService = AuthService.getInstance();
    this.errorMessage = "";
    projectsLiveData = new MutableLiveData<>();
    handleResponse(repository.projects((authService.currentToken.getValue())));
  }

  private void handleResponse(LiveData<ProjectListResponse> projectListResponseLiveData) {
    projectListResponseLiveData.observeForever(
        projectListResponse -> {
          ProjectListSuccessResponse projectListSuccessResponse =
              projectListResponse.getProjectListSuccessResponse();

          if (projectListSuccessResponse != null) {
            projectsLiveData.setValue(projectListSuccessResponse.getResult());
            System.out.println(projectsLiveData.getValue().toString());
          } else {
            errorMessage = projectListResponse.getErrorResponse().getError();
          }
        });
  }

  public void itemClick(Project project) {
    System.out.println("CLICKED");
    navigator.onItemClick(project);
  }

  public void test(){
    System.out.println("TEST");
  }

  public MutableLiveData<List<Project>> getProjectsLiveData() {
    return projectsLiveData;
  }

  public void setProjectsLiveData(MutableLiveData<List<Project>> projectsLiveData) {
    this.projectsLiveData = projectsLiveData;
  }

  public String getErrorMessage() {
    return errorMessage;
  }

  public void setErrorMessage(String errorMessage) {
    this.errorMessage = errorMessage;
  }
}

This is my Fragment

public class projectOverviewFragment extends Fragment implements ProjectOverViewNavigator {

  private ProjectOverviewViewModel viewModel;
  private ProjectAdapter adapter;
  private FragmentProjectOverviewBinding binding;
  private NavController navController;

  @Override
  public void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    viewModel = new ViewModelProvider(this).get(ProjectOverviewViewModel.class);
    viewModel.setNavigator(this);
    adapter = new ProjectAdapter();
  }

  @Nullable
  @Override
  public View onCreateView(
      @NonNull LayoutInflater inflater,
      @Nullable ViewGroup container,
      @Nullable Bundle savedInstanceState) {
    super.onCreateView(inflater, container, savedInstanceState);
    binding = FragmentProjectOverviewBinding.inflate(inflater, container, false);
    binding.setProjectOverviewViewModel(viewModel);
    binding.setLifecycleOwner(this);


    RecyclerView recyclerView = binding.recyclerViewProjects;
    recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
    recyclerView.setAdapter(adapter);

    binding.getProjectOverviewViewModel().test();

    return binding.getRoot();
  }

  @Override
  public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);
    navController = Navigation.findNavController(view);

    viewModel
        .getProjectsLiveData()
        .observe(getViewLifecycleOwner(), projects -> adapter.setProjects(projects));
  }

  public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
    super.onCreateContextMenu(menu, v, menuInfo);
    MenuInflater inflater = getActivity().getMenuInflater();
    inflater.inflate(R.menu.setting_menu, menu);
  }

  @Override
  public boolean onContextItemSelected(MenuItem item) {
    /*case R.id.first_action:
        // your first action code
        return true;
    case R.id.second_action:
        // your second action code
     */
    return true;
  }


  @Override
  public void onItemClick(Project project) {
    System.out.println(project.getDescription());

  /*  projectOverviewFragmentDirections.ActionProjectOverviewFragmentToProjectDetailsFragment action =
        projectOverviewFragmentDirections.actionProjectOverviewFragmentToProjectDetailsFragment(
            project.getId());

    navController.navigate(action);*/
  }
}

Solution

  • I had to do the Databinding of the Viewmodel for the individual Listitem in the Project Adapter. The VieModel of the ProjectAdapter is set in the Fragment.

    public class ProjectAdapter extends RecyclerView.Adapter<ProjectAdapter.ProjectViewHolder> {
      private ProjectOverviewViewModel viewModel;
    
      public void setProjects(List<Project> projects) {
        this.projects = projects;
        notifyDataSetChanged();
      }
    
      public void setViewModel(ProjectOverviewViewModel viewModel) {
        this.viewModel = viewModel;
      }
    
      public static class ProjectViewHolder extends RecyclerView.ViewHolder {
        private ProjectItemBinding projectItemBinding;
    
        public ProjectViewHolder(@NonNull ProjectItemBinding projectItemBinding) {
          super(projectItemBinding.getRoot());
          this.projectItemBinding = projectItemBinding;
        }
      }
    
      private List<Project> projects = new ArrayList<>();
    
      @NonNull
      @Override
      public ProjectViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        ProjectItemBinding projectItemBinding =
            DataBindingUtil.inflate(
                LayoutInflater.from(parent.getContext()), R.layout.project_item, parent, false);
    
        return new ProjectViewHolder(projectItemBinding);
      }
    
      @Override
      public void onBindViewHolder(@NonNull ProjectViewHolder holder, int position) {
        Project currentProject = projects.get(position);
        holder.projectItemBinding.setProject(currentProject);
        holder.projectItemBinding.setProjectOverviewViewModel(viewModel);
      }
    
      @Override
      public int getItemCount() {
        return projects.size();
      }
    }
    
    public View onCreateView(
          @NonNull LayoutInflater inflater,
          @Nullable ViewGroup container,
          @Nullable Bundle savedInstanceState) {
        super.onCreateView(inflater, container, savedInstanceState);
        binding = FragmentProjectOverviewBinding.inflate(inflater, container, false);
        binding.setLifecycleOwner(this);
        binding.setProjectOverviewViewModel(viewModel);
    
        RecyclerView recyclerView = binding.recyclerViewProjects;
        recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
        recyclerView.setHasFixedSize(true);
        adapter.setViewModel(viewModel);
        recyclerView.setAdapter(adapter);
    
        return binding.getRoot();
      }