1

In the Android app, I have an EditText which should replace certain strings with values from app data.

for e.g. if user types $username it should get replaced with the name of whichever user is currently logged in.

The Editable parameter in afterTextChanged() method of TextWatcher applied on EditText replaces the $username with correct value but the problem is that after the $username is replaced with actual username if I press any character after that it is appended with username followed by pressed character.

e.g.

Say current logged in username is Joe

a. if the input is Hi this is @username

b. afterTextChanged() changes it to Hi this is Joe

c. Now if I press any other character(say I press g OR space) then text in EditText changes to Hi this is Joeusernameg OR Hi this is Joeusername

How do I get output as in step b?

etTemplateMessage.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) {
            final String strUserNameCode = "$username";
            String text = s.toString();
            if(text.contains(strUserNameCode)){
                int startIndex = text.indexOf(strUserNameCode);
                int endIndex = startIndex + strUserNameCode.length();
                Editable profileName = new SpannableStringBuilder(FileUtil.getUTF8String(settingDTO.getProfileName()));
                s.replace(startIndex, endIndex, profileName);
            }

        }
    });
Phantômaxx
  • 37,901
  • 21
  • 84
  • 115
Chandan Pednekar
  • 525
  • 5
  • 19

1 Answers1

3

on your afterTextChange method you should set text to the edit text. And String has replace(CharSequence old, CharSequence new) method you can also use it. like this,

PublishSubject publishSubject = PublishSubject.create();
        publishSubject.debounce(200, TimeUnit.MILLISECONDS)
                .subscribeOn(Schedulers.newThread())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(query -> onTextChanged(query.toString()));


void onTextChanged(String text){
 final String strUserNameCode = "$username";
     etTemplateMessage.setText(text.replace(strUserNameCode, FileUtil.getUTF8String(settingDTO.getProfileName())));
}

and on your aftertextChange method call publishSubject.onNext( s.toString())

  • Note that you can achieve this with RxJava.
Rob
  • 886
  • 9
  • 16
  • I already tried this. When is set etTemplateMessage.setText() inside afterTextChanged() the app hangs as soon as I hit/ type `e` in $username. Any ideas? – Chandan Pednekar Apr 03 '19 at 12:42
  • You can do this with rxjava. You can create PublishSubject object and configure it with debounce 200 milliseconds. And when you stop typing it will be work only that time. I will update my answer so you can see it. – Rob Apr 03 '19 at 12:49
  • My fault. Your solution works. I was calling text.replace() function just before etTemplateMessage.setText(). Hence the replaced text got ignored and the text in `EditText` never changed. But since I called `setText()` method and the text never changed. It went into an infinite loop since `setText() fires text changed event`. Thanks. `PublishSubject` was not required. – Chandan Pednekar Apr 03 '19 at 12:56
  • Good to know it. – Rob Apr 03 '19 at 12:58