google-mapsxamarin.forms.net-core

How to introduce delay between API calls to google search to avoid OVER_QUERY_LIMIT error


I am using PlacesSearchBar to provide a autocomplete option to look up places in my Xamarin Forms application.

This is working fine from the component's point of view, but google API is returning me OVER_QUERY_LIMIT after one or two attempts.

I think I know what the issue is here, this component is making more than one call to this google API per second that puts me as a suspect mode on the google logic and it starts to return me the OVER_QUERY_LIMIT status. However I am unable to see how to introduce a delay between these calls.

here is how I am using this component.

<searchplaces:PlacesBar x:Name="edtSearch" MinimumSearchText="6"  ApiKey="<API KEY>" Placeholder="Please enter your destination address"></searchplaces:PlacesBar>
<AbsoluteLayout>
    <ActivityIndicator x:Name="spinner" IsRunning="false" AbsoluteLayout.LayoutBounds="0.5, 0.1, 50, 50" AbsoluteLayout.LayoutFlags="PositionProportional" />
    <ListView x:Name="lvPlaces" ItemsSource="{Binding .}"  RowHeight="60"
          VerticalOptions="CenterAndExpand" HorizontalOptions="CenterAndExpand"
          IsVisible="False" AbsoluteLayout.LayoutBounds="0, 0, 1, 1" AbsoluteLayout.LayoutFlags="SizeProportional">
        <ListView.ItemTemplate>
            <DataTemplate>
                <ViewCell>
                    <StackLayout BackgroundColor="#2B2C30" Orientation="Vertical" Margin="0,0,0,2" Padding="5,5,5,5" VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand" >
                        <Label Text="{Binding Description}" TextColor="#EAEDF7" FontSize="Medium" VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand"/>
                    </StackLayout>
                </ViewCell>
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>
</AbsoluteLayout>

on my .cs constructor I have this:

edtSearch.TextChanged += async (sender, e) => 
            {
                if (!string.IsNullOrEmpty(e.NewTextValue) && (e.NewTextValue.Length >= edtSearch.MinimumSearchText))
                {
                    lvPlaces.IsVisible = false;
                    spinner.IsVisible = true;
                    spinner.IsRunning = true;

                    edtSearch.IsReadOnly = true; // try 1: to introduce delay
                    await Task.Delay(800);  
                }
                else
                {
                    lvPlaces.IsVisible = true;
                    spinner.IsRunning = false;
                    spinner.IsVisible = false;
                    edtSearch.IsReadOnly = false;
                }
            };
            edtSearch.PlacesRetrieved = async (sender, result) =>
            {
                this.BindingContext = result.AutoCompletePlaces;
                spinner.IsRunning = false;
                spinner.IsVisible = false;
                edtSearch.IsReadOnly = false;

                if (result.AutoCompletePlaces != null && result.AutoCompletePlaces.Count > 0)
                    lvPlaces.IsVisible = true;

                if (result.Status == "OVER_QUERY_LIMIT")
                {
                    await Task.Delay(2000); // try 2: to introduce delay
                }
                };
            edtSearch.MinimumSearchText = 6; 

on the PlacesSearchBar component code I see this logic:

async void OnTextChanged(object sender, TextChangedEventArgs e)
        {
            if (!string.IsNullOrEmpty(e.NewTextValue) && e.NewTextValue.Length >= MinimumSearchText)
            {
                var predictions = await Places.GetPlaces(e.NewTextValue, ApiKey, Bias, Components, Type, Language);
                if (PlacesRetrieved != null && predictions != null)
                    OnPlacesRetrieved(predictions);
                else
                    OnPlacesRetrieved(new AutoCompleteResult());
            }
            else
            {
                OnPlacesRetrieved(new AutoCompleteResult());
            }
        } 

as this is a event, no matter what I do from outside this component, it does not effect this behavior of the original component.

How can I get over this OVER_QUERY_LIMIT when using this Auto complete text box?


Solution

  • I think we managed to solve this, issue was that we has not connected our project to a billing account as a result there is a bare minimal request something of the order of 1 request per every second that google allows.

    once we connected to a billing account this started to work at least for now.