I'm working with Db(via SQLite.NET PCL,not async version). At current moment i have a listview with some data(taken from db),also i got a searchbar/entry(its nvm),where user can input some values and then,via LINQ i'm going to make a query and update SourceItems of my List.
So the problems comes with performance,because my DB got million records and simple LINQ query working very slow.In other words,when user enter too fast some data,application gets huge lags and sometimes can Crash.
To resolve this problem,some things come in my mind(theoretically solution):
1)Need to put method(which i make query into db) on Task(to unlock my main UI thread)
2)Initialize timer,then turn on and :
Something like that(similar) or any suggestions.Thanks!
UPD:
So to be honest,i tried too much and didnt get a good result
BTW,my current code(Snippets) :
1) My SearchMethod
public void QueryToDB(string filter)
{
this.BeginRefresh ();
if (string.IsNullOrWhiteSpace (filter))
{
this.ItemsSource = SourceData.Select(x => x.name); // Source data is my default List of items
}
else
{
var t = App.DB_Instance.FilterWords<Words>(filter); //FilterWords it's a method,where i make direct requests to the database
this.ItemsSource = t.Select(x => x.name);
}
this.EndRefresh ();
}
2)Searchbar.TextChanged (anonymous method)
searchBar.TextChanged +=async (sender, e) =>
{
ViewModel.isBusy = true; //also i got a indicator,to show progress,while query working
await Task.Run(()=> //my background,works fine
{
listview.QueryToDB(searchBar.Text);
});
ViewModel.isBusy = false; // after method is finished,indicator turn off
};
The main problem is how to implement this part(with these case's),where 1 second passed and only then i'm going to make query to update my sourceItems of list(everytime,when user inputs some value into searchbar,this trigger(timer) must refresh again to zero).
Any help will be appreciated,thanks!
PS Sorry for my eng. skills!
One way to do it is to combine async Task.Run
and CancellationTokenSource
:
CancellationTokenSource cancellationTokenSource;
searchView.TextChanged += async (sender, e) =>
{
if (cancellationTokenSource != null) cancellationTokenSource.Cancel();
cancellationTokenSource = new CancellationTokenSource();
var cancellationToken = cancellationTokenSource.Token;
var searchBar = (sender as SearchBar);
if (searchBar != null)
{
string searchText = searchBar.Text;
try
{
await Task.Delay(650, cancellationToken);
if (cancellationToken.IsCancellationRequested) return;
var searchResults = await Task.Run(() =>
{
return ViewModel.Search(searchText);
});
if (cancellationToken.IsCancellationRequested) return;
ViewModel.YouItems.Repopulate(searchResults);
}
catch (OperationCanceledException)
{
// Expected
}
catch (Exception ex)
{
Logger.Error(ex);
}
}
};
You want to wait before actually performing your search. Killing a search task in midway can cause undefined behavior.
You want to save the current search filter and compared it again 1 second later. If that hasn't changed, do the search. Otherwise, abort :
searchBar.TextChanged += async (sender, e) =>
{
var filter = searchBar.Text;
await Task.Run(() =>
{
Thread.Sleep(1000);
if (filter == searchBar.Text)
listview.QueryToDB(searchBar.Text);
});
};
As to keep the view model updated, move your isBusy
assignments inside QueryToDB
because that is when your view model is truly busy :
public void QueryToDB(string filter)
{
this.BeginRefresh ();
ViewModel.isBusy = true;
// do your search
ViewModel.isBusy = false;
this.EndRefresh ();
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With