Search code examples
androidxamarinmvvmcrosssearchview

How to prevent android SearchView Query toggling while text is typing


I got my view with SearchView component. The problem is every new symbol in the input field toggling Query action, so there are some http request are fire etc, so it starts to working slow.

I want it to run only after I click on search button on virtual keyboard (bellow button ).

enter image description here

Is there any properties for that in SearchView?

layout code:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
                xmlns:local="http://schemas.android.com/apk/res-auto"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">


    <SearchView
        android:id="@+id/search"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:clickable="true"
        local:MvxBind="Query SearchString" />

</LinearLayout>

Or I should make something like custom binding which detects keyboard key click?

UPD:

Some code to make clear part of how search works:

View model

public class RemoteMusicSearchViewModel : MvxViewModel
    {
        private IMvxNavigationService _mvxNavigationService;
        private IRemoteMusicDataService _remoteMusicDataService;
        private int _currentPage;

        public RemoteMusicSearchViewModel(IMvxNavigationService mvxNavigationService,
            IRemoteMusicDataService remoteMusicDataService)
        {
            _mvxNavigationService = mvxNavigationService;
            _remoteMusicDataService = remoteMusicDataService;
        }

        public override void Start()
        {
            base.Start();

            _currentPage = 0;
        }

        private string _searchString;

        public string SearchString
        {
            get { return _searchString; }

            set
            {
                _searchString = value;
                RaisePropertyChanged(() => SearchString);
                PerformBasicSearch().ConfigureAwait(false);
            }
        }

        private ObservableCollection<DownloadableEntity> _foundItems;

        public ObservableCollection<DownloadableEntity> FoundItems
        {
            get { return _foundItems; }

            set
            {
                if (_currentPage > 0)
                {
                    _foundItems = new ObservableCollection<DownloadableEntity>(_foundItems.Concat(value));
                }
                else
                {
                    _foundItems = value;
                }

                RaisePropertyChanged(() => FoundItems);
            }
        }

        private async Task PerformBasicSearch(int page = 0)
        {
            string request = SearchString;
            string result = await _remoteMusicDataService.SearchByProperty(request, MusicSearchType.ByTracks, page).ConfigureAwait(false);
            var searchResult = MusicSearchResult.FromJson(result);

            await PrepareDataForOutput(searchResult).ConfigureAwait(false);
        }
    }

full layout code:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
                xmlns:local="http://schemas.android.com/apk/res-auto"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">


    <SearchView
        android:id="@+id/search"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:clickable="true"
        local:MvxBind="Query SearchString"
        />

    <MvvmCross.Binding.Droid.Views.MvxListView
        android:id="@+id/searchlist"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true"
        local:MvxBind="ItemsSource FoundItems"
        local:MvxItemTemplate="@layout/listitem"/>


</LinearLayout>

Solution

  • I found the solution - I just created new binding for that:

    public class SearchViewKeyPressEventsBinding : MvxAndroidTargetBinding
        {
            private readonly SearchView _searchView;
            private IMvxAsyncCommand _command;
    
            public SearchViewKeyPressEventsBinding(SearchView searchView) : base(searchView)
            {
                _searchView = searchView;
                _searchView.QueryTextSubmit += _searchView_KeyPress;
            }
    
            private void _searchView_KeyPress(object sender, SearchView.QueryTextSubmitEventArgs e)
            {
                try
                {
                    if (_command != null)
                    {
                        _command.ExecuteAsync();
                    }
                }
                catch (Exception ex)
                {
                    throw ex;
                }
            }
    
            public override Type TargetType
            {
                get { return typeof(IMvxAsyncCommand); }
            }
    
    
            protected override void SetValueImpl(object target, object value)
            {
                try
                {
                    _command = (IMvxAsyncCommand)value;
                }
                catch (Exception e)
                {
                    Log.Error("SOME BINDER FAIL\n\t" + e.Message + "\n", "SOME BINDER FAIL\n\t" + e.Message + "\n");
                    throw;
                }
            }
    
            protected override void Dispose(bool isDisposing)
            {
                if (isDisposing)
                {
                    _searchView.QueryTextSubmit -= _searchView_KeyPress;
                }
                base.Dispose(isDisposing);
            }
        }
    }
    

    Then registred it and it worked:

       registry.RegisterFactory(new MvxCustomBindingFactory<SearchView>("OnSearchSubmit", (sv) => new SearchViewKeyPressEventsBinding(sv)))
    

    In layout:

    <SearchView
            android:id="@+id/search10"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:clickable="true"
            local:MvxBind="Query SearchString; OnSearchSubmit OnSubmitPressCommand" />
    

    And don't forget to set up viewmodel's property:

     public IMvxAsyncCommand OnSubmitPressCommand
            {
                get
                {
                    return new MvxAsyncCommand(OnSearchSubmit);
                }
            }
    
      private async Task OnSearchSubmit()
            {
                //HideKeyboardOnSearchStart.Invoke(this, null);
                await PerformBasicSearch().ConfigureAwait(false);
            }