Sunday, June 19, 2016

Respond Keyboard while Updating UI

Leave a Comment

I am Using android.support.v7.widget.SearchView and I am performing Search on enter of every character in SearchView. following is the snippet.

searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener()             {                  @Override                 public boolean onQueryTextSubmit(String query)                 {                     return false;                 }                  @Override                 public boolean onQueryTextChange(String newText)                 {                      if (!newText.trim().equals(""))                     {                      displayResult(newText);                     return false;                    }               }             }); 

And I am updating the UI When I am Getting Result, So In My Case It will call Search API every time when user enter a single character. So Suppose user wants to Search "Australia" and try to enter whole word but My UI is Updating with Search and User has just type "Aus" after the Keyboard is not responding because it's updating the UI.

So I want Just want to respond Keyboard while Updating the UI.
Hope I'll get fast response.

5 Answers

Answers 1

The scenario of your case is:

  1. Input text

  2. Perform search

  3. Display results

  4. Do again

The lagging happened because of (2) + (3) cost much time to do.

Try to send the search key from (1) to worker thread (AsyncTask, Thread, IntentService,...).

(2) will be execute on worker thread then push the results back to UI

(3) update the UI

To improve performance, I think you should perform search while user stop the input at period of time. In additional, stop unneccessary search if the input changed.

example: input1 > search1 > input2 > cancel old task1 > search2 > ...

Hope it help!

Answers 2

The key to the problem is both updating UI operation with the result from Search API and responding to SearchView with Keyboard are do its job in Main(UI) Thread.

In a short, you let the main thread do too much thing in a short time.

So the solution is to try to LIMIT the frequency of updating UI operation. I meaning, you should let the displayResult(newText) method can CANCEL the previous call when the user continuously inputted word in a short time.

Just updating the UI with the result ONCE when the whole word Australia was inputted completely.

BTW, your search API call should do in the background thread with some wonderful library(Retrofit && OkHttp).

Answers 3

There might be two things that you might be doing wrong. 1) Network request are performed from UI Thread 2) Parsing is done on UI Thread Judging from your stackoverflow points you might not be doing the first case ie; performing a network request on the UI Thread.

For Case 2: try to perform parsing on a background thread, try to shorten the json response (tell the author of the Search API to give a lightweight response). And for each query change cancel the previous task

Answers 4

Your keyboard is not responding because displayResult method is being executed on your main ui thread.

One of the possible solutions to handle this problem properly is using a IntentService, for instance, you can do:

MyIntentService.java

public class MyIntentService extends IntentService {      //Each of these results represent a possible status of your service     public static final int RESULT_ERROR = -1;     public static final int RESULT_ENDED = 1;     public static final int RESULT_START = 0;      public static final String SERVICE_BROADCAST = MyIntentService.class.getName()+".Broadcast";       public MigrateService(){         super(MigrateService.class.getName());     }       @Override     protected void onHandleIntent(Intent intent) {          //Get the query         String queryText = intent.getStringExtra("MyQuery");          //Notify the activity that search has started         publishResult(RESULT_START, Bundle.EMPTY);         Bundle data = null;         try{             data = getDataWithRetrofit(queryText);         } catch (SomeException e){             //In case of error, notify the activity             publishResult(RESULT_ERROR, Bundle.EMPTY);         }         //Search is ended         publishResult(RESULT_ENDED, data);     }      public void publishResult(int resultCode, Bundle data){         Intent intent = new Intent(SERVICE_BROADCAST);         intent.putExtras(data);         intent.putExtra("resultCode",resultCode);         sendBroadcast(intent);     } } 

Basically, you have a Service that fetches data in background thread and sends data to your Activity when some event occurs (start/end).

On your Activity class, you need to do the following:

1. Declare a BroadcastReceiver instance:

private BroadcastReceiver mReceiver = new BroadcastReceiver() {     @Override     public void onReceive(Context context, Intent intent) {         if(intent.hasExtra("resultCode")) {             int resultCode = intent.getIntExtra("resultCode",MyService.STATUS_ERROR);             switch (resultCode) {                 case MyIntentService.RESULT_START:                     showIndeterminateProgress();                     break;                 case MyIntentService.RESULT_ENDED:                     updateResultList(data);                     break;                 case MyIntentService.RESULT_ERROR:                     showErrorMessage();                     break;             }         }     } }; 

2. Register and unregister your BroadcastReceiver:

@Override public void onResume(){     super.onResume();     registerReceiver(mReceiver, new IntentFilter(MyIntentService.SERVICE_BROADCAST)); }  @Override public void onPause() {     super.onPause();     unregisterReceiver(mReceiver); } 

3. Start your Service:

searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener()     {         @Override         public boolean onQueryTextSubmit(String query)         {             return false;         }         @Override         public boolean onQueryTextChange(String newText)         {             if (!newText.trim().equals(""))             {                 Intent i = new Intent(this, MyIntentService.class);                 i.putExtra("MyQuery",newText);                 startService(i);                 return false;             }         }     }); 

Sources:

Answers 5

Use TextWatcher in its afterTextChanged method write your search query and call refresh your view from there itself. Also,Use asynchronous way for making API calls so that your UI doesnt get stuck and you can load the response in your refreshView method .

If You Enjoyed This, Take 5 Seconds To Share It

0 comments:

Post a Comment