Android реализует поиск с моделью представления и живыми данными - PullRequest
0 голосов
/ 03 июля 2018

Я работаю над проектом для Android по курсу udacity. В настоящее время я пытаюсь реализовать функцию поиска, придерживаясь компонентов архитектуры Android и используя Firestore и комнату. Я довольно новичок во всех этих концепциях, поэтому, пожалуйста, укажите все, что кажется неправильным.

Поэтому я создал хранилище базы данных, чтобы синхронизировать базы данных пожарного депо и помещения и доставлять данные. Затем я использую viewmodel и шаблон наблюдателя (я думаю), поэтому мой наблюдатель получает данные и ищет изменения, передает их моему адаптеру (refreshMyList(List)), который заполняет recyclerview следующим образом:

 contactViewModel = ViewModelProviders.of(this).get(ContactsViewModel.class);
 contactViewModel.getAllContacts().observe(this, new 
 Observer<List<DatabaseContacts>>() {
        @Override
        public void onChanged(@Nullable List<DatabaseContacts> 
        databaseContacts) {
            ArrayList<DatabaseContacts> tempList = new ArrayList<>();
            tempList.addAll(databaseContacts);
            contactsAdapter.refreshMyList(tempList);
            if (tempList.size() < 1) {
                results.setVisibility(View.VISIBLE);
            } else {
                results.setVisibility(View.GONE);
            }
        }
    });

Теперь я хочу выполнить поиск данных, у меня все запросы в комнате настроены нормально, и в моем хранилище данных есть методы для получения контактов на основе строки поиска, но я не могу обновить свой список. читал, что есть способы сделать это как Transformations.switchMap? но я не могу понять, как это работает, может кто-нибудь мне помочь

В настоящее время я пытаюсь вернуть список результатов от асинхронной задачи, она использовалась для возврата текущих данных, но я изменил ее, поскольку getValue() всегда был null, не уверен, что это правильно, вот асинхронность:

private static class searchContactByName extends AsyncTask<String, Void, 
ArrayList<DatabaseContacts>> {

    private LiveDatabaseContactsDao mDao;

    searchContactByName(LiveDatabaseContactsDao dao){
        this.mDao = dao;
    }

    @Override
    protected ArrayList<DatabaseContacts> doInBackground(String... params) {
        ArrayList<DatabaseContacts> contactsArrayList = new ArrayList<>();
        mDao.findByName("%" + params[0] + "%");
        return contactsArrayList;
    }
}

Я вызываю это из своего хранилища контактов в своей собственной оболочке:

public List<DatabaseContacts> getContactByName(String name) throws 
ExecutionException, InterruptedException {
    //return databaseContactsDao.findByName(name);
    return new searchContactByName(databaseContactsDao).execute(name).get();
}

и это называется из моей модели вида следующим образом:

public List<DatabaseContacts> getContactByName(String name) throws 
ExecutionException, InterruptedException {
    return  contactRepository.getContactByName(name);
}

Я тогда вызываю это из моего фрагмента:

private void searchDatabase(String searchString) throws ExecutionException, 
InterruptedException {
    List<DatabaseContacts> searchedContacts = 
    contactViewModel.getContactByName("%" + searchString + "%");
    ArrayList<DatabaseContacts> contactsArrayList = new ArrayList<>();
    if (searchedContacts !=  null){
        contactsArrayList.addAll(searchedContacts);
        contactsAdapter.refreshMyList(contactsArrayList);
    }
}

и это вызывается из метода изменения текста поискового запроса в моем onCreateOptionsMenu:

        @Override
        public boolean onQueryTextChange(String newText) {
            try {
                searchDatabase(newText);
            } catch (ExecutionException e) {
                e.printStackTrace();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return false;
        }

но это ничего не меняет в моем исходном recyclerview содержании, никогда не меняются идеи?

Ответы [ 4 ]

0 голосов
/ 31 мая 2019

Я столкнулся с той же проблемой, и мне удалось исправить с помощью

switchMap

и

MutableLiveData

Нам просто нужно использовать MutableLiveData , чтобы установить текущее значение editText, и при поиске пользователя мы вызываем setValue(editText.getText())

 public class FavoriteViewModel extends ViewModel {
            public LiveData<PagedList<TeamObject>> teamAllList;
        public MutableLiveData<String> filterTextAll = new MutableLiveData<>();

        public void initAllTeams(TeamDao teamDao) {
            this.teamDao = teamDao;
            PagedList.Config config = (new PagedList.Config.Builder())
                    .setPageSize(10)
                    .build();

            teamAllList = Transformations.switchMap(filterTextAll, input -> {
                if (input == null || input.equals("") || input.equals("%%")) {
//check if the current value is empty load all data else search
                    return new LivePagedListBuilder<>(
                            teamDao.loadAllTeam(), config)
                            .build();
                } else {
                    System.out.println("CURRENTINPUT: " + input);
                    return new LivePagedListBuilder<>(
                            teamDao.loadAllTeamByName(input), config)
                            .build();
                }

            });

            }

    }

Активность фрагмента

viewModel = ViewModelProviders.of(activity).get(FavoriteViewModel.class);
                        viewModel.initAllTeams(AppDatabase.getInstance(activity).teamDao());
                        FavoritePageListAdapter adapter = new FavoritePageListAdapter(activity);
                        viewModel.teamAllList.observe(
                                activity, pagedList -> {
                                    try {
                                        Log.e("Paging ", "PageAll" + pagedList.size());

                                        try {
                                            //to prevent animation recyclerview when change the list
                                            recycleFavourite.setItemAnimator(null);
                                            ((SimpleItemAnimator) Objects.requireNonNull(recycleFavourite.getItemAnimator())).setSupportsChangeAnimations(false);

                                        } catch (Exception e) {
                                        }

                                        adapter.submitList(pagedList);

                                    } catch (Exception e) {
                                    }
                                });
                        recycleFavourite.setAdapter(adapter);

//first time set an empty value to get all data
                        viewModel.filterTextAll.setValue("");



                edtSearchFavourite.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) {

                    @Override
                    public void afterTextChanged(Editable editable) {
                      //just set the current value to search.
                        viewModel.filterTextAll.setValue("%" + editable.toString() + "%");


                    }
                });

Комната Дао

@Dao
public interface TeamDao {


        @Query("SELECT * FROM teams order by orders")
        DataSource.Factory<Integer, TeamObject> loadAllTeam();


        @Query("SELECT * FROM teams where team_name LIKE  :name or LOWER(team_name_en) like LOWER(:name) order by orders")
        DataSource.Factory<Integer, TeamObject> loadAllTeamByName(String name);


    }

PageListAdapter

public class FavoritePageListAdapter extends PagedListAdapter<TeamObject, FavoritePageListAdapter.OrderHolder> {
    private static DiffUtil.ItemCallback<TeamObject> DIFF_CALLBACK =
            new DiffUtil.ItemCallback<TeamObject>() {
                // TeamObject details may have changed if reloaded from the database,
                // but ID is fixed.
                @Override
                public boolean areItemsTheSame(TeamObject oldTeamObject, TeamObject newTeamObject) {
                    System.out.println("GGGGGGGGGGGOTHERE1: " + (oldTeamObject.getTeam_id() == newTeamObject.getTeam_id()));
                    return oldTeamObject.getTeam_id() == newTeamObject.getTeam_id();
                }

                @Override
                public boolean areContentsTheSame(TeamObject oldTeamObject,
                                                  @NonNull TeamObject newTeamObject) {
                    System.out.println("GGGGGGGGGGGOTHERE2: " + (oldTeamObject.equals(newTeamObject)));
                    return oldTeamObject.equals(newTeamObject);
                }
            };

    private Activity activity;

    public FavoritePageListAdapter() {
        super(DIFF_CALLBACK);
    }

    public FavoritePageListAdapter(Activity ac) {
        super(DIFF_CALLBACK);
        this.activity = ac;

    }

    @NonNull
    @Override
    public OrderHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.row_favourite, parent, false);
        return new FavoritePageListAdapter.OrderHolder(view);

    }

    @Override
    public void onBindViewHolder(@NonNull OrderHolder holder,
                                 int position) {
        System.out.println("GGGGGGGGGGGOTHERE!!!");

        if (position <= -1) {
            return;
        }
        TeamObject teamObject = getItem(position);


        try {
                holder.txvTeamRowFavourite.setText(teamObject.getTeam_name());


        } catch (Exception e) {
            e.printStackTrace();
        }


    }

    public class OrderHolder extends RecyclerView.ViewHolder {

        private TextView txvTeamRowFavourite;


        OrderHolder(View itemView) {
            super(itemView);
            txvTeamRowFavourite = itemView.findViewById(R.id.txv_team_row_favourite);
        }

    }
}
0 голосов
/ 10 марта 2019

Я столкнулся с той же проблемой и решил ее с помощью ответа @Rohit, спасибо! Я немного упростил свое решение, чтобы лучше проиллюстрировать его. Есть Categories, и в каждой категории много Items. LiveData должен возвращать элементы только из одной категории. Пользователь может изменить категорию, а затем вызывается забавный search(id: Int), который изменяет value MutableLiveData с именем currentCategory. Затем это вызывает switchMap и приводит к новому запросу для элементов категории:

class YourViewModel: ViewModel() {

    // stores the current Category
    val currentCategory: MutableLiveData<Category> = MutableLiveData()

    // the magic happens here, every time the value of the currentCategory changes, getItemByCategoryID is called as well and returns a LiveData<Item>
    val items: LiveData<List<Item>> = Transformations.switchMap(currentCategory) { category ->
           // queries the database for a new list of items of the new category wrapped into a LiveData<Item>
           itemDao.getItemByCategoryID(category.id)
    }

    init {
        currentCategory.value = getStartCategoryFromSomewhere()
    }

    fun search(id: Int) { // is called by the fragment when you want to change the category. This can also be a search String...
        currentCategory.value?.let { current ->
            // sets a Category as the new value of the MutableLiveData
            current.value = getNewCategoryByIdFromSomeWhereElse(id)
        }
    }
}
0 голосов
/ 23 апреля 2019

Я использую продукт для поиска по штрих-коду, используя следующий подход.
Каждый раз, когда значение productBarCode изменяется, продукт будет искать в комнате дБ.

@AppScoped
class PosMainViewModel @Inject constructor(
var localProductRepository: LocalProductRepository) : ViewModel() {

val productBarCode: MutableLiveData<String> = MutableLiveData()

val product: LiveData<LocalProduct> = Transformations.switchMap(productBarCode) { barcode ->
    localProductRepository.getProductByBarCode(barcode)
}

init {
    productBarCode.value = ""
}

fun search(barcode: String) {
    productBarCode.value = barcode
}}

В деятельности

posViewModel.product.observe(this, Observer {
        if (it == null) {
           // not found
        } else {
            productList.add(it)
            rvProductList.adapter!!.notifyDataSetChanged()
        }
    })

для поиска

posViewModel.search(barcode) //search param or barcode
0 голосов
/ 04 июля 2018

вы можете использовать Transformation.switchMap для выполнения поисковых операций.

  1. В viewmodel создайте MutableLiveData с последней строкой поиска.

  2. Использование модели внутреннего вида:

    LiveData<Data> data = 
    LiveDataTransformations.switchMap(searchStringLiveData, string ->  
    repo.loadData(string)))
  1. Верните вышеуказанные данные в реальном времени, чтобы они могли наблюдать и обновлять представление.
...