Skip to content Skip to sidebar Skip to footer

Android Implement Search With View Model And Live Data

I'm working on a project in android for a udacity course I'm currently trying to implement a search function while adhering to android architecture components and using firestore a

Solution 1:

you can use Transformation.switchMap to do search operations.

  1. In viewmodel create MutableLiveData which has latest search string.

  2. Inside viewmodel use:

    LiveData<Data> data = 
    LiveDataTransformations.switchMap(searchStringLiveData, string ->  
    repo.loadData(string)))
  1. Return the above live data to activity so it can observe and update view.

Solution 2:

I faced the same issue and I managed to fix it using

switchMap

and

MutableLiveData

We just need to use MutableLiveData to set the current value of editText, and when the user search we call setValue(editText.getText())

publicclassFavoriteViewModelextendsViewModel {
            public LiveData<PagedList<TeamObject>> teamAllList;
        public MutableLiveData<String> filterTextAll = new MutableLiveData<>();

        publicvoidinitAllTeams(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 searchreturnnew LivePagedListBuilder<>(
                            teamDao.loadAllTeam(), config)
                            .build();
                } else {
                    System.out.println("CURRENTINPUT: " + input);
                    returnnew LivePagedListBuilder<>(
                            teamDao.loadAllTeamByName(input), config)
                            .build();
                }

            });

            }

    }

in Activity of fragment

viewModel = ViewModelProviders.of(activity).get(FavoriteViewModel.class);
                        viewModel.initAllTeams(AppDatabase.getInstance(activity).teamDao());
                        FavoritePageListAdapteradapter=newFavoritePageListAdapter(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(newTextWatcher() {
                    @OverridepublicvoidbeforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {

                    }

                    @OverridepublicvoidonTextChanged(CharSequence charSequence, int i, int i1, int i2) {

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


                    }
                });

Room Dao

@DaopublicinterfaceTeamDao {


        @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

publicclassFavoritePageListAdapterextendsPagedListAdapter<TeamObject, FavoritePageListAdapter.OrderHolder> {
    privatestatic DiffUtil.ItemCallback<TeamObject> DIFF_CALLBACK =
            newDiffUtil.ItemCallback<TeamObject>() {
                // TeamObject details may have changed if reloaded from the database,// but ID is fixed.@OverridepublicbooleanareItemsTheSame(TeamObject oldTeamObject, TeamObject newTeamObject) {
                    System.out.println("GGGGGGGGGGGOTHERE1: " + (oldTeamObject.getTeam_id() == newTeamObject.getTeam_id()));
                    return oldTeamObject.getTeam_id() == newTeamObject.getTeam_id();
                }

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

    private Activity activity;

    publicFavoritePageListAdapter() {
        super(DIFF_CALLBACK);
    }

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

    }

    @NonNull@Overridepublic OrderHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        Viewview= LayoutInflater.from(parent.getContext()).inflate(R.layout.row_favourite, parent, false);
        returnnewFavoritePageListAdapter.OrderHolder(view);

    }

    @OverridepublicvoidonBindViewHolder(@NonNull OrderHolder holder,
                                 int position) {
        System.out.println("GGGGGGGGGGGOTHERE!!!");

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


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


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


    }

    publicclassOrderHolderextendsRecyclerView.ViewHolder {

        private TextView txvTeamRowFavourite;


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

    }
}

Solution 3:

Here is a working example in KOTLIN

in the Fragment

binding.search.addTextChangedListener { text ->
            viewModel.searchNameChanged(text.toString())
        }


        viewModel.customers.observe(this, Observer {
            adapter.submitList(it)
            binding.swipe.isRefreshing=false
        })
  • search -> is my edit text
  • customers -> is the data list in the viewModel

View Model

privateval _searchStringLiveData = MutableLiveData<String>()

         val customers = Transformations.switchMap(_searchStringLiveData){string->
                repository.getCustomerByName(string)
            }

    init {
            refreshCustomers()
            _searchStringLiveData.value=""
        }


funsearchNameChanged(name:String){
        _searchStringLiveData.value=name
    }

Solution 4:

I faced the same issue and solved it with the answer of @Rohit, thanks! I simplified my solution a bit to illustrate it better. There are Categories and each Category has many Items. The LiveData should only return items from one Category. The user can change the Category and then the fun search(id: Int) is called, which changes the value of a MutableLiveData called currentCategory. This then triggers the switchMap and results in a new query for items of the category:

classYourViewModel: ViewModel() {

    // stores the current Categoryval 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()
    }

    funsearch(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)
        }
    }
}

Solution 5:

I implement the bar code searching product using the following approach. Everytime the value of productBarCode changes, the product will be searched in the room db.

@AppScopedclassPosMainViewModel@Injectconstructor(
var localProductRepository: LocalProductRepository) : ViewModel() {

val productBarCode: MutableLiveData<String> = MutableLiveData()

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

init {
    productBarCode.value = ""
}

funsearch(barcode: String) {
    productBarCode.value = barcode
}}

In activity

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

for searching

posViewModel.search(barcode) //search param or barcode

Post a Comment for "Android Implement Search With View Model And Live Data"