Android - Force Validation on a variable during coding process? - android

I am working on my own library for Android and I have two variables that need to be validated. The following variables are declared within one of my library classes.
Boolean Decimals = false;
Boolean Separator = true;
When developers use the library, if they set Decimals = true and Separator = true, I want to throw an error underlying the code lines displaying a message:
Decimals cannot be set as true when Separator is set as true`.
This is a form of validation I need in my library to avoid conflicts in certain functions.
How can I throw a library-level error after validating if these two variables are always set as opposites?
NOTE: Throwing it during runtime is not the desired behaviour. I would like to indicate it during the developer's coding process

Hopefully you are writing the library as an API rather than a set of loose functions.
The user might use it in this way:
LibraryObject lo = new LibraryObject(...);
lo.setDecimal(true);
lo.setSeparator(true);
Then in your setter, you will have some validation like:
setDecimal(boolean decimal) {
if(this.separator == false && decimal == true) this.decimal = true;
else {throw error; }
}
Same for the other case.

Suppose now you have a setter function to update this variable
public void setDecimals(boolean someValue)
{
this.Decimals = someValue;
}
And if you want to validate it you can do it inside the setter
public void setDecimals(boolean someValue) throws Exception
{
if(someConditions){
this.nickname = nick; // here this is the allowed case
}else{
throw new Exception("Decimals cannot be set as true when Separator is set as true");
}
}

Related

Comparing two object are indentical in kotlin

I have a two kotlin object which are very identical data without any change, but getting return false. which has to be return true if two object are identical, only if change then it should be return false.
Doing checking objects are:
private var emp1: Employee? = null
var emp2: Employee? = null
fun dataChanged(): Boolean {
return if (emp1 != null && emp2 != null) {
emp1 != emp2
} else {
false
}
}
I checked the data in log, which is not changing anyhing not even space.
Employee defiend as follows,
data class Employee(
//...
): Parcelable {
//...
}
No equals and hashcode.
here using for changing data change on edittext -> TextInputEditText, TextWatcher. Any suggestion, where, i'm doing wrong.
Thanks in advance.
When you define a data class compiler automatically derives the following members from all properties declared in the primary constructor:
equals()/hashCode() pair;
...
Therefore equals method execution depends on parameters of primary constructor.
If you use some other objects in primary constructor make sure they are also data classes or have overriden equals method.
I suggest to put logs before comparison of two objects and check whether they contain equal data.
EDIT:
I have a two kotlin object which are very identical data without any change, but getting return false.
Your function dataChanged() returns false for two identical objects because of condition emp1 != emp2. The name of the function says that it will return true if objects are not identical, false - if they are identical, i.e. data not changed. So the function dataChanged() works as expected.

Android: i'm already delete my data, but in room still exists some data

I have Boolean booleanCheckAvailabilityData to check availability data in my activity to create add/remove favorite. then i create
dataFavoriteMovieById = favoriteMovieViewModel.getAllFavoriteMovieById(idMovie);
to get data by id. so i make conditional statement to check avaiability data then put the result to boolean and i use the boolean later to add or remove the favorite.
if (dataFavoriteMovieById == null) {
booleanCheckAvailabilityData = false;
} else {
booleanCheckAvailabilityData = true;
}
In the first run, it work. my dataFavoriteMovieById is null
But, after i add or remove favorite. it always always contains data (RoomTrackingLiveData).
How can i solve this...
my code link : https://github.com/komangss/Submission-Menjadi-Android-Developer-Expert/blob/master/app/src/main/java/com/dicoding/submissionmade2_1/activity/DetailMovieActivity.java
I played with your app (thanks for providing a github link) and here are my results.
Latest app version
Your latest implementation doesn't produce an NPE anymore since you use getAllFavoriteMovieById in a more consistent way. You no longer initialize a LiveData instance in FavoriteMovieRepository by yourself but delegate it to Room to do it for you. So, you won't get an NPE since Room will always create a list to return results. If there're no items, it will return an empty list. So, you can safely remove a try/catch here:
try {
favoriteMovieViewModel.getAllFavoriteMovieById(idMovie).observe(this, new Observer<List<FavoriteMovie>>() {
#Override
public void onChanged(List<FavoriteMovie> favoriteMovies) {
booleanCheckAvailabilityData = favoriteMovies.size() != 0;
}
});
} catch (NullPointerException e) {
Log.d("ini bug nya", e.getMessage());
}
Original app version
In addition to what #Paul Ost said about how favoriteMovieViewModel should be used properly (by listening to it, not using it directly), I will explain why you actually had an NPE.
In that version, you were running into a NullPointerException because you returned the favoriteMovieById LiveData before it was actually initialized in your GetFavoriteMovieByIdAsyncTask.
So, here what was happening in detail. First, once your DetailMovieActivity had been created, favoriteMovieViewModel called getAllFavoriteMovieById() as below:
DetailMovieActivity.java
...
favoriteMovieViewModel = ViewModelProviders.of(this).get(FavoriteMovieViewModel.class);
dataFavoriteMovieById = favoriteMovieViewModel.getAllFavoriteMovieById(idMovie);
...
FavoriteMovieViewModel.java
FavoriteMovieViewModel instance, in turn, delegated the call to FavoriteMovieRepository instance as below:
public LiveData<List<FavoriteMovie>> getAllFavoriteMovieById(int idMovie) {
return repository.getFavoriteMovieById(idMovie);
}
FavoriteMovieRepository.java
Finally, getFavoriteMovieById started a GetFavoriteMovieByIdAsyncTask and returned favoriteMovieById:
public LiveData<List<FavoriteMovie>> getFavoriteMovieById(int id_movie) {
new GetFavoriteMovieByIdAsyncTask(favoriteMovieDao).execute(id_movie);
return favoriteMovieById;
}
But that's wrong, since your favoriteMovieById was set to null by default, and so on the first run, you were always getting it.
Your AsyncTask was eventually setting a non-null value, but it was too late:
...
private static class GetFavoriteMovieByIdAsyncTask extends AsyncTask<Integer, Void, Void> {
...
#Override
protected Void doInBackground(Integer... integers) {
FavoriteMovieRepository.favoriteMovieById = favoriteMovieDao.getFavoriteMovieById(integers[0]);
return null;
}
}
...
From what I can see in your code - getAllFavoriteMovieById works as expected. The thing is - you are using LiveData as a return type of getAllFavoriteMovieById thus it returns not the value itself but a LiveData wrapper. But if you will try to observe this LiveData object you will(presumably since I haven't seen relevant code) receive null instead of favourite value. The only correct place to assign value to your booleanCheckAvailabilityData inside this observer(depending on your DAO code of course).
favouriteMovieViewModel.getAllFavoriteMovieById().observe(this, Observer { data ->
if (data == null) {
booleanCheckAvailabilityData = false;
} else {
booleanCheckAvailabilityData = true;
}
})
Something like that(once again it depends on your DAO code and getAllFavoriteMovieById implementation)
Hope it helps.
In ROOM Try Deleting the old TABLE before inserting the new data. In that case the old data will be deleted as we are deleting the old data

manage null boolean with RxJava2 PublishSubject

I'm implementing the MVP design pattern. My presenter receives the new values from the view. I want to manage the state of a next button by automatically check if everything is valid when values are updated on the view.
In my form I have an optional part which is displayed only if the user select the correct option.
In this optional part I have a binary question. If the part is not displayed I need to set the value of the question to null on the Presenter side.
For example, the user select the option and the optional part is displayed. The user select the answer. Then the user change the option and the optional part is hidden. In that case I need to set the answer to the optional question to null, for the answer to not be already selected if the user display the optional part again.
To do so, I call a method on the Presenter with a null value instead of true/false.
Here is the code:
private final PublishSubject<Boolean> mObsOptionalAnswer = PublishSubject.create();
public MyPresenter(){
// Combine all the values together to enable/disable the next button
Observable.combineLatest(
// ... other fields
// I need this to return false if the optional part is
// displayed but nothing is selected
mObsOptionalAnswer.map(this::isValid),
(...) -> ...
).subscrible(enable ->{
mView.enableBtn(enable);
});
}
public void myFunction(Boolean isSomething){
// ... some code
mObsOptionalAnswer.onNext(isSomething);
}
private boolean isValid(Boolean value){
return value != null;
}
The problem is, since RxJava 2, null values are not allowed in the onNext() method.
So, how am I supposed to manage that?
If you want to be able to send a null value, you can use a wrapper. In this configuration, you send the wrapper, which isn't null even if the value itself is.
public class BooleanWrapper {
public final Boolean value;
public BooleanWrapper(Boolean value) {
this.value = value;
}
}
Your PublishSubject<Boolean> becomes a PublishSubject<BooleanWrapper> and you just have to create the wrapper and de-reference your Boolean when needed :
mObsOptionalAnswer.onNext(new BooleanWrapper(isSomething));
and
mObsOptionalAnswer.map(wrapper -> this.isValid(wrapper.value))
If you need to do that more than once in your code, you can create a generic wrapper (as described by this tutorial) :
public class Optional<M> {
private final M optional;
public Optional(#Nullable M optional) {
this.optional = optional;
}
public boolean isEmpty() {
return this.optional == null;
}
public M get() {
return optional;
}
}
you could use a constante Boolean object
public static final Boolean RESET_VALUE = new Boolean(false);
and you can emit this instead of emitting null. The receiver would have to check against this instance and behaving accordingly. Eg.
.subscrible(enable ->{
if (enable != RESET_VALUE) {
mView.enableBtn(enable);
}
});

What's Kotlin Backing Field For?

As a Java developer, the concept of a backing field is a bit foreign to me. Given:
class Sample {
var counter = 0 // the initializer value is written directly to the backing field
set(value) {
if (value >= 0) field = value
}
}
What's this backing field good for? Kotlin docs said:
Classes in Kotlin cannot have fields. However, sometimes it is necessary to have a backing field when using custom accessors.
Why? What's the difference with using the properties name itself inside the setter, eg.*
class Sample {
var counter = 0
set(value) {
if (value >= 0) this.counter = value // or just counter = value?
}
}
Because, say if you don't have field keyword, you won't be able to actually set/get the value in the get() or set(value). It enables you to access the backing field in the custom accessors.
This is the equivalent Java code of your sample:
class Sample {
private int counter = 0;
public void setCounter(int value) {
if (value >= 0) setCounter(value);
}
public int getCounter() {
return counter;
}
}
Apparently this is not good, as the setter is just an infinte recursion into itself, never changing anything. Remember in kotlin whenever you write foo.bar = value it will be translated into a setter call instead of a PUTFIELD.
EDIT: Java has fields while Kotlin has properties, which is a rather higher level concept than fields.
There are two types of properties: one with a backing field, one without.
A property with a backing field will store the value in the form of a field. That field makes storing value in memory possible. An example of such property is the first and second properties of Pair. That property will change the in-memory representation of Pair.
A property without a backing field will have to store their value in other ways than directly storing it in memory. It must be computed from other properties, or, the object itself. An example of such property is the indices extension property of List, which is not backed by a field, but a computed result based on size property. So it won't change the in-memory representation of List (which it can't do at all because Java is statically typed).
Initially, I too had a tough time understanding this concept. So let me explain it to you with the help of an example.
Consider this Kotlin class
class DummyClass {
var size = 0;
var isEmpty
get() = size == 0
set(value) {
size = size * 2
}
}
Now when we look at the code, we can see that it has 2 properties i.e - size (with default accessors) and isEmpty(with custom accessors). But it has only 1 field i.e. size. To understand that it has only 1 field, let us see the Java equivalent of this class.
Go to Tools -> Kotlin -> Show Kotlin ByteCode in Android Studio. Click on Decompile.
public final class DummyClass {
private int size;
public final int getSize() {
return this.size;
}
public final void setSize(int var1) {
this.size = var1;
}
public final boolean isEmpty() {
return this.size == 0;
}
public final void setEmpty(boolean value) {
this.size *= 2;
}
}
Clearly we can see that the java class has only getter and setter functions for isEmpty, and there is no field declared for it. Similarly in Kotlin, there is no backing field for property isEmpty, since the property doesn't depend on that field at all. Thus no backing field.
Now let us remove the custom getter and setter of isEmpty property.
class DummyClass {
var size = 0;
var isEmpty = false
}
And the Java equivalent of the above class is
public final class DummyClass {
private int size;
private boolean isEmpty;
public final int getSize() {
return this.size;
}
public final void setSize(int var1) {
this.size = var1;
}
public final boolean isEmpty() {
return this.isEmpty;
}
public final void setEmpty(boolean var1) {
this.isEmpty = var1;
}
}
Here we see both the fields size and isEmpty. isEmpty is a backing field because the getter and setter for isEmpty property depend upon it.
Backing fields are good for running validation or triggering events on state change. Think of the times you've added code to a Java setter/getter. Backing fields would be useful in similar scenarios. You would use backing fields when you needed to control or have visibility over setters/getters.
When assigning the field with the field name itself, you're actually invoking the setter (i.e. set(value)). In the example you have, this.counter = value would recurse into set(value) until we overflow our stack. Using field bypasses the setter (or getter) code.
My understanding is using field identifier as a reference to the property's value in get or set, when you want to change or use the property's value in get or set.
For example:
class A{
var a:Int=1
get(){return field * 2} // Similiar to Java: public int geta(){return this.a * 2}
set(value) {field = value + 1}
}
Then:
var t = A()
println(t.a) // OUTPUT: 2, equal to Java code: println(t.a * 2)
t.a = 2 // The real action is similar to Java code: t.a = t.a +1
println(t.a) // OUTPUT: 6, equal to Java code: println(t.a * 2)
The terminology backing field is filled with mystery. The keyword used is field. The get/set methods, follows immediately next to the member variable that is about to be get or set through this door protective methods mechanism. The field keyword just refers to the member variable that is to be set or get. At present Kotlin, you cannot refer to the member variable directly inside the get or set protective door methods because it will unfortunately result to infinite recursion because it will re-invoke the get or set and thus leds the runtime down into the deep abyss.
In C# though, you can directly reference the member variable inside the getter/setter methods. I am citing this comparison to present the idea that this field keyword is how the present Kotlin is implementing it but I do hope it will be removed in later versions and allow us to directly reference the member variable directly without resulting to infinite recursion.

Android validation is not a number from EditText

mail_xml is this:
EditText android:inputType="numberDecimal|numberSigned`
onTextChanged implemented on this and other edittexts and calls relative methods.
//and one method example:
if (editTextNumber.getText().toString().equals("") ||
editTextNumber.getText().toString().equals("-") ||
editTextNumber.getText().toString().equals(".")) {
//say its bad or reset interface so the user knows;
else {
//do stuff;
}
Should I create a class to do the validation and instantiate it, then use an if/else statement returning a boolean?
It's difficult because a - is valid as the user types, so is a .. But a . and - crashes. I'm thinking a class would be best?
I don't remember a function in java to do this, unless the api has been updated and I haven't seen it yet. I've created the classes i need and can instantiate them call their getter methods no problem. just stuck on the basic validation.
You can simply put the cast in a block try/catch...
This way if the text inserted is not a number, an exception is fired...
For exemple:
if(editTextNumber.getText()!=null && !editTextNumber.getText().toString().equals("")){
try{
// int value
Integer.parseInt(editTextNumber.getText().toString());
// double value
Double.parseDouble(editTextNumber.getText().toString());
}catch(Exception e){
//prints the exception that you got
//if number format exception then your input is not a number
e.printStackTrace();
}
}
Hope it helped...

Categories

Resources