Android Search View always gives the same result - android

I am using search view in my app to search through a list of item and run a query on a URL.
I am using the following code :
public boolean onQueryTextSubmit(String s) {
mSearchView.setQuery("", false);
mSearchView.clearFocus();
mSearchView.setIconified(true);
url+="intitle="+s+"&site=stackoverflow";
// mSearchView.setQuery("", false);
// mSearchView.clearFocus();
// mSearchView.setIconified(true);
new JSONTask().execute();
return false;
}
So I modify the URL based on the search query and run the async task to load the list of results.
This works fine the first time I search, but all subsequent searches give the same result even when the query is changed.
How do I fix this ?
Thanks !

If the variable url is global, you should set it's value to the initial value at the end of your onQueryTextSubmit(String s) method, because then on every next step it will concat the strings ( += ) and will be something like this url = %your original value%intitle="s"&site=stackoverflowintitle="s"&site=stackoverflowintitle="s"&site=stackoverflow

Related

Android how to search in empty query

I have an search view, below the search view contain edittext. i can check based on search view query and edittext content. Event the query is empty i need to search. Is this is
I have tried this but doesn't work
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
#Override
public boolean onQueryTextSubmit(String query) {
Log.i("MyApp", searchView.getQuery().toString());
consultarListaParadas(searchView.getQuery().toString());
getActivity().runOnUiThread(new Runnable() {
public void run() {
adaptadorListaParadasBus.setListaParadas(listaParadas);
adaptadorListaParadasBus.notifyDataSetChanged();
}
});
return true;
}
#Override
public boolean onQueryTextChange(String newText) {
if(newText.equals("")){
this.onQueryTextSubmit("");
}
return true;
}
});
Try with below condition inside onQueryTextChange() method, like below
if(TextUtils.isEmpty(newText)){
// Do your stuff here.
}
First thing first..
onQueryTextChange() will not be fired until you are not entering any text
, Instead what you can do is, make a call to search api with empty query param and get results...
Once text changes - You can use conditions given in other answers!! even your condition will work too.

Getting "Link text" of the link displayed in WebView

I have Android WebView which displays some links as: Link1TextLink2Text Now I would like to retrieve Link1Text and Link2Text when I long press these links. I have contextMenu implemented in the code and I could successfully get the link urls (http://link1.html, http://link2.html) using HitTestResult getExtra() method but how ccan I get those link texts ?FYI, I require those link texts for implementing "Copy link text" option in the contextMenu.
To get the text of an achor link:
I. Hook a touchstart listener to every web pages in the onPageFinished() callback of WebViewClient via evaluateJavascript. like:
//Javascripts to evaluate in onPageFinished
const w=window;
w.addEventListener('touchstart',wrappedOnDownFunc);
function wrappedOnDownFunc(e){
if(e.touches.length==1){
w._touchtarget = e.touches[0].target;
}
console.log('hey touched something ' +w._touchtarget);
}
note we've saved the touch target.
II. Then implement OnLongClicklisenter for webview. use evaluateJavascript again when you long pressed on a link object:
#Override
public boolean onLongClick(View v) {
WebView.HitTestResult result = ((WebView)v).getHitTestResult();
if (null == result) return false;
int type = result.getType();
switch (type) {
case WebView.HitTestResult.SRC_ANCHOR_TYPE:
if(result.getExtra()!=null){
((WebView)v).evaluateJavascript("window._touchtarget?window._touchtarget.innerText:''", new ValueCallback<String>() {
#Override
public void onReceiveValue(String value) {
System.out.println("hey received link text : "+value);
}
});
}
return true;
}
return false;
}
What's more, we can even choose to select the text of the anchor element! Actually this is one of the options that samsung browser offers when you long-pressed an tag .
To achieve this, we still need that recorded touch target. Besides we need 2 new javascript methods:
function selectTouchtarget(){
var tt = w._touchtarget;
if(tt){
w._touchtarget_href = tt.getAttribute("href");
tt.removeAttribute("href");
var sel = w.getSelection();
var range = document.createRange();
range.selectNodeContents(tt);
sel.removeAllRanges();
sel.addRange(range);
}
}
function restoreTouchtarget(){
var tt = w._touchtarget;
if(tt){
tt.setAttribute("href", w._touchtarget_href);
}
}
Finnaly in the onLongClick listener, instead of just fetch the innerText, we programmatically set the selection, trigger the action menu bar, and restore the removed href attribute of our touch target.
case WebViewmy.HitTestResult.SRC_ANCHOR_TYPE:
if(result.getExtra()!=null){
WebViewmy mWebView = ((WebViewmy)v);
mWebView.evaluateJavascript("selectTouchtarget()", new ValueCallback<String>() {
#Override
public void onReceiveValue(String value) {
/* bring in action mode by a fake click on the programmatically selected text. */
MotionEvent te = MotionEvent.obtain(0,0,KeyEvent.ACTION_DOWN,mWebView.lastX,mWebView.lastY,0);
mWebView.dispatchTouchEvent(te);
te.setAction(KeyEvent.ACTION_UP);
mWebView.dispatchTouchEvent(te);
te.recycle();
//if it's not delayed for a while or the href attribute is not removed, then the above code would click into
// the anchor element instead of select it's text.
/* restore href attribute */
mWebView.postDelayed(() -> mWebView.evaluateJavascript("restoreTouchtarget()", null), 100);
}
});
}
return true;
In my case, I've extended the WebView as WebViewmy to record last touched positions, lastX and lastY, in the onTouchEvent method.
Unfortunately, a clear, official way to do this is not available. Although, there are two APIs (selectText and copySelection) which are pending API council approval, that may help to do this, but they are not available at the moment.

Does EditText.getText().getLength() return 0 when it contains a hint?

I have some code, but it is not working as expected. My logic doesn't seem to be faulty, so I think it is an implementation error. My code:
public boolean[] party_check(){
Date date_ET = new Date(party_dateET.getYear(), party_dateET.getMonth(), party_dateET.getDayOfMonth());///Date is deprecated,
///but easy to handle
///this is used to test the date contained in the datepicker, party_dateET. If it is before the day today, then it will not write,
///and a message is displayed
boolean[] return_array = new boolean[4];
///EditText party_titleET;
///EditText party_timeET;
///EditText party_dateET;
///EditText party_venueET;
return_array[0] = true;
if(party_titleET.getText().length() == 0){
return_array[1] = false;
return_array[0] = false;
}else{
return_array[1] = true;
}
if(date_ET.before(Calendar.getInstance().getTime()) == true){
return_array[2] = false;
return_array[0] = false;
///tests that the date entered is not invalid, ie. is in the future.
///not test for time. I could say that if time == 00:00, then don't run, or use a listener to check if it has changed,
///using a boolean value. But this would not really benefit the task much, so I haven't. It would also
///take more coding, and more complex coding.
}else{
return_array[2] = true;
}
if(party_venueET.getText().length() == 0){
return_array[3] = false;
return_array[0] = false;
}else{
return_array[3] = true;
}
return return_array;
///return_array[0] - 1st value in array - is used as toggle as to whether the party is ready or not.
///return_array[1-4] are used to indicate to the user which textbox is empty/ has a problem.
}
However it does not do what I expect it to do when I return the boolean array. This is used for testing whether the user has entered a text value into the EditText's.
However it does not work as expected. Is my logic faulty, or I have implemented it wrong? Thanks for the help!!
The hint does not get returned, when you use getText(). You can use getHint() though.
Text and Hint are different properties.
So the Text will be empty, if the hint is shown.
Let's say that the hint is a "dress" for the text (not to let it "naked"), but it's not the text itself.

Android Async inside a OnGroupClickListener function

I have a Exapandable Listview that needs the child rows to be added dynamically when someone clicks on a group row. Best way was to send a AsyncHttp request to my server and the server responds with a json which I parse into and Object. The problem with this is that I need to return true on the OnClickGroupListener if json is empty and or false if json has data. How would I go bout doing this?
UPDATE*******
I added the Following to my code:
private boolean childrenLoaded;
public boolean onGroupClick(ExpandableListView expandableListView, View view, int i, long l) {
if(!childrenLoaded){
getChildren(i);
}else{
return false;
}
return true;
}
public void getChildren(int position){
//HttpAsync request here
onSuccess(json){
childrenLoaded = true;
if (json has data){
listview.performclick(arguments for perform click);
}else{
exit
}
}
}
Looking at the OnGroupClickListener documentation, it appears you only need to return true if the click was handled by you.
Returns
True if the click was handled
If you would like to track some other true/false outcome (such as the emptyness of a json response) it should conceptually and literally be handled elsewhere. For example, you could have a small progress indicator that shows on the list item when the click happens (return true because you obviously handled the click), and stop the progress bar when your network request completes with either a success or a failure.

Android: How to get search suggestions asynchronously from the web?

I have created a searchable activity. Now, i want to add search suggestions that are taken from web service. I want to get those suggestions asynchronously. According to Adding Custom Suggestions I need to override the query method, do my suggestion search, build my own MatrixCursor and return it. but this is the problem, my request for getting the suggestion is an asynchronically one. so when result is back from net it out side of query method's scope.
Here is an example of SearchView with suggestions coming from a network service (I used Retrofit):
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_search_activity, menu);
final SearchView searchView = (SearchView) MenuItemCompat.getActionView(menu.findItem(R.id.search));
final CursorAdapter suggestionAdapter = new SimpleCursorAdapter(this,
android.R.layout.simple_list_item_1,
null,
new String[]{SearchManager.SUGGEST_COLUMN_TEXT_1},
new int[]{android.R.id.text1},
0);
final List<String> suggestions = new ArrayList<>();
searchView.setSuggestionsAdapter(suggestionAdapter);
searchView.setOnSuggestionListener(new SearchView.OnSuggestionListener() {
#Override
public boolean onSuggestionSelect(int position) {
return false;
}
#Override
public boolean onSuggestionClick(int position) {
searchView.setQuery(suggestions.get(position), false);
searchView.clearFocus();
doSearch(suggestions.get(position));
return true;
}
});
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
#Override
public boolean onQueryTextSubmit(String query) {
return false;
}
#Override
public boolean onQueryTextChange(String newText) {
MyApp.autocompleteService.search(newText, new Callback<Autocomplete>() {
#Override
public void success(Autocomplete autocomplete, Response response) {
suggestions.clear();
suggestions.addAll(autocomplete.suggestions);
String[] columns = {
BaseColumns._ID,
SearchManager.SUGGEST_COLUMN_TEXT_1,
SearchManager.SUGGEST_COLUMN_INTENT_DATA
};
MatrixCursor cursor = new MatrixCursor(columns);
for (int i = 0; i < autocomplete.suggestions.size(); i++) {
String[] tmp = {Integer.toString(i), autocomplete.suggestions.get(i), autocomplete.suggestions.get(i)};
cursor.addRow(tmp);
}
suggestionAdapter.swapCursor(cursor);
}
#Override
public void failure(RetrofitError error) {
Toast.makeText(SearchFoodActivity.this, error.getMessage(), Toast.LENGTH_SHORT).show();
Log.w("autocompleteService", error.getMessage());
}
});
return false;
}
});
return true;
}
It seems that the request to the suggestion content provider is not run on the UI thread, anyway, according to this answer: https://stackoverflow.com/a/12895381/621690 .
If you can change your http request you could simply call it blocking inside the query method. Might help to listen for interruptions or other signals (custom ones maybe) to stop unnecessary requests.
Another option - if you do not want to change any request classes that are already asynchronous (like if you are using Robospice) - should be to just return the MatrixCursor reference and populate it later on. The AbstractCursor class already implements the Observer pattern and sends out notifications in case of changes. If the search system is listening it should handle any changes in the data. I have yet to implement that myself so I cannot confirm that it will work out as nicely as I picture it. (Have a look at CursorLoader's source for more inspiration.)
And, anyway, isn't that the whole point of a cursor? Otherwise we could simply return a list with data.
UPDATE:
For me, using a MatrixCursor didn't work out. Instead, I have implemented two other solutions:
Using the AutoCompleteTextField in combination with a custom subclass of ArrayAdapter which itself uses a custom subclass of Filter. The method Filter#performFiltering() (which I override with the synchronous call to the remote service) is called asynchronously and the UI thread is not blocked.
Using the SearchWidget with a SearchableActivity and a custom ArrayAdapter (without custom Filter). When the search intent comes in, the remote request is started (Robospice) and when it comes back via callback, I call the following custom method on my ArrayAdapter<Tag> subclass:
public void addTags(List<Tag> items) {
if (items != null && items.size() > 0) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
super.setNotifyOnChange(false);
for (Tag tag : items) {
super.add(tag);
}
super.notifyDataSetChanged();
} else {
super.addAll(items);
}
}
}
This method takes care of triggering the notifications on the adapter and thus the search result list.
The closest thing I have found to solve this, is by using a ContentProvider and do the network request on the Query method of your provider (even when this goes against the best practices), with the result you can create a MatrixCursor as it's show here and here.
I'm still searching for other options like using a SyncAdapter, which seems overwhelming for the purpose of just showing suggestions that aren't used anywhere else.
Another option, that I took to do this asynchronously is to use an AutoCompleteTextView, that way you can create a custom adapter, where you can implement the getFilter function as it is shown in this answer.

Categories

Resources