[英]How to update recyclerview based on spinner selection MVVM + LiveData
I have an Android app (Java) that uses MVVM + LiveData to display a list of shows by season.我有一个 Android 应用程序(Java),它使用 MVVM + LiveData 按季节显示节目列表。 I want season 1 titles to display in a RecyclerView when the user first lands on the fragment.当用户第一次登陆片段时,我希望第 1 季的标题显示在 RecyclerView 中。 I then want the user to be able to select another season and then display those titles.然后我希望用户能够 select 另一个赛季然后显示这些标题。 I'm able to send the selected season to my ViewModel, but I don't know how to update my RecyclerView with the selected season's titles.我可以将所选季节发送到我的 ViewModel,但我不知道如何使用所选季节的标题更新我的 RecyclerView。 Any help is greatly appreciated!任何帮助是极大的赞赏!
Here is my fragment:这是我的片段:
public class ShowFragment extends Fragment {
private ShowTitlesAdapter showTitlesAdapter;
private ArrayList<Titles> titlesList;
private FragmentShowBinding binding;
private TitlesViewModel titlesViewModel;
private String ShowTag, ShowTitle, ShowImgUrl;
private RecyclerView rvTitles;
private Spinner popupSpinner;
public ShowFragment() {
// Required empty public constructor
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
binding = FragmentShowBinding.inflate(inflater, container, false);
View view = binding.getRoot();
return view;
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
titlesList = new ArrayList<>();
titlesViewModel = new ViewModelProvider(this).get(TitlesViewModel.class);
initAdapter();
init();
ShowFragmentArgs args = ShowFragmentArgs.fromBundle(getArguments());
ShowTag = args.getFranchiseTag();
titlesViewModel.getAllTitles(ShowTag);
ShowImgUrl = args.getShowImg();
ShowTitle = args.getShowTitle();
titlesViewModel.getAllTitles(ShowTitle);
binding.showTitle.setText(ShowTitle);
Drawable placeHolder = getResources().getDrawable(R.drawable.placeholder_1080x1080);
Glide.with(getContext())
.load(ShowImgUrl) //image url
.placeholder(placeHolder)
.into(binding.showImage);
}
private void initAdapter() {
binding.rvTitles.setLayoutManager(new LinearLayoutManager(getContext()));
showTitlesAdapter = new ShowTitlesAdapter(getContext(), titlesList);
binding.rvTitles.setAdapter(showTitlesAdapter);
}
private void init() {
titlesList.clear();
titlesViewModel.sortedSeasonListOne.observe(getViewLifecycleOwner(), new Observer<List<Titles>>() {
@Override
public void onChanged(List<Titles> titles) {
titlesList.addAll(titles);
showTitlesAdapter.setShowTitlesList(titlesList);
}
});
titlesViewModel.getAllTitles(ShowTag);
createDropDownList(titlesList);
}
public void createDropDownList(ArrayList<Titles> titles) {
List<String> seasonListStr = new ArrayList<>();
titlesViewModel.seasonsStrList.observe(getViewLifecycleOwner(), new Observer<List<String>>() {
@Override
public void onChanged(List<String> seasons) {
seasonListStr.addAll(seasons);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
seasonListStr.replaceAll(s -> "Season " + s);
}
ArrayAdapter<String> adapter = new ArrayAdapter<String>(getContext(), android.R.layout.simple_list_item_1, seasonListStr);
adapter.setDropDownViewResource(android.R.layout.simple_list_item_1);
binding.popupSpinner.setAdapter(adapter);
binding.popupSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long l) {
titlesViewModel.populateTitlesInSeason(parent.getItemAtPosition(position).toString());
// showTitlesAdapter.setShowTitlesList(titlesList); --> I don't know how to update this list with another season of titles!
}
@Override
public void onNothingSelected(AdapterView<?> adapterView) {
}
});
binding.popupSpinner.setAdapter(adapter);
}
});
}
@Override
public void onDestroyView() {
super.onDestroyView();
binding = null;
}
}
ViewModel:视图模型:
public class TitlesViewModel extends ViewModel {
Repository repository;
private final io.reactivex.rxjava3.disposables.CompositeDisposable disposables = new CompositeDisposable();
public MutableLiveData<ArrayList<Titles>> titlesListLiveData;
public List<String> seasonsList;
public LiveData<List<Titles>> sortedList;
public LiveData<List<Titles>> sortedSeasonListOne;
public LiveData<List<Titles>> sortedSeasonListSeason;
public LiveData<List<Integer>> seasons;
public LiveData<List<String>> seasonsStrList;
@Inject
public TitlesViewModel(Repository repository) {
this.repository = repository;
titlesListLiveData = repository.getTitlesLiveData();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
sortedList = Transformations.map(titlesListLiveData, titlesList -> titlesList.stream().sorted(Comparator.comparing(Titles::getSeasonNumber).thenComparing(Titles::getEpisodeNumber)).collect(Collectors.toList()));
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
seasons = Transformations.map(sortedList, list -> list.stream().map(Titles::getSeasonNumber).distinct().collect(Collectors.toList()));
seasonsStrList = Transformations.map(seasons, strList -> strList.stream().map(Object::toString).collect(Collectors.toList()));
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
sortedSeasonListOne = Transformations.map(titlesListLiveData, srtList -> srtList.stream().sorted(Comparator.comparing(Titles::getSeasonNumber).thenComparing(Titles::getEpisodeNumber)).filter(list ->1 == list.getSeasonNumber()).collect(Collectors.toList()));
}
}
public void populateTitlesInSeason(String season) {
String seasonNo = season.substring(7);
int seasonNum = 1;
try{
seasonNum = Integer.parseInt(seasonNo);
}catch(NumberFormatException ex){
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
int finalSeasonNum = seasonNum;
sortedSeasonListSeason = Transformations.map(titlesListLiveData, seasonList -> seasonList.stream().sorted(Comparator.comparing(Titles::getSeasonNumber).thenComparing(Titles::getEpisodeNumber)).filter(list -> finalSeasonNum == list.getSeasonNumber()).collect(Collectors.toList()));
}
}
/////////Titles
public void getAllTitles(String tag) {
repository.getAllTitles(tag);
}
@RequiresApi(api = Build.VERSION_CODES.N)
public MutableLiveData<ArrayList<Titles>> getTitlesListLiveData() {
return repository.getTitlesLiveData();
}
@Override
protected void onCleared() {
super.onCleared();
disposables.clear();
}
}
Repository:存储库:
public class Repository {
final ApiService apiService;
private final MutableLiveData<ArrayList<Titles>> titlesList = new MutableLiveData<>();
@Inject
public Repository(ApiService service){this.apiService = service;}
public void getAllTitles(String tag){
apiService.getTitles(tag).enqueue(new Callback<ArrayList<Titles>>() {
@Override
public void onResponse(Call<ArrayList<Titles>> call, Response<ArrayList<Titles>> response) {
if (response.body() != null) {
titlesList.postValue(response.body());
}
}
@Override
public void onFailure(Call<ArrayList<Titles>> call, Throwable t) {
Log.d("Titles","onFailure"+Thread.currentThread().getName());
}
});
}
public MutableLiveData<ArrayList<Titles>> getTitlesLiveData(){
return titlesList;
}
}
RecyclerView Adapter: RecyclerView 适配器:
public class ShowTitlesAdapter extends RecyclerView.Adapter<ShowTitlesAdapter.ShowTitlesViewHolder> {
private ItemShowTitleBinding binding;
private ArrayList<Titles> showTitles;
private Context context;
int pos;
public ShowTitlesAdapter(Context context, ArrayList<Titles> showTitles){
this.context = context;
this.showTitles = showTitles;
}
@NonNull
@Override
public ShowTitlesViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(context);
binding = ItemShowTitleBinding.inflate(inflater, parent, false);
return new ShowTitlesViewHolder(binding);
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
@Override
public void onBindViewHolder(@NonNull ShowTitlesViewHolder holder, int position) {
holder.binding.showTitleLayout.setClipToOutline(true);
holder.binding.episodeNo.setText(Integer.toString(showTitles.get(position).getEpisodeNumber()));
holder.binding.episodeTitle.setText(showTitles.get(position).getTitle());
pos = position;
holder.binding.showTitleLayout.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
ShowFragmentDirections.ActionShowFragmentToMovieShowDetailFragment action =
ShowFragmentDirections.actionShowFragmentToMovieShowDetailFragment(showTitles.get(position).getId(), showTitles.get(position).getFranchiseTag());
Navigation.findNavController(v).navigate((NavDirections) action);
}
});
}
@Override
public int getItemCount() {
if(showTitles != null){
return showTitles.size();
}
return 0;
}
public class ShowTitlesViewHolder extends RecyclerView.ViewHolder {
private ItemShowTitleBinding binding;
public ShowTitlesViewHolder(ItemShowTitleBinding binding) {
super(binding.getRoot());
this.binding = binding;
}
}
public void setShowTitlesList(ArrayList<Titles> showTitles){
this.showTitles = showTitles;
notifyDataSetChanged();
}
}
In short:简而言之:
ShowFragment
you need to observe sortedSeasonListSeason
of your TitlesViewModel
在ShowFragment
中,您需要观察sortedSeasonListSeason
的TitlesViewModel
populateTitlesInSeason
(you already do it)当您收到具体季节时,您应该将其传递给populateTitlesInSeason
(您已经这样做了)populateTitlesInSeason
method you should pass your sortedSeasonListSeason
list back to ShowFragment
via MutableLiveData
在populateTitlesInSeason
方法中,您应该通过MutableLiveData
将sortedSeasonListSeason
列表传回ShowFragment
MutableLiveData
for sortedSeasonListSeason
list in TitlesViewModel
to pass selected data, for example sortedSeasonListSeasonLiveData
所以你需要在TitlesViewModel
中为sortedSeasonListSeason
列表创建MutableLiveData
以传递选定的数据,例如sortedSeasonListSeasonLiveData
sortedSeasonListSeasonLiveData.postValue(sortedSeasonListSeason)
所以你只需要sortedSeasonListSeasonLiveData.postValue(sortedSeasonListSeason)
ShowFragment
and handle received list of concrete titles in observer from stage #1 of my instruction现在回到ShowFragment
并从我的指令的第 1 阶段处理观察者中收到的具体标题列表
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.