使用共享 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
并将其设置为我的 viewModel
的 users
我的 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()
以便我可以在其回调中访问用户并使用它们在地图中创建标记。本质上,我尝试调用 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;
}
}
在activity中:
mViewModel.fetchUsers();
并且在两个片段中:
viewModel.usersLiveData.observe(this,{ list->
// user your list here in both fragments
// rather than fetch users on both fragments
});
上下文:我有一个 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
并将其设置为我的 viewModel
的 users
我的 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()
以便我可以在其回调中访问用户并使用它们在地图中创建标记。本质上,我尝试调用 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;
}
}
在activity中:
mViewModel.fetchUsers();
并且在两个片段中:
viewModel.usersLiveData.observe(this,{ list->
// user your list here in both fragments
// rather than fetch users on both fragments
});