簡體   English   中英

使用共享 ViewModel 將 FireStore 數據提取到兩個片段中的有效方法

[英]Efficient way to fetch FireStore data into two fragments with a shared ViewModel

上下文:我有一個User class,如下所示:

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

和兩個Fragment ,其中我將使用RecyclerView在第一個片段中顯示用戶名列表,在第二個片段中使用GoogleMap顯示用戶設備位置的標記。 我在這兩個片段之間使用共享的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;
    }
}

在我的存儲庫 class 中,

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 List ,並將其設置為我的viewModelusers ,然后為我的RecyclerView構建了一個適配器,並通過調用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()
                                )
                            );
                }
            }
        });
    }
}

我在 onMapReady() 中再次調用了fetchUsers() onMapReady()以便我可以在其回調中訪問用戶並使用它們在 map 中創建標記。本質上,我嘗試調用fetchUsers()兩次,但我認為有一個更有效的方法方法來做到這一點,但我不知道如何處理這個。 請幫助我,對不起我的英語不好。

您可以在 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
});

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM