0

I'm implement an TextInputEditText with RxBinding.

Problem: When I do some math operation on first TextInputEditText and set the result to another TextInputEditText, The screen is not responding. When I start to type another digit, its not displayed in the edit text. I know why this happened, but don't know how to fix. For more detail, please check the code below.

Code:

class NumberSystemFragment : Fragment() {
  override fun onCreateView() { ... }
  override fun onViewCreated() {
    binding?.run {
      // It still ok if just observe a single edit text
      etBinary.observeInput().subscribe {
        val dec = it.fold(0L) { acc, el ->
          (acc * 2) + el.digitToInt(radix = 2)
        }
        val oct = dec.toString(8)
        val hex = dec.toString(16)

        etDecimal.setText(dec.toString())
        etOctal.setText(oct)
        etHexadecimal.setText(hex)
      }

      // But, when I add more EditText, the screen will not responding.
      // I know why this can happen, because when I set the result from operation above,
      // and display it to another EditTexts, then the other EditText will begin to observe its input too.
      // Then the racing condition or whatever it is, will occur.
      etDecimal.observeInput().subscribe {
        val bin = it.toLong().toString(2)
        val oct = it.toLong().toString(8)
        val hex = it.toLong().toString(16)

        etBinary.setText(bin)
        etOctal.setText(oct)
        etHexadecimal.setText(hex)
      }
    }
  }

  private fun <T : EditText> T.observeInput() =
    RxTextView.textChanges(this)
      .skipInitialValue()
      .subscribeOn(Schedulers.io())
      .observeOn(AndroidSchedulers.mainThread())
      .map(CharSequence::toString)
      .publish()
      .refCount()
}

Sorry, I'm new with RxJava, RxBinding, etc.

dans
  • 17
  • 5
  • `subscribeOn(Schedulers.io())` makes no sense. Afaik, you are supposed to subscribe to the RxBinding stuff on the main thread, which I presume you are already on in `observeInput`. – akarnokd May 26 '22 at 09:28
  • @akarnokd Then, which schedulers should I use sir? To replace the Schedulers.io(). – dans May 26 '22 at 09:46
  • Use none. ¤¤¤¤¤¤¤ – akarnokd May 26 '22 at 10:21
  • @akarnokd ok sir, but the problem is still not solved. There is the link (https://i.stack.imgur.com/BrWG9.gif). I don't know, that can be say as not responding or not. – dans May 26 '22 at 10:25
  • Check your log for errors, add an onError handler to the `subscribe` calls. Your code probably crashes somewhere else now. – akarnokd May 26 '22 at 10:41
  • @akarnokd I've launched my app about 40minutes but it still doesn't show any error on the log. The condition is still same, not displaying the next number I've inputted. And Its not freeze because I can press another edit text. – dans May 26 '22 at 13:49
  • @akarnokd There is the link: https://imgur.com/kCSf95k – dans May 26 '22 at 14:11
  • Something must be wrong in the code not shown. Since I can't remotely look at or debug your code, please post a standalone project somewhere (i.e., GitHub) that demonstrates your problem. – akarnokd May 26 '22 at 14:47
  • @akarnokd Sorry for my late reply sir. Link of my sample project: https://github.com/dansampl/EditTextWithRxJavaSampleApp. – dans May 27 '22 at 14:01
  • @akarnokd did you find the problem sir? – dans May 30 '22 at 06:32

1 Answers1

0

Two issues.

  1. You have created a feedback loop by setting text on the other editors, which then trigger updates on the current editor.
  2. If your code crashes, it will stop listening to values.

First of all, make these extension method changes:

private fun <T: EditText> T.observeInput() =
    RxTextView.textChanges(this)
        .skipInitialValue()
        .map(CharSequence::toString) // <------------------ order matters
        .distinctUntilChanged() // <----------------------- order matters
        .observeOn(AndroidSchedulers.mainThread())
        .publish()
        .refCount()

private fun TextInputEditText.setText(text: CharSequence, onlyIfChanged: Boolean) {
    if (onlyIfChanged) {
        if (Objects.equals(this.text.toString(), text.toString())) {
            return;
        }
    }
    this.setText(text);
}

Then, update your onNext handlers:

// etBinary

// store calculation data
try {
    Log.d("XYZ-etBinary", t);
    val decResult = t.fold(0L) { acc, element ->
        (acc * 2) + element.digitToInt(2)
    }
    val octResult = decResult.toString(8)
    val hexResult = decResult.toString(16).uppercase()

    // and display the results to another edit text which corresponds with their radix representation
    etDecimal.setText(decResult.toString(), true)
    etOctal.setText(octResult, true)
    etHexadecimal.setText(hexResult, true)
} catch (e: Throwable) {
    Log.e("XYZ-etBinary", e.message.toString())
}
// etDecimal

// store calculation data
try {
    Log.d("XYZ-etDecimal", t);
    val binResult = t.toLong().toString(2)
    val octResult = t.toLong().toString(8)
    val hexResult = t.toLong().toString(16).uppercase()

    // and display the results to another edit text which corresponds with their radix representation
    etBinary.setText(binResult, true)
    etOctal.setText(octResult, true)
    etHexadecimal.setText(hexResult, true)
} catch (e: Throwable) {
    Log.e("XYZ-etDecimal", e.message.toString())
}

Also posted it as a Pull Request on your repo: https://github.com/dansampl/EditTextWithRxJavaSampleApp/pull/1/files

akarnokd
  • 69,132
  • 14
  • 157
  • 192
  • Wow! Thank you so much sir. Thanks for helping me to solve this problem, your solution is really works. But may I ask one more question sir? – dans May 31 '22 at 10:46
  • My question is: There is a best way to handle input that provided by user? For example when user input a number/digit/symbol very quickly to an input (e.g. decimal input) using a computer keyboard (If they use this app on personal computer with emulator). If they do so, the input will stuck. When I check why did this happen, I saw the log were flooded with same result emitted by observer. The result in here is the digit that was only displayed on the input before it stuck, which has been converted. 19(decimal) -> "10011(binary)" – dans May 31 '22 at 11:10
  • Does it happen in the example app I fixed for you? If not, you adapted the solution wrongly in your main application. – akarnokd May 31 '22 at 18:11
  • Yes it happen in the example app, this case is quite rare sir, sometimes it works but sometimes it doesn't. – dans Jun 03 '22 at 07:33