#android #android-fragments #android-recyclerview #observer-pattern
#Android #android-фрагменты #android-recyclerview #наблюдатель-шаблон
Вопрос:
Я создаю медиа-приложение для Android и пытаюсь добавить к нему функцию плейлиста, пользователь сможет создать собственный плейлист и изменить его.
Я использую RecyclerView, чтобы показать пользователю список песен, из которых он может выбирать. Проблема в том, что я не понимаю, как передать Arraylist выбранных песен из адаптера во фрагмент. Я пытался использовать шаблон Observer, но не знаю, как использовать эту информацию.
Это мой фрагмент для создания списка воспроизведения:
public class CreatePlaylistFragment extends Fragment implements PlaylistAdapterInterface {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_create_playlist, container, false);
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
ArrayList<ProgramsData> dataArrayList = ProgramsReceiver.getPrograms();
ArrayList<ProgramsData> sortedList = new ArrayList<>(dataArrayList);
adapter = new CreatePlaylistAdapter(dataArrayList, view.getContext(), this);
adapter.adapterInterface = this;
ivCreatePlaylist.setOnClickListener(v -> {
Toast.makeText(v.getContext(), "Creating Playlist!", Toast.LENGTH_SHORT).show();
new PlaylistsJsonWriter(playlistArrayList,getContext()).execute();
});
}
@Override
public void OnItemClicked(ArrayList<ProgramsData> programs) {
programsToCreate = programs;
String s = etListName.getText().toString();
playlistArrayList.add(new Playlist(s, programsToCreate));
}
}
Это адаптер Recycler с ViewHolder в качестве внутреннего класса:
public class CreatePlaylistAdapter extends RecyclerView.Adapter<CreatePlaylistViewHolder> {
List<ProgramsData> programsDataList;
Context context;
public PlaylistAdapterInterface adapterInterface = null;
public CreatePlaylistAdapter(List<ProgramsData> programsDataList, Context context , PlaylistAdapterInterface adapterInterface) {
this.programsDataList = programsDataList;
this.context = context;
this.adapterInterface = adapterInterface;
}
@NonNull
@Override
public CreatePlaylistViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
LayoutInflater inflater = LayoutInflater.from(context);
View view = inflater.inflate(R.layout.chose_program_to_playlist_item, viewGroup, false);
return new CreatePlaylistViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull CreatePlaylistViewHolder holder, int i) {
ProgramsData programsData = programsDataList.get(i);
holder.tvProgramName.setText(programsData.getProgramName());
if (programsData.getStudentName() != null)
holder.tvStudentName.setText(programsData.getStudentName());
else holder.tvLine.setText(""); //if there is no student the line won't be printed
holder.ivProfilePic.setImageResource(programsData.getProfilePic());
holder.programsData = programsData;
// holder.mAdapterInterface = adapterInterface;
adapterInterface.OnItemClicked(holder.programs);
}
@Override
public int getItemCount() {
return programsDataList.size();
}
}
class CreatePlaylistViewHolder extends RecyclerView.ViewHolder {
TextView tvProgramName;
TextView tvStudentName;
TextView tvLine;
CircleImageView ivProfilePic;
ToggleButton tbCheck;
ProgramsData programsData;
ArrayList<ProgramsData> programs;
PlaylistAdapterInterface mAdapterInterface;
public CreatePlaylistViewHolder(@NonNull View itemView) {
super(itemView);
tvProgramName = itemView.findViewById(R.id.tvProgramName);
tvStudentName = itemView.findViewById(R.id.tvStudentName);
ivProfilePic = itemView.findViewById(R.id.ivProfilePic);
tvLine = itemView.findViewById(R.id.tvLine);
tbCheck = itemView.findViewById(R.id.tbCheck);
programs= new ArrayList<>();
tbCheck.setOnClickListener(v -> {
if (tbCheck.isChecked()) {
tbCheck.setBackgroundResource(R.drawable.ic_radio_button_checked);
programs.add(programsData);
} else if (!tbCheck.isChecked()) {
tbCheck.setBackgroundResource(R.drawable.ic_check);
programs.remove(programsData);
}
});
}
}
И это интерфейс для шаблона наблюдателя:
public interface PlaylistAdapterInterface {
void OnItemClicked(ArrayList<ProgramsData> programs);
}
Я знаю, что это много кода, но я просто не понимаю, как передать данные из адаптера обратно во фрагмент…
Комментарии:
1. Какова область действия Arraylist объектов? Вы хотите получить к нему доступ из класса view holder
Ответ №1:
Я не совсем понимаю, что вы пытаетесь сделать. Код содержит несколько ошибок, которые я попытаюсь объяснить.
Явная ошибка, которую вы допустили, остается в onBindViewHolder, где вы вызываете слушателя при создании каждого элемента, а не после нажатия на него. Вам нужно просто добавить OnClickListener в ViewHolder.getItemView() или в определенном представлении viewholder, а затем выполнить операцию, которую вам нужно выполнить при нажатии на элемент. Если вы установите прослушиватель внутри onBindViewHolder, у вас также есть метод с именем holder.getAdapterPosition(), который вы можете использовать, чтобы понять, на какой элемент вы нажимаете.
Viewholder следует использовать только для настройки представлений в соответствии с данными, которые вы привязываете, и ничего больше. По этой причине вы не должны передавать ему какой-либо объект или прослушиватель, а вместо этого использовать описанный выше подход.
Если вам нужно просто получить выбранные песни после подтверждения пользователем списка воспроизведения, вы можете просто добавить общедоступный метод в свой адаптер
public List<ProgramsData> getSelectedSongs()
который вы можете вызвать из своего фрагмента, когда пользователь нажимает кнопку подтверждения.
Чтобы иметь список всех выбранных песен, у вас может быть другой список
ArrayList<ProgramsData> selectedPrograms;
который вы собираетесь заполнить после щелчка.
Содержимое прослушивателя внутри onBindViewHolder может быть
ProgramsData currentProgram = programs.get(holder.getAdapterPosition());
if(selectedPrograms.contains(currentProgram){
selectedPrograms.remove(currentProgram);
}else{
selectedPrograms.add(currentProgram);
}
notifyItemChanged(holder.getAdapterPosition); //You can use this to update the view of the selected item
Затем внутри onBindViewHolderMethod вы можете проверить, являются ли элементы, которые вы привязываете, частью selectedList, и соответствующим образом обновить представления.
Ответ №2:
Вы можете использовать метод обратного вызова. Сохраняйте список выбранных элементов в списке массивов и отправляйте обратно во фрагмент при нажатии кнопки «Готово» или любой другой кнопки, которую вы разместили для завершения действия. Выполните следующие действия
-Создайте интерфейс с параметром list.
-Фрагмент должен реализовывать этот интерфейс.
-Затем, когда вы инициализируете адаптер Recyclerview, передайте этот объект интерфейса.
-Когда нажата кнопка «Готово», вызовите переопределенный метод этого интерфейса и отправьте список выбранных песен в качестве аргумента.