Rx trong Kotlin (P2)
Bài đăng này đã không được cập nhật trong 7 năm
Tiếp theo phần 1
Mình xin đi vào thực hành một ví dụ cho các bạn dễ hình dung
Ví dụ đơn giản này sẽ như sau, nhập chuỗi string vào EditText và sau đó tự động response hiển thị lên TextView, response sẽ được gọi bằng một API cứ 1s sau khi nhập text.
Đơn giản như sau:
Để dễ hiểu hơn, mình sẽ trình bày cả 2 cách reactive
và non-reactive
Non-reactive
Mình sử dụng hàm schedule()
của Timer
để chạy chạy sau cử mỗi 1s, đừng quên dùng runOnUiThread()
nhé.
Đây là code khi viết bằng Java
//Java
Timer timer = new Timer();
final TextView textView = (TextView) findViewById(R.id.textView);
final EditText editText = (EditText) findViewById(R.id.editText);
editText.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
}
@Override
public void onTextChanged(final CharSequence s, int start, int before,
int count) {
if (timer != null)
timer.cancel();
}
@Override
public void afterTextChanged(final Editable s) {
timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
runOnUiThread(new Runnable() {
@Override
public void run() {
textView.setText("Output : " + editText.getText());
}
});
}
}, 1000);
}
});
Đây là code khi trình bày bằng Kotlin
//Kotlin
var timer: Timer? = Timer()
val editTextStop = findViewById(R.id.editText) as EditText
editTextStop.addTextChangedListener(object : TextWatcher {
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) = Unit
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
timer?.cancel()
}
override fun afterTextChanged(s: Editable) {
timer = Timer()
timer!!.schedule(object : TimerTask() {
override fun run() {
runOnUiThread { textView.setText("Output : " + editTextStop.getText()) }
}
}, 1000)
}
})
Reactive
Với reactive chúng ta cần làm theo 3 steps:
1-Tạo một observable
2-Sử dụng debounce
để set delay 1s
3-Subscribe
nó
Bạn có thể làm như sau, với Java:
Observable.create(new Observable.OnSubscribe<String>() {
@Override
public void call(final Subscriber<? super String> subscriber) {
editText.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(final CharSequence s, final int start, final int count, final int after) {
}
@Override
public void onTextChanged(final CharSequence s, final int start, final int before, final int count) {
subscriber.onNext(s.toString());
}
@Override
public void afterTextChanged(final Editable s) {
}
});
}
})
.debounce(1000, TimeUnit.MILLISECONDS)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Action1<String>() {
@Override
public void call(final String s) {
textView.setText("Output : " + s);
}
});
Còn khi bạn dùng Kotlin:
Observable.create(Observable.OnSubscribe<String> { subscriber ->
editText.addTextChangedListener(object : TextWatcher {
override fun afterTextChanged(s: Editable?) = Unit
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) = Unit
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int)
= subscriber.onNext(s.toString())
})
}).debounce(1000, TimeUnit.MILLISECONDS)
.observeOn(AndroidSchedulers.mainThread())
.subscribe({
text ->
textView.text = "Output : " + text
})
RxBinding
Đoạn code trên có quá nhiều các boilerplate, nhìn quá dài dòng, để hạn chế điều này và giúp code của bạn ngắn hơn, loại bỏ được các boilerplate này ta có thể dùng RxBindings với rất nhiều cách binding cho UI widgets. Có thể dùng trong cả Java và Kotlin. Với Java, ta dùng Retrolambda và RxBinding, ví dụ code như sau:
//Java with Retrolambda and RxBinding
RxTextView.afterTextChangeEvents(editText)
.debounce(1000,TimeUnit.MILLISECONDS)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(tvChangeEvent -> {
textView.setText("Output : " + tvChangeEvent.view()
.getText());
});
Với Kotlin, ta cũng sử dụng RxBinding
//Kotlin with RxBinding
RxTextView.afterTextChangeEvents(editText)
.debounce(1000, TimeUnit.MILLISECONDS)
.observeOn(AndroidSchedulers.mainThread())
.subscribe { tvChangeEvent ->
textView.text = "Output : " + tvChangeEvent.view().text
}
Không còn nhiều các đoạn code thừa nữa, cũng giúp rất nhiều cho maintainer dễ dàng hiểu được code của bạn. Hy vọng bài này đã giúp các bạn một phần hiểu được cách dùng Rx trong Java và đặc biệt là Kotlin, chúc bạn vui với ngôn ngữ mới này!
All rights reserved