How to get the result from EventObserver in Android Java - android

I am following this post: https://stackoverflow.com/questions/56071990/android-architecture-singleliveevent-and-eventobserver-practicle-example-in-java
public class Event<T> {
private boolean hasBeenHandled = false;
private T content;
public Event(T content) {
this.content = content;
}
public T getContentIfNotHandled() {
if (hasBeenHandled) {
return null;
} else {
hasBeenHandled = true;
return content;
}
}
public boolean isHandled() {
return hasBeenHandled;
}
}
import androidx.annotation.Nullable;
import androidx.lifecycle.Observer;
public class EventObserver<T> implements Observer<Event<T>> {
private OnEventChanged onEventChanged;
public EventObserver(OnEventChanged onEventChanged) {
this.onEventChanged = onEventChanged;
}
#Override
public void onChanged(#Nullable Event<T> tEvent) {
if (tEvent != null && tEvent.getContentIfNotHandled() != null && onEventChanged != null)
onEventChanged.onUnhandledContent(tEvent.getContentIfNotHandled());
}
interface OnEventChanged<T> {
void onUnhandledContent(T data);
}
}
I have this in my repository:
private MutableLiveData<Event<String>> _amsRepositoryError = new MutableLiveData<>();
public MutableLiveData<Event<UserModel>> amsLoginSuccessReply(){return _amsLoginSuccessReply;}
_amsLoginSuccessReply.postValue(new Event(userModel));
And I catch this in my viewmodel:
amsRepository.amsLoginSuccessReply().observe(mLifeCycleOwner, new EventObserver<UserModel>(data -> {
// HOW DO I GET THE data here.
}));
on the observe, how do I get the values of the data?

Related

Android PowerMockito of TextUtils returns wrong result

I have updated to Android 31 and Android Studio Dolphin and now my tests are failing because of TextUtils.isEmpty() returns wrong result.
I have this method to mock TextUtils.isEmpty().
protected void mockTextUtilsIsEmpty() {
PowerMockito.mockStatic(TextUtils.class);
PowerMockito.when(TextUtils.isEmpty(any(CharSequence.class))).thenAnswer(invocation -> {
String val = (String) invocation.getArguments()[0];
return val == null || val.length() == 0;
});
}
This is my test class.
#RunWith(PowerMockRunner.class) #PrepareForTest(TextUtils.class)
public class CustomerDetailsPresenterTest extends BaseTest {
#Rule TrampolineSchedulerRule trampolineSchedulerRule = new TrampolineSchedulerRule();
#Mock GetCustomerUseCase getCustomerUseCase;
#Mock GetMenuItemsUseCase getMenuItemsUseCase;
#Mock RolesManager rolesManager;
#Mock CustomerDetailsPresenter.View view;
private CustomerDetailsPresenter presenter;
private final int customerId = 1;
#Before public void setUp() {
mockTextUtilsIsEmpty();
presenter = new CustomerDetailsPresenter(getCustomerUseCase, getMenuItemsUseCase, rolesManager);
presenter.setView(view);
}
#Test public void shouldDisplayCustomerWithEmptyData() {
// Given
CustomerDetails customerDetails = CustomerDetails.newBuilder()
.build();
// When
Mockito.when(getCustomerUseCase.execute(customerId)).thenReturn(Single.just(customerDetails));
presenter.getCustomerDetails(customerId);
//Then
Mockito.verify(view).showRefreshing();
Mockito.verify(view).hideRefreshing();
Mockito.verify(view).displayCustomerEmailUnknown();
Mockito.verify(view).displayCustomerNoteUnknown();
}
}
This is my actual class that I want to test.
public class CustomerDetailsPresenter implements Presenter{
private final GetCustomerUseCase getCustomerUseCase;
private final GetMenuItemsUseCase getMenuItemsUseCase;
private final RolesManager rolesManager;
private CompositeDisposable disposables;
private View view;
#Inject public CustomerDetailsPresenter(
GetCustomerUseCase getCustomerUseCase,
GetMenuItemsUseCase getMenuItemsUseCase,
RolesManager rolesManager
) {
this.getCustomerUseCase = getCustomerUseCase;
this.getMenuItemsUseCase = getMenuItemsUseCase;
this.rolesManager = rolesManager;
}
public void setView(View view) {
this.view = view;
}
public void getCustomerDetails(int id) {
disposables = RxUtil.initDisposables(disposables);
if (rolesManager.isUserReadOnly()) {
view.showScreenAsReadOnly();
}
view.showRefreshing();
Disposable disposable = getCustomerUseCase.execute(id)
.doOnSuccess(customerDetails -> view.hideRefreshing())
.subscribe(customerDetails -> {
if (customerDetails != null) {
if (TextUtils.isEmpty(customerDetails.getInvoiceEmail())) {
view.displayCustomerEmailUnknown();
} else {
view.displayCustomerEmail(customerDetails.getInvoiceEmail());
}
if (TextUtils.isEmpty(customerDetails.getBillingNote())) {
view.displayCustomerNoteUnknown();
} else {
view.displayCustomerNote(customerDetails.getBillingNote());
}
view.displayCustomerAddress(customerDetails);
view.displayLastModified(customerDetails);
} else {
view.hideCustomerSecondAndThirdPhones();
}
} else {
view.hideCustomerDetails();
}
},
view::handleError
);
disposables.add(disposable);
What could be the problem?
So, in this part, it always goes to the else part of the statement, and as you can in my unit test that should not happen since I am providing null to invoice email field.
if (TextUtils.isEmpty(customerDetails.getInvoiceEmail())) {
view.displayCustomerEmailUnknown();
} else {
view.displayCustomerEmail(customerDetails.getInvoiceEmail());
}
Any ideas?

How should I code if i want Query specific the with Room? [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 1 year ago.
Improve this question
I am now learing how to save data in a local database using Room in Android Dev Doc. And I had done the Codelab in this links.https://developer.android.com/codelabs/android-room-with-a-view#0 I can Upddate, Insert, Delete and Query all data in table.
Now, I want Query the data with specific id. How should I code in ViewModel and Repository class? Thanks.
My table named "Diary",
Diary.class
#Entity(tableName = "diary_table")
public class Diary {
#PrimaryKey(autoGenerate = true)
private int id;
#ColumnInfo(name = "diary_title")
private String diary_Title;
#ColumnInfo(name = "diary_content")
private String diary_Content;
public Diary(#NonNull String diary_Title, String diary_Content) {
this.diary_Title = diary_Title;
this.diary_Content = diary_Content;
}
public void setDiary_Title(String diary_Title) {
this.diary_Title = diary_Title;
}
public void setDiary_Content(String diary_Content) {
this.diary_Content = diary_Content;
}
public void setId(int id) {
this.id = id;
}
public int getId() {
return id;
}
public String getStrId() {
return String.valueOf(id);
}
public String getDiary_Title() {
return diary_Title;
}
public String getDiary_Content() {
return diary_Content;
}
}
DiaryDao.class
#Dao
public interface DiaryDao {
#Insert
void insertDiaries(Diary... diaries);
#Update
void updateDiaries(Diary... diaries);
#Delete
void deleteDiaries(Diary... diaries);
//删除到一无所有 慎用!
#Query("DELETE FROM diary_table")
void deleteAllDiaries();
#Query("SELECT * FROM diary_table ORDER BY ID ASC")
LiveData<List<Diary>>getAllDiariesLive();//get all diary
#Query("SELECT * FROM diary_table WHERE ID=:id")
LiveData<Diary> getSpecificDiariesLive(int id);//get specific diary
}
DiaryRepository
class DiaryRepository {
private LiveData<Diary> specificDiary;
private LiveData<List<Diary>> allDiariesLive;
private DiaryDao diaryDao;
DiaryRepository(Context context) {
DiaryRoomDatabase diaryRoomDatabase = DiaryRoomDatabase.getDiaryDatabase(context.getApplicationContext());
diaryDao = diaryRoomDatabase.getDiaryDao();
allDiariesLive = diaryDao.getAllDiariesLive();
specificDiary = diaryDao.getSpecificDiariesLive(/**how should i code here***/);
}
void insetDiaries(Diary... diaries) {
new InsertAsyncTask(diaryDao).execute(diaries);
}
void updateDiaries(Diary... diaries) {
new UpdateAsyncTask(diaryDao).execute(diaries);
}
void deleteDiaries(Diary... diaries) {
new DeleteAsyncTask(diaryDao).execute(diaries);
}
void deleteAllDiaries(Diary... diaries) {
new DeleteAllAsyncTask(diaryDao).execute();
}
LiveData<Diary> getSpecificDiary(int i) {return specificDiary; }
LiveData<List<Diary>> getAllDiariesLive() {
return allDiariesLive;
}
static class InsertAsyncTask extends AsyncTask<Diary, Void, Void> {
private DiaryDao diaryDao;
InsertAsyncTask(DiaryDao diaryDao) {
this.diaryDao = diaryDao;
}
#Override
protected Void doInBackground(Diary... diaries) {
diaryDao.insertDiaries(diaries);
return null;
}
}
static class UpdateAsyncTask extends AsyncTask<Diary, Void, Void> {
private DiaryDao diaryDao;
UpdateAsyncTask(DiaryDao diaryDao) {
this.diaryDao = diaryDao;
}
#Override
protected Void doInBackground(Diary... diaries) {
diaryDao.updateDiaries(diaries);
return null;
}
}
static class DeleteAsyncTask extends AsyncTask<Diary, Void, Void> {
private DiaryDao diaryDao;
DeleteAsyncTask(DiaryDao diaryDao) {
this.diaryDao = diaryDao;
}
#Override
protected Void doInBackground(Diary... diaries) {
diaryDao.deleteDiaries(diaries);
return null;
}
}
static class DeleteAllAsyncTask extends AsyncTask<Void, Void, Void> {
private DiaryDao diaryDao;
DeleteAllAsyncTask(DiaryDao diaryDao) {
this.diaryDao = diaryDao;
}
#Override
protected Void doInBackground(Void... voids) {
diaryDao.deleteAllDiaries();
return null;
}
}
}
DiaryViewModel.class
public class DiaryViewModel extends AndroidViewModel {
private DiaryRepository diaryRepository;
public DiaryViewModel(#NonNull Application application) {
super(application);
diaryRepository = new DiaryRepository(application);
}
public LiveData<Diary> getSpecificDiary(/**how should i code here?**/) {
return diaryRepository.getSpecificDiary(i);
}
public LiveData<List<Diary>> getAllDiariesLive() {
return diaryRepository.getAllDiariesLive();
}
public void insertDiaries(Diary... diaries) {
diaryRepository.insetDiaries(diaries);
}
public void updateDiaries(Diary... diaries) { diaryRepository.updateDiaries(diaries); }
public void deleteDiary(Diary... diaries) { diaryRepository.deleteDiaries(diaries);}
public void deleteAllDiaries() {
diaryRepository.deleteAllDiaries();
}
}
I think in DiaryRepository:
class DiaryRepository {
private LiveData<List<Diary>> allDiariesLive;
private DiaryDao diaryDao;
DiaryRepository(Context context) {
DDiaryRoomDatabase diaryRoomDatabase = DiaryRoomDatabase.getDiaryDatabase(context.getApplicationContext());
diaryDao = diaryRoomDatabase.getDiaryDao();
allDiariesLive = diaryDao.getAllDiariesLive();
}
void insetDiaries(Diary... diaries) {
new InsertAsyncTask(diaryDao).execute(diaries);
}
void updateDiaries(Diary... diaries) {
new UpdateAsyncTask(diaryDao).execute(diaries);
}
void deleteDiaries(Diary... diaries) {
new DeleteAsyncTask(diaryDao).execute(diaries);
}
void deleteAllDiaries(Diary... diaries) {
new DeleteAllAsyncTask(diaryDao).execute();
}
LiveData<Diary> getSpecificDiary(int i) {
return diaryDao.getSpecificDiariesLive(i);
}
LiveData<List<Diary>> getAllDiariesLive() {
return allDiariesLive;
}
...
so your ViewModel will be changed to this:
public class DiaryViewModel extends AndroidViewModel {
private DiaryRepository diaryRepository;
public DiaryViewModel(#NonNull Application application) {
super(application);
diaryRepository = new DiaryRepository(application);
}
public LiveData<Diary> getSpecificDiary(int i) {
return diaryRepository.getSpecificDiary(i);
}
...
DiaryRepository.class and ViewModel.class like hosseini sajad code. And i should use this with livedata like follow:
mDiaryViewModel = new ViewModelProvider(activity).get(DiaryViewModel.class);
mDiaryViewModel.getSpecificDiary(pos+1).observe(activity, diary -> {
Log.d("test", "Here is the Title: " + diary.getDiary_Title() + "\n" + "Here is the Content: " +diary.getDiary_Content() );
});

Retrofit response return " NumberFormatexception : Empty string"

i know actually a lot of these kinds of questions, and i have searched on google but i can't find where the error is in my code.
I tried to send a request to fetch data, but it runs the onFailure method which reads "NumberFormatException: Empty string" and the data can't be displayed in the recyclerview, even though I'm also getting a json response as I wanted.
i got this response:
{
"kode":1,
"pesan":"Barang ditemukan",
"data":[
{
"Sat_1":"PT",
"Sat_2":"",
"Isi_2":"",
"KdBrg":"280349191",
"NmBrg":"SILICONE PACIFIER STEP 1A",
"Stock_Akhir":"0",
"Hrg":28000
}
]
}
my object model
public class ModelDataBarang {
private int Isi_2;
private int Isi_3;
private int Isi_4;
private String KdBrg;
private String NmBrg;
private String Sat_1;
private String Sat_2;
private String Sat_3;
private String Sat_4;
private String KdHrgList;
private double Stock_Akhir;
private double HrgJl11;
public double getHrgJl11() {
return HrgJl11;
}
public void setHrgJl11(double hrgJl11) {
HrgJl11 = hrgJl11;
}
private String Hrg;
public String getHrg() {
return Hrg;
}
public void setHrg(String hrg) {
Hrg = hrg;
}
public String getKdHrgList() {
return KdHrgList;
}
public void setKdHrgList(String kdHrgList) {
KdHrgList = kdHrgList;
}
public String getSat_3() {
return this.Sat_3;
}
public void setSat_3(String sat_3) {
this.Sat_3 = sat_3;
}
public String getSat_4() {
return this.Sat_4;
}
public void setSat_4(String sat_4) {
this.Sat_4 = sat_4;
}
public int getIsi_3() {
return this.Isi_3;
}
public void setIsi_3(int isi_3) {
this.Isi_3 = isi_3;
}
public int getIsi_4() {
return this.Isi_4;
}
public void setIsi_4(int isi_4) {
this.Isi_4 = isi_4;
}
public String getKdBrg() {
return this.KdBrg;
}
public void setKdBrg(String kdBrg) {
this.KdBrg = kdBrg;
}
public String getNmBrg() {
return this.NmBrg;
}
public void setNmBrg(String nmBrg) {
this.NmBrg = nmBrg;
}
public String getSat_1() {
return this.Sat_1;
}
public void setSat_1(String sat_1) {
this.Sat_1 = sat_1;
}
public String getSat_2() {
return this.Sat_2;
}
public void setSat_2(String sat_2) {
this.Sat_2 = sat_2;
}
public int getIsi_2() {
return this.Isi_2;
}
public void setIsi_2(int isi_2) {
this.Isi_2 = isi_2;
}
public double getStock_Akhir() {
return this.Stock_Akhir;
}
public void setStock_Akhir(double stock_Akhir) {
this.Stock_Akhir = stock_Akhir;
}
public String toString() {
return this.NmBrg;
}
}
my recyclerview data holder
ModelDataBarang modelBarangResto= listModel.get(position);
holder.tvKdBrg.setText(modelBarangResto.getKdBrg());
holder.tvNmBarang.setText(modelBarangResto.getNmBrg());
holder.tvHrgBrg.setText(String.valueOf(modelBarangResto.getHrg()));
all answers i will appreciate
Your model class values are not defined as per your response. Try to check and modify respective return type. You are getting this error because you have defined Isi_2 as int in your model class but in response you are getting empty string.
Replace this
private int Isi_2;
With this
private String Isi_2;

How can I make connection between retrofit and RxJava in different classes?

I have some classes as presenter and in these classes I use retrofit for some methods. But some methods are duplicated. So I want to use a class for all retrofit and connect to server methods and call them when I want.
But when I created that class it has NullpointerException Error
I will be very thankful if you help me
this is presenter codes:
public class DefinitionPresenter implements DefinitionContract.Presenter {
private KalaBeanDataSource kalaBeanDataSource;
private DefinitionContract.View view;
private CompositeDisposable compositeDisposable = new CompositeDisposable();
private DatabaseMethods databaseMethods;
private ActivityKindList activityKindList;
public DefinitionPresenter(KalaBeanDataSource kalaBeanDataSource){
this.kalaBeanDataSource = kalaBeanDataSource;
databaseMethods = new DatabaseMethods(kalaBeanDataSource,compositeDisposable);
activityKindList = new ActivityKindList();
}
#Override
public void attachView(DefinitionContract.View view) {
this.view = view;
}
#Override
public void detachView() {
view = null;
if(compositeDisposable != null && compositeDisposable.size() > 0){
compositeDisposable.clear();
}
}
#Override
public void activityKind() {
activityKindList = databaseMethods.getActivityKind();
if(activityKindList.getItems().size() > 0){
view.getActivityKind(activityKindList);
}else{
view.showMessage(databaseMethods.message);
}
}
}
And this is a class that I created for get data from server with retrofit and RxJava
public class DatabaseMethods {
private KalaBeanDataSource kalaBeanDataSource;
private CompositeDisposable compositeDisposable;
private ActivityKindList activityKindListResult;
public String message = null;
public DatabaseMethods(KalaBeanDataSource kalaBeanDataSource,CompositeDisposable compositeDisposable){
this.kalaBeanDataSource = kalaBeanDataSource;
this.compositeDisposable = compositeDisposable;
activityKindListResult = new ActivityKindList();
}
public ActivityKindList getActivityKind(){
kalaBeanDataSource.getActivityKind().subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new SingleObserver<ActivityKindList>() {
#Override
public void onSubscribe(Disposable d) {
compositeDisposable.add(d);
}
#Override
public void onSuccess(ActivityKindList activityKindList) {
activityKindListResult = activityKindList;
}
#Override
public void onError(Throwable e) {
message = e.toString();
}
});
if(message == null && activityKindListResult.getItems().size() > 0){
return activityKindListResult;
}else{
return null;
}
}
this method always returns null:
public ActivityKindList getActivityKind(){
kalaBeanDataSource.getActivityKind().subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new SingleObserver<ActivityKindList>() {
#Override
public void onSubscribe(Disposable d) {
compositeDisposable.add(d);
}
#Override
public void onSuccess(ActivityKindList activityKindList) {
activityKindListResult = activityKindList;
}
#Override
public void onError(Throwable e) {
message = e.toString();
}
});
if(message == null && activityKindListResult.getItems().size() > 0){
return activityKindListResult;
}else{
return null;
}
}
1) make this method void
2) create an interface and call it in onSuccess() and onError()
3) implement interface in your presenter

RxJava2 form validation

I have a form with 4 possible options that need to be checked (could be less as well depending on circumstances). There are 2 editexts, one for email and one for a reference field when creating an order.
The email and reference fields may or may not be left empty based on conditions (which are available when the form is created). Additionally we may need to show an alert dialog to tell the user that it may not be possible to show the reference value (to the recipient of the order) and they may also need to agree to a terms and condition alert dialog.
Currently the onConfirm checks is something like this,
void onCreateOrderConfirmed(#Nullable final String receiverEmail,
#Nullable final String reference,
#Nullable final Boolean noRefAgreed,
#Nullable final Boolean termsAndConditionsAgreed) {
if (!reviewCompletionState.emailRequirementSatisfied()) {
if (!isValidEmail(receiverEmail)) {
view.showEmailError();
return;
}
reviewCompletionState = reviewCompletionState.newBuilder()
.receiverEmail(receiverEmail)
.emailRequirementSatisfied(true)
.build();
}
if (!reviewCompletionState.referenceRequirementSatisfied()) {
if (isEmpty(reference)) {
view.showReferenceError();
return;
}
reviewCompletionState = reviewCompletionState.newBuilder()
.reference(reference)
.referenceRequirementSatisfied(true)
.build();
}
if (!reviewCompletionState.noRefAgreed()) {
if (noRefAgreed == null || !noRefAgreed) {
view.showNoReferenceAlert();
return;
}
reviewCompletionState = reviewCompletionState.newBuilder()
.noRefAgreed(true)
.build();
}
if (!reviewCompletionState.termsAndConditionsAgreed()) {
if (termsAndConditionsAgreed == null || !termsAndConditionsAgreed) {
view.showTermsDisclaimerAlert();
return;
}
reviewCompletionState = reviewCompletionState.newBuilder()
.termsAndConditionsAgreed(true)
.build();
}
createOrder();
}
I would love to know if there is a way to make this validation simpler with RxJava2? (but don't currently know enough to be able to do this)
TIA
This can be a simple. There will be a lot of code, I'll show the result first.
private ReviewValidator reviewValidator = new ReviewValidator();
void onCreateOrderConfirmed(#Nullable final String receiverEmail,
#Nullable final String reference,
#Nullable final Boolean noRefAgreed,
#Nullable final Boolean termsAndConditionsAgreed) {
ReviewState reviewState = new ReviewState(receiverEmail,
reference,
noRefAgreed,
termsAndConditionsAgreed);//another model for simplicity
reviewValidator.validate(reviewState)
.flatMap(reviewState -> /* create order */)
.subscribe(this::onOrderCreated, this::onOrderCreatingError);
}
void onOrderCreated(Object order) {//or what you need here
//handle positive result
}
void onOrderCreatingError(Throwable throwable) {
if (throwable instanceof ValidateException) {
List<ValidateError> errors = ((ValidateException) throwable).getValidateErrors();
for (ValidateError error: errors) {
switch (error.getField()) {
case EMAIL: {
view.showEmailError();
return;//or break if you want show all errors
}
case REFERENCE: {
view.showReferenceError();
return;
}
//handle another errors....
}
}
//handle another error cases...
}
First, create model for reviewState:
public class ReviewState {
private String receiverEmail;
private String reference;
private Boolean noRefAgreed;
private Boolean termsAndConditionsAgree;
public ReviewState(String receiverEmail,
String reference,
Boolean noRefAgreed,
Boolean termsAndConditionsAgree) {
this.receiverEmail = receiverEmail;
this.reference = reference;
this.noRefAgreed = noRefAgreed;
this.termsAndConditionsAgree = termsAndConditionsAgree;
}
public String getReceiverEmail() {
return receiverEmail;
}
public String getReference() {
return reference;
}
public Boolean getNoRefAgreed() {
return noRefAgreed;
}
public Boolean getTermsAndConditionsAgree() {
return termsAndConditionsAgree;
}
}
Then create you own validator. It is not necessary to create a whole model, you can create validator for every field and and link them with flatMap(), your choice.
public class ReviewValidator extends Validator<ReviewState> {
#Override
protected List<ValidateFunction> getValidateFunctions(ReviewState reviewState) {
List<ValidateFunction> validateFunctions = new LinkedList<>();
validateFunctions.add(() -> validateEmail(reviewState.getReceiverEmail()));
validateFunctions.add(() -> validateReference(reviewState.getReference()));
//another validation methods
return validateFunctions;
}
private ValidateError validateEmail(String email) {
if (TextUtils.isEmpty(email)) {
return new ValidateError(Field.EMAIL);//Field.EMAIL - just enum
}
return null;
}
private ValidateError validateReference(String reference) {
if (TextUtils.isEmpty(reference)) {
return new ValidateError(Field.REFERENCE);
}
return null;
}
//....
//another validation methods
}
Abstract class for validator:
public abstract class Validator<Model> {
public Single<Model> validate(Model model) {
return Single.just(model)
.map(this::validateModel)
.flatMap(this::processResult);
}
private Single<Model> processResult(ValidateResultModel<Model> validateResultModel) {
return Single.create(subscriber -> {
List<ValidateError> validateErrors = validateResultModel.getValidateErrors();
if (validateErrors.isEmpty()) {
subscriber.onSuccess(validateResultModel.getModel());
} else {
subscriber.onError(new ValidateException(validateErrors));
}
});
}
private ValidateResultModel<Model> validateModel(Model model) {
List<ValidateError> errors = new LinkedList<>();
for (ValidateFunction validateFunctions : getValidateFunctions(model)) {
ValidateError error = validateFunctions.validate();
if (error != null) {
errors.add(error);
}
}
return new ValidateResultModel<>(model, errors);
}
protected abstract List<ValidateFunction> getValidateFunctions(Model model);
protected interface ValidateFunction {
#Nullable
ValidateError validate();
}
}
Helper classes for validator...
public class ValidateError {
private Field field;
public ValidateError(Field field) {
this.field = field;
}
public Field getField() {
return field;
}
}
class ValidateResultModel<T> {
private T model;
private List<ValidateError> validateErrors;
ValidateResultModel(T model, List<ValidateError> validateErrors) {
this.model = model;
this.validateErrors = validateErrors;
}
T getModel() {
return model;
}
List<ValidateError> getValidateErrors() {
return validateErrors;
}
}
public class ValidateException extends RuntimeException {
private List<ValidateError> validateErrors;
ValidateException(List<ValidateError> validateErrors) {
this.validateErrors = validateErrors;
}
public List<ValidateError> getValidateErrors() {
return validateErrors;
}
}
Initially, I took the idea from here: https://github.com/matzuk/TestableCodeMobius/tree/master/app/src/main/java/com/matsyuk/testablecodemobius/business/transfer/validation
i think you should the RxJava CombineLatest, so you need all of the form input are producing an observable, then you just combine it and adjust the view
as a reference you can check:
https://medium.com/#etiennelawlor/rxjava-on-the-sign-in-screen-9ecb66b88572
Using RxJava for email login validation, an observable is emitting twice
========
example:
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.Toast;
import com.jakewharton.rxbinding2.view.RxView;
import com.jakewharton.rxbinding2.widget.RxCompoundButton;
import com.jakewharton.rxbinding2.widget.RxTextView;
import io.reactivex.Observable;
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
EditText receiverText = findViewById(R.id.input_receiver);
EditText referenceText = findViewById(R.id.input_reference);
CheckBox checkRef = findViewById(R.id.check_ref);
CheckBox checkTerms = findViewById(R.id.check_terms);
Button buttonLogin = findViewById(R.id.button_login);
Observable<CharSequence> receiverObservable = RxTextView.textChanges(receiverText).skip(1); // can add more logic
Observable<CharSequence> referenceObservable = RxTextView.textChanges(referenceText).skip(1); // can add more logic
Observable<Boolean> refCheckObservable = RxCompoundButton.checkedChanges(checkRef); // can add more logic
Observable<Boolean> termsCheckObservable = RxCompoundButton.checkedChanges(checkTerms); // can add more logic
Observable<String> combineObservable = Observable.combineLatest(
receiverObservable,
referenceObservable,
refCheckObservable,
termsCheckObservable, (receiverCharSequence, referenceCharSequence, refBoolean, termsBoolean) -> {
// add logic here for now it is only combine the input
return receiverCharSequence + " " + referenceCharSequence + " " + refBoolean + " " + termsBoolean ;}
);
RxView.clicks(buttonLogin).flatMap(o -> { return combineObservable;}).distinctUntilChanged().subscribe(string -> {
Toast.makeText(this, string, Toast.LENGTH_LONG).show();
});
}
}

Categories

Resources