ArrayList Remove Object - android

I'm working on an app in android studio. The part of the app I'm having issues with is where the user can favourite and remove their favourite item. I do this by adding and removing the item from a list.
The thing is the add functionality works which is:
public void addFavorite(Context context, NewSubject subject) {
List<NewSubject> favorites = getFavorites(context);
if (favorites == null)
favorites = new ArrayList<NewSubject>();
favorites.add(subject);
saveFavorites(context, favorites);
}
I am passing in an object of type "NewSubject" which is just a class of getters and setters for name and id.
The problem arises when I try to remove an item from this list. Code below:
public void removeFavorite(Context context, NewSubject subject) {
ArrayList<NewSubject> favorites = getFavorites(context);
if (favorites != null) {
favorites.remove(subject);
saveFavorites(context, favorites);
}
}
I've even tried something like:
for(int i = 0; i < favorites.size(); i++){
if(favorites.get(i).getSubject_name() == subject.getSubject_name())
favorites.remove(i);
}
Even though both subject names match, the if statement never triggers as true. By changing it to ID it does remove the item but I was wondering why it doesn't work the other way. MeetTitan suggested to use "equals" operator to compare Strings and this has fixed that issue. But I'm still wondering as to why removing the item by "subject" without the FOR loop and IF statement doesn't work.
I have cleared the app's data multiple times whilst trying to debug the source of the problem.
Thank you for your time and help, it is much appreciated.

This applies if you are re-creating NewSubject twice... If you are trying to remove the exact same instance of NewSubject that you got from the collection, then I guessed wrong and this isn't the answer you are looking for.
Is it possible you haven't defined equals and hashCode in your Favorites object? Without those remove will only work with the EXACT same object instance in the collection. If you haven't, try defining them and see if remove() works the way you expect.
Without those methods defined, collections will respond this way:
Obj x=new Obj("data")
Obj y=new Obj("data")
collection.put(x)
collection.remove(y)
assert( collection.size() == 1) // was not removed because .equals didn't exist--remove reverted to == instead which failed, x != y
collection.remove(x)
assert( collection.size() == 0) // NOW it worked because you used the same instance.
if you define .equals and hashCode to compare the strings inside obj, then this will work:
collection.put(x)
collection.remove(y)
assert( collection.size() == 0) // worked because x.equals(y)!

Try
String.equalsIgnoreCase(value1,value2)
This might do your work.

From your example, it's evident that name is a String object. In java, you have to use ".equals()" or comparing two strings.
You can do this:
if(favorites.get(i).getSubject_name().equals(subject.getSubject_name())){
...
}
Or, you can override the equals() method in your NewSubject class to make this work:
favorites.remove(subject);
You can use something like this as your equals() method in the NewSubject class (considering you are only matching two NewSubject objects based on their names):
#Override
public boolean equals(Object other){
if (other == null) return false;
if (other == this) return true;
NewSubject otherSubject = (NewSubject) other;
if(this.getSubject_name().equals(otherSubject.getSubject_name()))
return true;
else
return false;
}
Update:
You may want to override hashcode() as well. If your NewSubject class ever gets used in a hash-based collection such as HashMap, overriding only equals() method will not be sufficient. For reference, this is from Effective Java by Joshua Bloch:
You must override hashCode() in every class that overrides equals().
Failure to do so will result in a violation of the general contract
for Object.hashCode(), which will prevent your class from functioning
properly in conjunction with all hash-based collections, including
HashMap, HashSet, and Hashtable.

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

Parse.com - Android: boolean on if a User belongs to an Array

I have an array of Users in a class, under the column "likers"
I want to check whether or not the current user is contained in the likers array, in minimal time
This is my current (dysfunctional) code:
ArrayList<ParseUser> likers = (ArrayList<ParseUser>) rating.get("likers");
Boolean contained = likers.contains(ParseUser.getCurrentUser()) //always returns false
How can I change it to make it work? I feel it's a match on ObjectId. Maybe there is a function in the Parse SDK?
Thanks!
You can use next approach.
ParseObject rating = ParseObject.create(ParseObject.class);
ArrayList<ParseUser> likers = (ArrayList<ParseUser>) rating.get("likers");
Boolean contained = containsUser(likers, ParseUser.getCurrentUser());
Method
private boolean containsUser(List<ParseUser> list, ParseUser user) {
for (ParseUser parseUser : list) {
if (parseUser.hasSameId(user)) return true;
}
return false;
}
Little bit about your code. It works correct, return false. Because ArrayList implements the List Interface. If you look at the Javadoc for List at the contains method you will see that it uses the equals() method to evaluate if two objects are the same. Result of rating.get("likers") contains same ParseUsers as ParseUser.getCurrentUser, but they are different objects at memory. So you need find it by comparing ObjectId from Parse.com.

Android: Null safe equals before API v19

I have two objects Object1 and Object2, which may or may not be null.
I want to test null safe equality between them (true if both null, or both equal)
I have done my research and found Objects.equals(Object1,Object2), which fulfills its purpose.
But the problem is that it's only for API level 19+.
How do I make this compatible with lesser APIs?
There are several options.
You could override the
equals() method in the class you are comparing, and use obj1.equals(obj2)
You could use the hashCode() method of Object to determine if they are equivalent, by using obj1.hashCode() == obj2.hashCode()
Just using plain old == determines weather two variables contain the same instance of a class.
If these aren't null safe, you can easily write your own null checking with obj == null
This should be completely independent of the Android Api.
Have you tried Guava?
Guava has some pretty nice functionality that removes alot of the boilerplate.
Here is a link of their example.
Here is a simple comparison method. It seems odd that you have to roll your own, though.
/**
* Null safe comparison of two objects.
* #return true if the objects are identical.
*/
public static boolean objectEquals(Object o1, Object o2) {
if (o1 == null && o2 == null) return true;
if (o1 == null) return false;
return o1.equals(o2);
}

if ArrayList contains doesn't work

i'm curently developing app which has lots of ArraYlists and it needs to compare them with nonlist data. When i try this method fdata.contains(data2) it always returns false. ArayLists contains class named 'favdat' which looks like this:`
public class favdat {
public String product,term,note,link;
}
And Data2 is defined like this: favdat Data2=new favdat();
I have also tryed retain all method and it returns list in the size of 0.
I know that some data are equal.
So the question is how could i tell if fdata contains data2?
The default implementation to compare objects is to compare if they are the same object, so two objects with the exactly same attributes would still not be equals. What you need to do is override the hashCode and equals methods. As an example:
public int hashCode() {
return product.hashCode() * 31 + term.hashCode();
}
public boolean equals(Object o) {
if (o instanceof favdata) {
favdata other = (favdata) o;
return product.equals(other.product)
&& term.equals(other.term)
&& note.equals(other.note)
&& link.equals(other.link);
} else {
return false;
}
}
In java classnames are usually started with capitals, so it would be Favdat, and your code usually gets easier to read to keep the field declarations separate.
You need to define a method called equals(Object obj) inside favdat that will enable object comparison.
Here's a more detailed howto:
Comparing Objects in Java
Also related thread in SO, talk about how ArrayList.contains() work.

Categories

Resources