#android #android-edittext #android-room
#Android #android-редактировать текст #android-комната
Вопрос:
Когда вы нажимаете на кнопку поиска, она активируется с полным списком элементов. Вверху находится EditText, и когда пользователь начинает вводить имя, список должен быть динамически отфильтрован. Я осваиваю только компоненты архитектуры и вроде бы мне удалось реализовать поиск, но он работает криво.
Предположим, что есть следующие имена: «magic», «summer», «salt», «spark» и так далее. Я начинаю вводить «s» — список меняется, остаются только слова с этой буквой. Затем я ввожу «a», слово «соль» должно остаться, но ничего не меняется. Когда я стираю введенные данные, список не обновляется. Помогите решить проблему.
DataDao
@Query("SELECT * FROM Data WHERE title LIKE :search")
LiveData<List<Data>> getAllSearch(String search);
Хранилище данных
public class DataRepository {
private DatabaseCopier db;
private DataDao dataDao;
DataRepository(Application application) {
db = DatabaseCopier.getInstance(application);
dataDao = db.getDatabase().dataDao();
}
LiveData<List<Data>> getAllSearch(String search) {
return db.getDatabase().dataDao().getAllSearch(search);
}
ViewModel с фабрикой, где я передаю имя конструктору.
public class DataViewModelSearch extends AndroidViewModel {
private LiveData<List<Data>> currentData;
private DataRepository repository;
public DataViewModelSearch(@NonNull Application application, final String dataTitle) {
super(application);
String verseTitle = dataTitle;
repository = new DataRepositorySearch(application);
currentData = repository.getAllSearch(verseTitle);
}
public LiveData<List<Data>> getAllSearch() {
return currentData;
}
public static class ModelFactorySearch extends ViewModelProvider.NewInstanceFactory {
@NonNull
private final Application application;
private final String dataTitle;
private final DataRepository repository;
public ModelFactorySearch(@NonNull Application application, String title) {
super();
this.application = application;
this.dataTitle = title;
repository = new DataRepository(application);
}
@NonNull
@SuppressWarnings("unchecked")
@Override
public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
if (modelClass == DataViewModel.class) {
return (T) new DataViewModelSearch(application, dataTitle);
}
return null;
}
}
}
Активность поиска
public class SearchActivity extends AppCompatActivity {
private SearchAdapter adapter;
RvObserver observer;
EditText etFilter;
RecyclerView recyclerView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_search);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
observer = new RvObserver();
etFilter = findViewById(R.id.et_filter);
recyclerView = findViewById(R.id.rv_search);
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
recyclerView.setLayoutManager(layoutManager);
DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(this, LinearLayoutManager.VERTICAL);
dividerItemDecoration.setDrawable(this.getResources().getDrawable(R.drawable.divider));
recyclerView.addItemDecoration(dividerItemDecoration);
adapter = new SearchAdapter(onSearchClickListener, this);
recyclerView.setAdapter(adapter);
DataListViewModel dataListViewModel = ViewModelProviders.of(this).get(DataListViewModel.class);
dataListViewModel.getAllVersesABS().observe(this, new Observer<List<Data>>() {
@Override
public void onChanged(List<Data> data) {
adapter.setData(data);
}
});
Bundle bundle = new Bundle(1);
bundle.putString("filter", "");
etFilter.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
@Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
refresh(charSequence.toString());
}
@Override
public void afterTextChanged(Editable editable) {
}
});
}
private void refresh(String searchText) {
Bundle bundle = new Bundle(1);
bundle.putString("filter", searchText);
searchText = "%" searchText "%";
final DataViewModelSearch.ModelFactorySearch factory = new DataViewModelSearch.ModelFactorySearch(
getApplication(), searchText);
final DataViewModelSearch modelSearch = ViewModelProviders.of(this, factory)
.get(DataViewModelSearch.class);
modelSearch.getAllSearch().observe(this, new Observer<List<Data>>() {
@Override
public void onChanged(List<Data> data) {
adapter.setData(data);
adapter.notifyDataSetChanged();
}
});
}
@Override
protected void onResume() {
super.onResume();
adapter.registerAdapterDataObserver(observer);
}
@Override
protected void onPause() {
super.onPause();
adapter.unregisterAdapterDataObserver(observer);
}
Ответ №1:
Во-первых, у вас проблема с вашей логикой обновления. Каждый раз, когда вы что-то вводите, вы создаете новую ViewModel с новым репозиторием.
Во-вторых, вы используете LiveData как инструмент асинхронной работы, но LiveData срабатывает, когда вы что-то меняете в своей базе данных. Однако вы не изменяете данные и просто хотите выполнить SQL-запрос. Вот почему я использую AsyncTask в примере (для простоты). Вы можете использовать RxJava.
Вот простой пример.
Активность поиска
public class SearchActivity extends AppCompatActivity {
private SearchAdapter adapter;
private DataViewModelSearch dataListViewModel;
EditText etFilter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_search);
etFilter = findViewById(R.id.et_filter);
RecyclerView recyclerView = findViewById(R.id.rv_search);
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
recyclerView.setLayoutManager(layoutManager);
adapter = new SearchAdapter(onSearchClickListener, this);
recyclerView.setAdapter(adapter);
dataListViewModel = ViewModelProviders.of(this).get(DataListViewModel.class);
dataListViewModel.searchData.observe(this, new Observer<List<Data>>() {
@Override
public void onChanged(List<Data> data) {
adapter.setData(data); // it will be triggered every time when we change searchData in ViewModel via searchData.setValue()
}
});
etFilter.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
@Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
dataListViewModel.refresh(charSequence.toString());
}
@Override
public void afterTextChanged(Editable editable) {
}
});
}
}
ViewModel
public class DataViewModelSearch extends AndroidViewModel {
MutableLiveData<List<Data>> searchData = new MutableLiveData<>();
private DataRepository repository;
public DataViewModelSearch(@NonNull Application application) {
super(application);
repository = new DataRepositorySearch(application); // better create repos outside viewModel or activity, but this is for example
}
private void refresh(String searchText) {
String formattedSearchText = "%" searchText "%";
new GetSearchDataTask.execute(formattedSearchText)
}
//for Async Work
private class GetSearchDataTask extends AsyncTask<Void, Void, List<Data>> {
@Override
protected List<Data> doInBackground(String... params) {
return repository.getAllSearch(params[0])
}
@Override
protected void onPostExecute(List<Data> data) {
super.onPostExecute(data);
searchData.setValue(data); //change LiveData value
}
}
}
Ваш репозиторий должен вернуть List<Data> getAllSearch(String search);
Комментарии:
1. Привет. Поиск работает корректно, но мне нужно было, чтобы при нажатии на кнопку поиска отображался весь список, а когда я вводил название, оставалось то, что было нужно. И при такой реализации открывается пустой экран, и поиск не работает динамически. Не могли бы вы рассказать мне, как это сделать?
2. Просто создайте OnClickListener и make
dataListViewModel.refresh("");
, и тогда ваш параметр LIKE будет выглядеть «%%». Это должно вернуть все результаты3. Извините за глупый вопрос. Я не понимаю, на чем слушатель должен зависать
4. Как я понял, вы сказали, что когда вы нажимаете на кнопку поиска, вы хотите показать все результаты, поэтому вам нужно настроить прослушиватель на поиск biutton