当前位置: 首页 > 知识库问答 >
问题:

使用共享ViewModel将FireStore数据提取为两个片段的有效方法

盖高畅
2023-03-14

上下文:我有一个User类,看起来像这样:

public class User {
    private String firstname;
    private String lastname;
    private GeoPoint location;
    
    /* Constructor and getters */
    ...
}

还有两个片段s,在其中我将使用RecyclerViewGoogleMap在第一个片段中显示用户名列表,后者显示第二个片段中用户的设备位置标记。我在这两个片段之间使用共享的ViewModel,以提供所需的数据。ViewModel如下所示:

@HiltViewModel
public class UsersViewModel extends ViewModel {

    private List<User> users;
    private UserRepository repository;

    @Inject
    public UsersViewModel(UserRepository repository) {
        this.repository = repository;
    }

    public void fetchUsers(OnFetchDataCallback callback) {
        repository.getUsers(callback); 
    }

    public void setUsers(List<User> users) {
        this.users = users;
    }

    public List<User> getUsers() {
        return users;
    }
}

在我的资源库课上,

public class UserRepository {

    private final FirebaseFirestore db;

    @Inject
    public UserRepository(FirebaseFirestore db) {
        this.db = db;
    }

    public List<User> getUsers(OnFetchDataCallback callback) {
        db.collection("users")
            .addSnapshotListener(new EventListener<QuerySnapshot>() {
                @Override
                public void onEvent(@Nullable QuerySnapshot val,
                                    @FirebaseFirestoreException e) {
                    List<User> users = new ArrayList<>();
    
                    for (QueryDocumentSnapshot document : val) {
                        users.add(document.toObject(User.class);
                    }
                    callback.onFetchData(users);
                }
            });
    }
}

我有一个名为getUsers()的方法,可以从firestore数据库中实际获取用户。我还创建了一个如下所示的接口回调

public interface OnFetchDataCallback {
    void onFetchData(List<User> users);
}

这样以后我就可以在我的两个片段中访问获取的用户。在我的第一个片段中,

@AndroidEntryPoint
public class DisplayUsersFragment extends Fragment {
    private FragmentDisplayUsersBinding binding;
    private UsersViewModel viewModel;
    private UsersAdapter adapter;

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

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater,
                             @Nullable ViewGroup container,
                             @Nullable Bundle savedInstanceState) {
        binding = FragmentDisplayUsersBinding.inflate(inflater, container, false);
        binding.usersRecyclerView.setLayoutManager(
            new LinearLayoutManager(getContext()));

        viewModel.fetchUsers(new OnFetchDataCallback() {
            @Override
            public void onFetchData(List<User> users) {
                viewModel.setUsers(users);
                adapter = new UsersAdapter(viewModel.getUsers());
                binding.usersRecyclerView.setAdapter(adapter);
            }
        });
        return binding.getRoot();
    }
}

我调用了fetchUsers(),访问了回调中users列表,并将其设置为myviewModelusers,然后为myRecyclerView构建了一个适配器,并通过调用viewModel>为其提供了所需的数据。getUsers()并将其作为适配器的构造函数参数传递。现在,我的问题是,在我的第二个片段中,

@AndroidEntryPoint
public class UsersMapFragment extends Fragment implements OnMapReadyCallback {

    private FragmentUsersMapBinding binding;
    private UsersViewModel viewModel;

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

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater,
                             @Nullable ViewGroup container,
                             @Nullable Bundle savedInstanceState) {
        binding = FragmentUsersMapBinding.inflate(inflater, container, false);
        return binding.getRoot();
    }

    @Override
    public void onViewCreated(@NonNull View view,
                              @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        SupportMapFragment mapFragment = SupportMapFragment.newInstance();
        getChildFragmentManager().beginTransaction()
            .add(R.id.users_map_fragment_container, mapFragment)
            .commit()
        mapFragment.getMapAsync(this);
    }

    @Override
    public void onMapReady(@NonNull GoogleMap googleMap) {
         viewModel.fetchUsers(new OnFetchDataCallback() {
            @Override
            public void onFetchData(List<User> users) {
                viewModel.setUsers(users);
                for (User user : viewModel.getUsers()) {
                    googleMap.addMarker(new MarkerOptions()
                                .position(new LatLng(
                                    user.getLocation().getLatitude(),
                                    user.getLocation().getLongitude())
                                )
                                .title(user.getFirstname() + " " 
                                       user.getLastname()
                                )
                            );
                }
            }
        });
    }
}

我再次调用了fetchUser()内部onMap就绪(),以便我可以访问其回调内部的用户,并使用它们在映射中创建标记。本质上,我尝试调用fetchUser()两次,但我认为有一种更有效的方法可以做到这一点,但我不知道如何处理。请帮帮我,对不起,我的英语不好。


共有1个答案

郜俊晤
2023-03-14

您可以在ViewModel中使用实时数据:请参阅下面给出的代码:

@HiltViewModel
public class UsersViewModel extends ViewModel {

    private List<User> users;
    MutableLiveData<List<User>> usersLiveData = new MutableLiveData();
    private UserRepository repository;

    @Inject
    public UsersViewModel(UserRepository repository) {
        this.repository = repository;
    }

    public void fetchUsers() {
        repository.getUsers(new OnFetchDataCallback() {
            @Override
            public void onFetchData(List<User> users) {
            usersLiveData.setValue(users);
            // you can observe this data after calling fetch users from your activity
            setUsers(users);
}); 
    }

    public void setUsers(List<User> users) {
        this.users = users;
    }

    public List<User> getUsers() {
        return users;
    }
}

在活动中:

mViewModel.fetchUsers();

在这两个片段中:

viewModel.usersLiveData.observe(this,{ list->
   // user your list here in both fragments
   // rather than fetch users on both fragments
});
 类似资料:
  • 好吧,正如我试图在标题中总结的那样,下面是细节。 我们有一个相对较大的应用程序,它使用Dagger,以非常不理想的方式,所以我们决定开始编写测试,为此,我需要公开Mockito的依赖项,因此,我面临一个问题,开始使用单例工厂提供视图模型,仍然适用,并且有大量的教程可以解释这一点。 在我们的应用程序中,有许多使用单个活动实现的功能和导航组件,该单个活动有时具有创建的视图模型,我们使用该模型在容器活动

  • 在上一次谷歌IO上,谷歌发布了一些新arch组件的预览,其中之一是ViewModel。 在文档中,谷歌展示了该组件的一个可能用途: 一个活动中的两个或多个片段需要相互通信是很常见的。这绝不是小事,因为两个片段都需要定义一些接口描述,所有者活动必须将两者绑定在一起。此外,两个片段都必须处理另一个片段尚未创建或不可见的情况。 这个常见的痛点可以通过使用ViewModel对象来解决。想象一个主细节片段的

  • 我有一个包含两个片段的FragmentActivity(support-v4)。并且都包含一个带有ActionBar的SearchView的菜单。 PlayListFragment: 附注。 我找到了原因,但没有解决方法: 呼叫 如何禁用ActionBar/SearchView/TextView的保存和还原?

  • 我需要观察Modelview中的livedata更改来更新片段(将列表添加到RecycerView中)。 该实现工作正常,但在片段之间切换时面临问题。 并试图将观察者移除为:或或或尝试在

  • 我有一个包含一个活动和两个片段的应用程序,在第一个片段中,我应该能够将数据插入数据库,在第二个片段中,我应该能够在一个RecyclerView中看到添加的项目。 所以我已经创建了数据库、我的RecyclerView适配器和ViewModel, 我是否应该在活动中初始化ViewModel,并以某种方式从片段中调用它来使用insert? 我是否应该在两个片段中初始化viewmodel两次? 我的代码如

  • 问题内容: 我的GUI中有多个组合框,所有组合框都需要数据。此数据将随机更改,因此需要一种快速的方法来保持所有值同步。我遇到了DefaultComboBoxModel,它实际上非常合适。唯一的事情是,我需要组合框彼此独立- 意思是:如果我在一个上选择一个值,则所有其他框都不应更改。我做了一些研究,并阅读了标准的Java教程,但没有一个告诉我如何使用DefaultComboBoxModel来实现这一