I have the following issue:
Inside a fragment let say FragmentTest, i am having the following thread:
new Thread(new Runnable() {
public void run() {
...
if (condition) {
if (isAdded()) {
getActivity.runOnUiThread(new Runnable () {
public void run() {
rightEditText.addTextChangedListener(FragmentTest.this);} }
}
}
}
...
}
}).start;
inside of onCreate method.
The FragmentTest implements the TextWatcher interface but none of the interface method is called.
Migrating the comment to the answer:
Why do you need to do this inside a separate thread? I think the problem is that all the UI components run on the main UI thread. Try it without the thread.
I guess no further explanation is needed here. OP migrated his code to the UI thread and it worked.
public class MainActivity extends AppCompatActivity implements TextWatcher {
EditText edttext;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
edttext = (EditText) findViewById(R.id.editText);
edttext.addTextChangedListener(this);
}
#Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
#Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
runOnUiThread(new Runnable() {
#Override
public void run() {
Toast.makeText(MainActivity.this,"change",Toast.LENGTH_SHORT).show();
}
});
}
#Override
public void afterTextChanged(Editable editable) {
}
}
Related
Currently, I need to capture the final appeared text in EditText.
Here's my simple code.
MainActivity.java
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
EditText editText = findViewById(R.id.edit_text);
editText.addTextChangedListener(new TextWatcher() {
#Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
#Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
#Override
public void afterTextChanged(Editable editable) {
Log.i("CHEOK", ">>>" + editable.toString() + "<<<");
doSomething(editable.toString());
}
private void doSomething() {}
});
}
}
activity_main.xml
<EditText
android:id="#+id/edit_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textMultiLine|textNoSuggestions"
android:imeOptions="actionSend" />
Here's how it behave.
When there's no spelling suggestion
When I press ENTER
afterTextChanged is being triggered one time with the following output.
>>>123
456<<<
When spelling suggestion is there
When I press ENTER
afterTextChanged is being triggered multiple time with the following output.
>>>def<<<
>>><<<
>>>abc
<<<
>>>abc
def<<<
I'm not interested the intermediate text in between. I'm only interested in final text (which is abc\ndef)
How possible can I have something like
#Override
public void afterTextChanged(Editable editable) {
if (isFinalText(edittable.toString())) {
doSomething(editable.toString());
}
}
without turning off spelling suggestion.
P/S
I don't mind to extends EditText, and do some hacking within it. However, I had tried to override dispatchKeyEvent and onKeyPreIme in EditText. Not sure why they are not being called.
P/S/S
I'm also try onEditorAction technique as discussed in https://stackoverflow.com/a/8063533/72437 It won't work for my case as my EditText is multi-line.
Finally I come to the conclusion :
editText.addTextChangedListener(new TextWatcher() {
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
#Override
public void afterTextChanged(Editable s) {
if (prevString.length() >= s.length()) {
if (userIsInteracting) {
doSomething(s.toString());
}
} else {
doSomething(s.toString());
}
prevString = s.toString();
}
});
editText.setOnKeyListener(new View.OnKeyListener() {
#Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_DEL)
userIsInteracting = true;
Log.d("key event", keyCode + event.toString());
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
userIsInteracting = false;
}
}, 1000);
return false;
}
});
Do try it out, It will work for sure. I tried and working perfectly.
Happy Coding!!!
This is a correct solution to solve my faced problem. The key is to use
editText.post
Solution
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final EditText editText = findViewById(R.id.edit_text);
editText.addTextChangedListener(new TextWatcher() {
#Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
#Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
#Override
public void afterTextChanged(final Editable editable) {
final String originalString = editable.toString();
editText.post(new Runnable() {
#Override
public void run() {
String text = editText.getText().toString();
if (text.equals(originalString)) {
Log.i("CHEOK", originalString);
}
}
});
}
});
}
}
The idea is, when the time posted function is executed, editText.getText() is returning a complete text (abc\ndef)
Adding if (text.equals(originalString)), is to ignore 2 intermediate texts in between (def and abc\n)
Im using Places autocomplete for Android Library below is my code:
private void callGoogleAutoComplete(String newText) {
AutocompleteFilter typeFilter = new AutocompleteFilter.Builder()
.setCountry("PK")
.build();
Task<AutocompletePredictionBufferResponse> results=mGeoDataClient.getAutocompletePredictions(newText,myBounds,typeFilter);
results.addOnCompleteListener(new OnCompleteListener<AutocompletePredictionBufferResponse>() {
#Override
public void onComplete(#NonNull Task<AutocompletePredictionBufferResponse> task) {
try {
String response="";
} catch (Exception e) {
e.printStackTrace();
}
}
});
results.addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
}
});
results.addOnSuccessListener(new OnSuccessListener<AutocompletePredictionBufferResponse>() {
#Override
public void onSuccess(AutocompletePredictionBufferResponse autocompletePredictions) {
}
});
}
Above method is called every time when text change in EditText, I want to cancel pervious call (Task) as on every character task is being generated. But Im unable to cancel Task.
Note
I only posted necessary code for Listeners only.
I think it's a better way to delay user input. Wait for user finished typing then call your method it helps you. Like this way
editText.addTextChangedListener(
new TextWatcher() {
#Override public void onTextChanged(CharSequence s, int start, int before, int count) { }
#Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { }
private Timer timer=new Timer();
private final long DELAY = 1000; // milliseconds
#Override
public void afterTextChanged(final Editable s) {
timer.cancel();
timer = new Timer();
timer.schedule(
new TimerTask() {
#Override
public void run() {
// TODO: do what you need here (refresh list)
// you will probably need to use runOnUiThread(Runnable action) for some specific actions
}
},
DELAY
);
}
}
);
I have an AutoCompleteTextView in my layout. After the user entered the first character, I'd like to do an API call, which I'm doing in an AsyncTask. I've used addTextChangedListener and I'm doing the API call on TextChanged. But the problem is that the API call is getting done each time the user makes any change to the AutoCompleteTextView.
But I'd want the API call to happen only once, that is after the first character is inputted. How do I achieve this ?
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_places_search);
search_airport = (AutoCompleteTextView) findViewById(R.id.place_search);
autocompleteadapter = new ArrayAdapter(this, android.R.layout.simple_list_item_1, airports);
search_airport.setAdapter(autocompleteadapter);
search_airport.addTextChangedListener(new TextWatcher() {
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
mAirport = new AsyncTaskAirport(search_airport.getEditableText().toString().substring(0, 1));
mAirport.execute((Void) null);
}
#Override
public void afterTextChanged(Editable s) {
}
});
}
try this,
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
if(s.toString().trim().length()==1){
mAirport = new AsyncTaskAirport(search_airport.getEditableText().toString().substring(0, 1));
mAirport.execute((Void) null);
}
}
You can solve your problem with a timer.Here is how
#Override
public void onTextChanged(CharSequence s, int start, int before, int count)
{
int COMPLETION_DELAY = 2000;
if (timer != null)
{
timer.cancel();
timer.purge();
timer = null;
}
timer = new Timer();
timer.schedule(new TimerTask()
{
#Override
public void run()
{
new Handler(Looper.getMainLooper()).post(new Runnable()
{
#Override
public void run()
{
if (s.toString().length() >= appCompatAutoCompleteTextView.getThreshold())
{
//CALL WebService Here
}
}
});
}
}, COMPLETION_DELAY);
}
now your service will not be called when user making changes while typing in auto complete. service will only be called once user stops + 2 Second.
I use this code for AutoCompleteTextView - so when you delete the last character to show the list. But mAutoCompleteTextView.showDropDown(); dont work.
mAutoCompleteTextView.addTextChangedListener(new TextWatcher() {
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
#Override
public void afterTextChanged(Editable s) {
if (s.toString().equals("")) {
mAutoCompleteTextView.showDropDown();
}
}
});
When initializing the widget, I remembered the adapter in a class field.
use this to set adapter
mAdapter = (ArrayAdapter<String>)actv.getAdapter(); // mAdapter is a class field
actv.setText("Tim Hortons");
actv.setSelection(0, actv.getText().length());
actv.setAdapter((ArrayAdapter<String>)null); // turn off the adapter
actv.requestFocus();
Handler handler = new Handler() {
public void handleMessage(Message msg) {
((AutoCompleteTextView)msg.obj).setAdapter(mAdapter);
};
Message msg = mHandler.obtainMessage();
msg.obj = actv;
handler.sendMessageDelayed(msg, 200);
hope this will help you
I am doing such thing
Add a timer to the autocompletes for .5 seconds before
sending a request to the server. If the user types before the
.5 timer, reset the timer.
i am trying inside of onTextChanged()
public void onTextChanged(CharSequence s, int start, int before, int count) {
/* String newText = s.toString();
if(!newText.trim().equals(""))
Autocompletes_Timer(newText);*/
}
private Handler handler;
private void Autocompletes_Timer(final String newText) {
if(handler!= null)
handler.removeCallbacksAndMessages(null);
handler = new Handler();
handler.postDelayed(runnable(newText), 500);
}
please suggest me.
public class SomeClass extends Activity implements TextWatcher {
private Handler serverHandler;
#Override
public void onCreate(Bundle savedInstance) {
serverHandler = new Handler();
...
}
...
public void onTextChanged(CharSequence s, int start, int before, int count) {
if(!newText.trim().equals(""))
serverHandler.removeCallbacksAndMessages(null);
serverHandler.postDelayed(new Runnable() {
#Override
public void run() {
//Do somthing there
}
}, 500);
}
}
}
try that:
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
//Do somthing there
}
}, 5000);