Я новичок в Java-программировании для Android. Я использую MVVM, и у меня есть метод поиска в моем DAO. когда я использую этот метод для поиска чего-либо в recyclerview, он работает нормально, и я могу обновлять, удалять и нажимать на результат поиска. Однако после этого, если я попытаюсь отредактировать или удалить элемент напрямую, после того, как я нажму кнопку обновления или удаления, появится слово, которое я искал.
Ниже мой метод поиска в DAO.
@Query("SELECT * FROM vocabularytable WHERE Vocabulary LIKE '%' ||:vocabulary || '%' OR Definition LIKE '%' ||:vocabulary || '%'")
LiveData<List<Vocabulary>> search(String vocabulary);
Вот мой RecyclerViewAdapter
public class RecycleViewAdapter extends RecyclerView.Adapter<RecycleViewAdapter.VIewHolder> {
private final List<Vocabulary> vocabularyList; // Original list
private final List<Vocabulary> displayList; // List used for displaying
private final Context context;
private final onVocabularyClickListener onVocabularyClickListener;
public RecycleViewAdapter(List<Vocabulary> vocabularyList, Context context, onVocabularyClickListener onVocabularyClickListener) {
this.vocabularyList = vocabularyList;
this.displayList = new ArrayList<>(vocabularyList);
this.context = context;
this.onVocabularyClickListener = onVocabularyClickListener;
}
@NonNull
@Override
public RecycleViewAdapter.VIewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.activity_vocabulary, parent, false);
return new VIewHolder(view, onVocabularyClickListener);
}
@Override
public void onBindViewHolder(@NonNull RecycleViewAdapter.VIewHolder holder, int position) {
holder.vocabularyBind(displayList.get(position));
}
@Override
public int getItemCount() {
return displayList.size();
}
public class VIewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
private final AppCompatTextView tvVocabulary;
private final AppCompatTextView tvDefinition;
private final AppCompatImageButton imgBtnEdit;
private final AppCompatImageButton imgBtnDelete;
onVocabularyClickListener onVocabularyClickListener;
public VIewHolder(@NonNull View itemView, onVocabularyClickListener onVocabularyClickListener) {
super(itemView);
tvVocabulary = itemView.findViewById(R.id.tvVocabulary);
tvDefinition = itemView.findViewById(R.id.tvDefinition);
imgBtnEdit = itemView.findViewById(R.id.imgBtnEdit);
imgBtnDelete = itemView.findViewById(R.id.imgBtnDelete);
this.onVocabularyClickListener = onVocabularyClickListener;
itemView.setOnClickListener(this);
imgBtnEdit.setOnClickListener(this);
imgBtnDelete.setOnClickListener(this);
}
@Override
public void onClick(View v) {
if (v.getId() == R.id.imgBtnEdit) {
onVocabularyClickListener.onEditVocabularyClick(getAdapterPosition());
} else if (v.getId() == R.id.imgBtnDelete) {
onVocabularyClickListener.onDeleteVocabularyClick(getAdapterPosition());
} else {
onVocabularyClickListener.onVocabularyClick(getAdapterPosition());
}
}
public void vocabularyBind(Vocabulary vocabulary) {
tvVocabulary.setText(vocabulary.getVocabulary());
tvDefinition.setText(vocabulary.getDefinition());
}
}
public void filterList(List<Vocabulary> filteredList) {
displayList.clear();
displayList.addAll(filteredList);
notifyDataSetChanged();
}
public void resetList(List<Vocabulary> originalList) {
displayList.clear();
displayList.addAll(originalList);
notifyDataSetChanged();
}
public Vocabulary getVocabularyAtPosition(int position) {
return displayList.get(position);
}
public interface onVocabularyClickListener {
void onVocabularyClick(int position);
void onDeleteVocabularyClick(int position);
void onEditVocabularyClick(int position);
}
}
И вот MainActivity (я использую текст редактирования для поиска
Здесь я загружаю дада в recyclerview, когда открываю приложение (вызываю этот метод в onCreate
private void recyclerLoad() {
vocabularyViewModel = new ViewModelProvider.AndroidViewModelFactory(MainActivity.this.getApplication()).create(VocabularyViewModel.class);
vocabularyViewModel.getAllData.observe(this, vocabularies -> {
recycleViewAdapter = new RecycleViewAdapter(vocabularies, MainActivity.this, MainActivity.this);
recyclerView.setAdapter(recycleViewAdapter);
});
}
searchView.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
String query =s.toString();
if (!query.isEmpty()) {
vocabularyViewModel.search(query).observe(MainActivity.this, (List<Vocabulary> list) -> {
recycleViewAdapter.filterList(list);
});
} else {
searchView.clearFocus();
hideKeyboard(searchView);
refreshVocabularyList();
}
}
@Override
public void afterTextChanged(Editable s) {
}
});
**Method for when I click on an item**
@Override
public void onVocabularyClick(int position) {
searchView.clearFocus();
DialogFragment.isDelete = false;
DialogFragment.isEdit = false;
Vocabulary vocabulary = recycleViewAdapter.getVocabularyAtPosition(position);
Bundle bundle = new Bundle();
bundle.putParcelable("vocabulary", vocabulary);
showFragment.setArguments(bundle);
FragmentManager manager = getSupportFragmentManager();
FragmentTransaction transaction = manager.beginTransaction();
transaction.replace(R.id.mainLayout, showFragment)
.addToBackStack(null)
.commit();
}
**For when I click on delete (imageButton) next to an item**
@Override
public void onDeleteVocabularyClick(int position) {
searchView.clearFocus();
DialogFragment.isEdit = false;
DialogFragment.isDelete = true;
Vocabulary vocabulary = recycleViewAdapter.getVocabularyAtPosition(position);
Bundle bundle = new Bundle();
bundle.putParcelable("vocabulary", vocabulary);
dialogFragment.setArguments(bundle);
dialogFragment.show(getSupportFragmentManager(), null);
}
**When I click on edit (imageButton) next to an item**
@Override
public void onEditVocabularyClick(int position) {
searchView.clearFocus();
DialogFragment.isDelete = false;
DialogFragment.isEdit = true;
Vocabulary vocabulary = recycleViewAdapter.getVocabularyAtPosition(position);
Bundle bundle = new Bundle();
bundle.putParcelable("vocabulary", vocabulary);
dialogFragment.setArguments(bundle);
dialogFragment.show(getSupportFragmentManager(), null);
}
**When I click on save button in a dialog to enter new words**
@Override
public void onDialogSave(Vocabulary vocabulary) {
if (vocabulary != null) {
searchView.clearFocus();
VocabularyViewModel.insert(vocabulary);
refreshVocabularyList(); // Refresh the list after saving
dialogFragment.dismiss();
}
}
**When I click on update button in the update dialog**
@Override
public void onDialogUpdate(Vocabulary vocabulary) {
if (vocabulary != null) {
VocabularyViewModel.update(vocabulary);
refreshVocabularyList(); //Refresh the list after updating
dialogFragment.dismiss();
} else {
Toast.makeText(this, "Please fill all the fields", Toast.LENGTH_SHORT).show();
}
}
**When I click on delete button in the delete dialog**
@Override
public void onDialogDelete(Vocabulary vocabulary) {
if (vocabulary != null) {
VocabularyViewModel.delete(vocabulary);
refreshVocabularyList(); //Refresh the list after deleting
dialogFragment.dismiss();
}
}
private void refreshVocabularyList() {
vocabularyViewModel.getAllData.observe(MainActivity.this, vocabularies ->{
/*vocabularyList.clear();
vocabularyList.addAll(vocabularies);*/
recycleViewAdapter.resetList(vocabularies); // Reset to original list
});
}
Я думаю, что у вас есть случай, когда в текстовом поле не установлено значение ""
после вашей модели VocabularyViewModel
Например
Добавьте этот фрагмент кода ниже ко всем вашим функциям, таким как onDialogUpdate
, onDialogSave
и onDialogDelete
.
searchView.setText(""); // clears your search field
Внимательно изучаю документацию по Android android
Я думаю, нам нужно удалить наблюдаемое, прежде чем начинать новый поиск, это должно сработать.
searchView.addTextChangedListener(new TextWatcher() {
private LiveData<List<Vocabulary>> searchLiveData;
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
String query = s.toString();
if (!query.isEmpty()) {
if (searchLiveData != null) {
// Remove the old observer before starting a new search
searchLiveData.removeObservers(MainActivity.this);
}
searchLiveData = vocabularyViewModel.search(query);
searchLiveData.observe(MainActivity.this, list -> {
recycleViewAdapter.filterList(list);
});
} else {
searchView.clearFocus();
hideKeyboard(searchView);
refreshVocabularyList();
}
}
@Override
public void afterTextChanged(Editable s) {}
});
@AlexNourani попробуйте добавить это recycleViewAdapter.resetList(vocabularyViewModel.getAllData.getValue());
после searchView..setText("")
Я сейчас сделал, как вы сказали, не работает.
это очень странно, часть меня думает о вашем database
запросе, но я проведу расследование, как только узнаю, есть ли у вас какие-либо ошибки. Я обновил код, теперь посмотрим, что произойдет. @АлексНурани
Я сделал все шаги, но не работает. вы что думаете, что я создаю новый проект и переношу в него все коды? Я сделал чистую перестройку и сделал недействительным, но это не помогло.
@AlexNourani попробуйте изменить add searchView.addTextChangedListener
и еще одну вещь, о которой я мог подумать, это то, что вы не закрываете соединение с базой данных после чтения из нее.
@AlexNourani, можете ли вы изменить все вхождения строки на TextField, чтобы использовать экземпляр TextFieldValue вместо String. Пожалуйста, обратитесь за помощью к этой документации материал.mit.edu/afs/sipb/project/android/docs/guide/topics/ui/…
Я использую базу данных номеров. Нужно ли закрывать какое-либо соединение? Я прочту статью и попробую реализовать. Спасибо
@AlexNourani о да, вы делаете, потому что, если вы этого не сделаете, ваша программа все равно будет использовать то же соединение, которое она использовала для чтения, а также для обновления/удаления, когда этого не следует, новое соединение должно быть установлено к базе данных для любой транзакции, а также recycleview устарел разработчик .android.com/reference/android/support/v7/widget/… почему вы не используете Jetpack Compose вместо традиционного XML, я думаю, что значение текстового поля в вашем случае не поддерживается, поэтому может не сработать.
@AlexNourani Я обновил КОД. Похоже, что в вашем методе afterTextChanged нет непосредственной угрозы бесконечного цикла, поскольку вы не вносите изменения в Editable непосредственно внутри него. Однако если бы вы изменили Editable внутри afterTextChanged, вам нужно было бы быть осторожным, чтобы избежать рекурсивных вызовов. В нынешнем виде использование afterTextChanged безопасно.
Дааа,-->> «Я думаю, нам нужно удалить наблюдаемое, прежде чем начинать новый поиск, это должно сработать» Вы правы. проблема была в этом, и я сделал то же самое внутри ondialogUpdate и onDialogeDelete. и это полностью работает. Большое спасибо. что касается jetCompose, мне нужно начать его изучать и работать с ним. Я считаю, что один лучше.
@AlexNourani Я рад, что это работает
Я это сделал, но это не работает. Я думаю, мне нужно где-то очистить или удалить список поиска, но я не знаю где.