I want to update key values when it removed, so I wrote codes below. These codes are in the Checkbox listener.
What I did first :
if(isChecked) {
Long size = dataSnapshot.child("Bookmark").getChildrenCount();
ref_h.child(userUid).child("Bookmark").child(Long.toString(size + 1)).setValue(diningUid);
} else {
for (int i = 1; i <= dataSnapshot.child("Bookmark").getChildrenCount(); i++) {
if (dataSnapshot.child("Bookmark").child(Integer.toString(i)).getValue().toString().equals(diningUid)) {
dataSnapshot.child("Bookmark").child(Integer.toString(i)).getRef().removeValue();
isRemoved = true;
}
if(isRemoved) {
if(i != dataSnapshot.child("Bookmark").getChildrenCount()){
String newDiningUid;
newDiningUid = dataSnapshot.child("Bookmark").child(Integer.toString(i + 1)).getValue().toString();
Log.d("newUID", newDiningUid);
ref_h.child(userUid).child("Bookmark").child(Integer.toString(i)).setValue(newDiningUid);
} else {
dataSnapshot.child("Bookmark").child(Integer.toString(i)).getRef().removeValue();
}
}
}
}
But when the Checkbox status changes rapidly, key values are messed up.
like this
data structure 2
Then I fixed the code with try-catch phrase.
if(isChecked) {//if not checked before listener runs, add to bookmark
Long size = dataSnapshot.child("Bookmark").getChildrenCount();
ref_h.child(userUid).child("Bookmark").child(Long.toString(size + 1)).setValue(diningUid);
} else {//if checked before listener runs, remove from bookmark
for (int i = 1; i <= dataSnapshot.child("Bookmark").getChildrenCount(); i++) {
try {
if (dataSnapshot.child("Bookmark").child(Integer.toString(i)).getValue().toString().equals(diningUid)) {
dataSnapshot.child("Bookmark").child(Integer.toString(i)).getRef().removeValue();
isRemoved = true;
}
} catch (NullPointerException e) {
if (dataSnapshot.child("Bookmark").child(Integer.toString(i + 1)).getValue().toString().equals(diningUid)) {
dataSnapshot.child("Bookmark").child(Integer.toString(i + 1)).getRef().removeValue();
isRemoved = true;
}
}
if(isRemoved) {
//update afterward value's index
if(i != dataSnapshot.child("Bookmark").getChildrenCount()){
String newDiningUid;
newDiningUid = dataSnapshot.child("Bookmark").child(Integer.toString(i + 1)).getValue().toString();
ref_h.child(userUid).child("Bookmark").child(Integer.toString(i)).setValue(newDiningUid);
} else {//remove last value
try {
dataSnapshot.child("Bookmark").child(Integer.toString(i)).getRef().removeValue();
} catch (NullPointerException e) {
dataSnapshot.child("Bookmark").child(Integer.toString(i + 1)).getRef().removeValue();
}
}
}
}
}
But I don't think I solved this problem.
How can I update key values properly?
or do I need to add a delay to Checkbox?
or change the data structure?
The best solution is to not use sequential numeric keys, but rely on Firebase's push IDs. For reasons on why this is a better approach and how they work, see these classic Firebase blog posts:
Best Practices: Arrays in Firebase
The 2^120 Ways to Ensure Unique Identifiers
If you insist on using array-like keys, you will have to use a transaction on the entire bookmark node to determine the next index. This is the only way to prevent the race condition that you now encounter when the array contents frequently change.
Related
Actually i'm developing an inventory app where i scan some EAN codes then i insert the quantity of an item and then i add it to an ArrayList in recyclerView.
For now i had no problem as i've made the inventory part where the items had to have different lines for each in recyclerView but now i have to make the order part and here if an item exist yet in ArrayList i have to sum it's quantity and put it to top of recyclerView.
I was trying to make something like a for loop when i'm going to add a new item and check if it's exist in ArrayList, if it's exist i was going to sum that item quantity with old one but the problem was that sometimes the app was going to crash and that the item wasn't going on top of recyclerView.
Do you have any suggestion on how can i do it?
for (ItemModel item : itemModel) {
if (item.getCodiceArticolo()
.equals(code.getText()
.toString())) {
item.setQta(String.valueOf(
Integer.parseInt(item.getQta()) + 1));
}
}
I was trying to make something like that.
Try this code:
ItemModel matchedItem = null;
int matchedItemIndex = -1;
for (ItemModel item : itemModel) {
if (item.getCodiceArticolo()
.equals(code.getText()
.toString())) {
item.setQta(String.valueOf(
Integer.parseInt(item.getQta()) + 1));
matchedItem = item;
matchedItemIndex = itemModel.indexOf(item);
break;
}
}
if (matchedItemIndex > -1) {
itemModel.remove(matchedItem);
itemModel.add(
0,
matchedItem);
notifyItemMoved(index,
0);
}
You do not adderror log to your list, so I guess your program crashes because sometimes there is a value that has no quantity (there is no valid number) and therefore can not parse the number, so in this case you just write that there is one item in list that has not been there yet.
for (ItemModel item : itemModel) {
if (item.getCodiceArticolo()
.equals(code.getText()
.toString())) {
try {
item.setQta(String.valueOf(
Integer.parseInt(item.getQta()) + 1));
}
catch (Exception ex) {
item.setQta(String.valueOf(1));
}
}
}
If this does not help, please attach error log.
Since the app is crashing, your ArrayList might not have been initialized as suggested in the comments.
For checking if the item exists you can use
if (arraylist_of_items != null && arraylist_of_items.contains(item)) {
// do your stuff here
}
Three days a go i was getting the "ConcurrentModificationException" but now i'm trying another approach inspired by other answers or better the following one:
boolean nuovo = true;
for (ItemModel itemModels : itemModel) {
if (itemModels.getCodiceArticolo()
.equals(code.getText()
.toString())) {
itemModels.setQta(String.valueOf(
Integer.parseInt(itemModels.getQta()) + 1));
nuovo = false;
break;
}
}
if (nuovo) {
itemModel.add(new ItemModel(
code.getText()
.toString(),
"1"));
}
And is not crashing anymore and seems to work fine.
Thank's all for suggestions.
UPDATE
THANKS TO kartik malik ANSWER i was able to even "update" my items by adding the last one added on top, as i'm using reverse recyclerView i've done it by this wasy instead of putting the item to position 0
ItemModel matchedItem = null;
int matchedItemIndex = -1;
boolean nuovo = true;
for (ItemModel itemModels : itemModel) {
if (itemModels.getCodiceArticolo()
.equals(code.getText()
.toString())) {
itemModels.setQta(String.valueOf(
Integer.parseInt(itemModels.getQta()) +
Integer.parseInt(qta.getText()
.toString())));
MediaPlayer mpFound = MediaPlayer.create(
OrdiniActivity.this,
R.raw.errorsound);
mpFound.start();
matchedItem = itemModels;
matchedItemIndex = itemModel.indexOf(itemModels);
nuovo = false;
break;
}
}
if (matchedItemIndex > -1) {
itemModel.remove(matchedItem);
itemModel.add(matchedItem);
}
if (nuovo) {
itemModel.add(new ItemModel(
code.getText()
.toString(),
qta.getText()
.toString()));
}
With the boolean i'm checking if the item exist or not and if it doesn't exist i add the item as a new one.
I have to implement the multiple search query, how to achieve it , I know the basic idea of filtering the text with the search view but not getting the idea how to search with multiple string ,I am attaching the snapshot show it will make you feel better to get an idea.
I am loading the data from the webserver.
TruckInfo columns are:
Name of the truck
Total capacity (is the capacity of the truck)
Status Free/Busy (is the status of the truck which is currently all truck is free)
Free location (is the where truck is going to free).
Now as in snapshot second i have to filter this data , I had searched in the capacity column --> 10 tonnes to 45 tonnes, status is--> free , free location is -->CV , from 7wed2016 to 20 Fri 2016 and then i hit search button .
Expected output should not show any result because:
10 tonnes to 45 tonnes there is 2 truck ..which is right. as data coming from server
status of both the truck is free, which is right
Free location is CV that I searched, but as you can see both truck have free location mumbais, chandigarh, so this condition is false so overall search should show no data
My Try:
filter_search.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Log.e("filter_search","filter_search");
Localytics.tagEvent("Trucks Search Screen");
if(frmcap.getText().toString().length()==0){
frmcap_val=0;
cap_bool=1;
}
else
{
frmcap_val=Integer.parseInt(frmcap.getText().toString());
cap_bool=0;
}
if(tocap.getText().toString().length()==0) {
tocap_val=0;
cap_bool = 1;
}
else {
tocap_val=Integer.parseInt(tocap.getText().toString());
cap_bool=0;
}
if(from_loc_text.getText().length()==0)
loc_bool=1;
else
loc_bool=0;
if(frm_date_value.length()==0 || to_date_value.length()==0)
date_bool=1;
else
date_bool=0;
if(free.isChecked())
status_value="true";
if(busy.isChecked())
status_value="false";
if(any.isChecked())
status_value="any";
if(!any.isChecked()&&!free.isChecked()&&!busy.isChecked()){
Log.e("##inside","inside");
status_value="-default value";
}
if(!any.isChecked()&&!free.isChecked()&&!busy.isChecked())
status_bool=1;
if(search.getText().length()==0)
loc_search_info=1;
else
loc_search_info=0;
try {
if(status_value!=null && status_value.length()>0 && !status_value.equalsIgnoreCase("any")){
truckadapter.advanceSearchFilter(status_value,"checkBox");
list_mytrucks.setVisibility(View.VISIBLE);
}else if(status_value!=null && status_value.equalsIgnoreCase("any")){
list_mytrucks.setVisibility(View.VISIBLE);
}else if(frmcap.getText().toString()!=null && frmcap.getText().toString().length()>0){
truckadapter.advanceSearchFilter(frmcap_val+"","capacity");
list_mytrucks.setVisibility(View.VISIBLE);
}else if(tocap.getText().toString()!=null && tocap.getText().toString().length()>0){
truckadapter.advanceSearchFilter(tocap_val+"","capacity");
list_mytrucks.setVisibility(View.VISIBLE);
}else if(current_location.getText().length()>=0){
truckadapter.advanceSearchFilter(current_location.getText().toString(),"freeLocation");
list_mytrucks.setVisibility(View.VISIBLE);
}else if(fromdt.getText().length()>=0){
truckadapter.advanceSearchFilter(current_location.getText().toString(),"dateStamp");
list_mytrucks.setVisibility(View.VISIBLE);
}else if(todt.getText().length()>=0){
truckadapter.advanceSearchFilter(current_location.getText().toString(),"dateStamp");
list_mytrucks.setVisibility(View.VISIBLE);
}
view_advance_search.setVisibility(View.GONE);
} catch (JSONException e) {
e.printStackTrace();
}
}
});
Here is searchFiletring in getViewMethod:
public void advanceSearchFilter(String constraint,String tag) throws JSONException {
items.clear();
if(constraint.isEmpty()){
items.addAll(advanceSearchArrayList);
} else{
constraint = constraint.toUpperCase();
for(int i=0;i<advanceSearchArrayList.size();i++){
JSONObject jsonData = new JSONObject(String.valueOf(advanceSearchArrayList.get(i).getVehicle()));
if(tag.equalsIgnoreCase("capacity")){
int truckCapacity=Integer.parseInt(constraint);
if(Integer.parseInt(jsonData.getJSONObject("type").getString("capacity").toUpperCase())>=truckCapacity){
items.add(advanceSearchArrayList.get(i));
}
}
if(tag.equalsIgnoreCase("checkBox")){
if(advanceSearchArrayList.get(i).getFree().toUpperCase().contains(constraint)){
items.add(advanceSearchArrayList.get(i));
}
}
if(tag.equalsIgnoreCase("freeLocation")){
if(advanceSearchArrayList.get(i).getFree().toUpperCase().equalsIgnoreCase("true")){
Log.e("getFree_loc",""+advanceSearchArrayList.get(i).getFree_loc());
if(advanceSearchArrayList.get(i).getFree_loc().toUpperCase().contains(constraint)){
items.add(advanceSearchArrayList.get(i));
}
}
}
if(tag.equalsIgnoreCase("dateStamp")){
SimpleDateFormat formatter = new SimpleDateFormat("dd-MMM-yyyy");
Date date = null;
try {
date = formatter.parse(constraint);
} catch (ParseException e) {
e.printStackTrace();
}
try {
if(formatter.parse(advanceSearchArrayList.get(i).getFree().toUpperCase()).before(date) ){
items.add(advanceSearchArrayList.get(i));
}
} catch (ParseException e) {
e.printStackTrace();
}
}
}
}
notifyDataSetChanged();
}
You need to still explicitly compare each filter to property of each object to see if it matches or not.
Just an idea for flow:
Make a class for filter input. when user clicks search button, assign all filter values to that class.
Make a method inside model class, that returns true if any of the filter value matches. That takes filter class object as argument.
Now when user clicks search button, iterate over each object in array. Call this method. If it returns true, add this object in new filter array.
Use that filter array to show search results.
Example Code
///////// Filter class
class FilterTrucks {
String location;
int capacityStart;
int capacityEnd;
Arraylist<String> availability;
}
////// You model class
class Mytrucks {
String name;
String location;
int capacity;
String availability;
boolean matchFilter(FilterTrucks filter) {
boolean locationMatch = filterMatchesLocation(filter);
if(locationMatch)
return true;
boolean matchCapacity = filterMatchesCapacity(filter);
if(matchCapacity)
return true;
return false;
}
boolean filterMatchesLocation(FilterTrucks filter) {
return location.contains(filter.location);
}
boolean filterMatchesCapacity(FilterTrucks filter) {
return (capacity >= filter.capacityStart || capacity <= filter.capacityEnd)
}
////////// Your activity
Arraylist<Mytrucks> filterArray = new Arraylist<>();
filter_search.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
//create filter object from user selected fields
FilterTrucks filter = new FilterTrucks();
filter.location = txtLocation.getText().toString(); //for example
for(Mytrucks truck : arraylist) {
if(truck.matchFilter(filter))
filterArray.add(truck);
}
}
});
//use filter array to populate recycler view
Hope this helps!
This question already has answers here:
How to remove duplicates from a list?
(15 answers)
Closed 8 years ago.
I want to remove duplicates from ArrayList of type Alerts where Alerts is a class.
Class Alerts -
public class Alerts implements Parcelable {
String date = null;
String alertType = null;
String discription = null;
public Alerts() {
}
public Alerts(String date, String alertType, String discription) {
super();
this.date = date;
this.alertType = alertType;
this.discription = discription;
}
}
Here is how I added the elements -
ArrayList<Alerts> alert = new ArrayList<Alerts>();
Alerts obAlerts = new Alerts();
obAlerts = new Alerts();
obAlerts.date = Date1.toString();
obAlerts.alertType = "Alert Type 1";
obAlerts.discription = "Some Text";
alert.add(obAlerts);
obAlerts = new Alerts();
obAlerts.date = Date2.toString();
obAlerts.alertType = "Alert Type 1";
obAlerts.discription = "Some Text";
alert.add(obAlerts);
What I want to remove from them-
I want all alerts which have unique obAlerts.date and obAlerts.alertType. In other words, remove duplicate obAlerts.date and obAlerts.alertType alerts.
I tried this -
Alerts temp1, temp2;
String macTemp1, macTemp2, macDate1, macDate2;
for(int i=0;i<alert.size();i++)
{
temp1 = alert.get(i);
macTemp1=temp1.alertType.trim();
macDate1 = temp1.date.trim();
for(int j=i+1;j<alert.size();j++)
{
temp2 = alert.get(j);
macTemp2=temp2.alertType.trim();
macDate2 = temp2.date.trim();
if (macTemp2.equals(macTemp1) && macDate1.equals(macDate2))
{
alert.remove(temp2);
}
}
}
I also tried-
HashSet<Alerts> hs = new HashSet<Alerts>();
hs.addAll(obAlerts);
obAlerts.clear();
obAlerts.addAll(hs);
You need to specify yourself how the class decides equality by overriding a pair of methods:
public class Alert {
String date;
String alertType;
#Override
public boolean equals(Object o) {
if (this == 0) {
return true;
}
if ((o == null) || (!(o instanceof Alert)))
return false;
}
Alert alert = (Alert) o;
return this.date.equals(alert.date)
&& this.alertType.equals(alert.alertType);
}
#Override
public int hashCode() {
int dateHash;
int typeHash;
if (date == null) {
dateHash = super.hashCode();
} else {
dateHash = this.date.hashCode();
}
if (alertType == null) {
typeHash = super.hashCode();
} else {
typeHash = this.alertType.hashCode();
}
return dateHash + typeHash;
}
}
You can then loop through your ArrayList and add elements if they aren't already there as Collections.contains() makes use of these methods.
public List<Alert> getUniqueList(List<Alert> alertList) {
List<Alert> uniqueAlerts = new ArrayList<Alert>();
for (Alert alert : alertList) {
if (!uniqueAlerts.contains(alert)) {
uniqueAlerts.add(alert);
}
}
return uniqueAlerts;
}
However, after saying all that, you may want to revisit your design to use a Set or one of its family that doesn't allow duplicate elements. Depends on your project. Here's a comparison of Collections types
You could use a Set<>. By nature, Sets do no include duplicates. You just need to make sure that you have a proper hashCode() and equals() methods.
In your Alerts class, override the hashCode and equals methods to be dependent on the values of the fields you want to be primary keys. Afterwards, you can use a HashSet to store already seen instances while iterating over the ArrayList. When you find an instance which is not in the HashSet, add it to the HashSet, else remove it from the ArrayList. To make your life easier, you could switch to a HashSet altogether and be done with duplicates per se.
Beware that for overriding hashCode and equals, some constraints apply.
This thread has some helpful pointers on how to write good hashCode functions. An important lesson is that simply adding together all dependent fields' hashcodes is not sufficient because then swapping values between fields will lead to identical hashCodes which might not be desirable (compare swapping first name and last name). Instead, some sort of shifting-operation is usually done before adding the next atomic hash, eg. multiplying with a prime.
First store your datas in array then split at as one by one string,, till the length of that data execute arry and compare with acyual data by if condition and retun it,,
HashSet<String> hs = new HashSet<String>();
for(int i=0;i<alert.size();i++)
{
hs.add(alert.get(i).date + ","+ alert.get(i).alertType;
}
alert.clear();
String alertAll[] = null;
for (String s : hs) {
alertAll = s.split(",");
obAlerts = new Alerts();
obAlerts.date = alertAll[0];
obAlerts.alertType = alertAll[1];
alert.add(obAlerts);
}
I have two lists of Default and Chrome browsers history.
I want to merge these two lists into one list.
I need to update item if I find it duplicate (is common between two lists).
So, my "BrowserRecord" class is like this:
public class BrowserRecord {
private long id;
private int bookmark;
private long created;
private long date;
private String title;
private String url;
private long visits;
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
BrowserRecord record = (BrowserRecord) o;
return url.equals(record.url);
}
#Override
public int hashCode() {
return url.hashCode();
}
// other getter setter methods
...
}
and finally, I have a method that gets browsers histories and does merging:
public List<BrowserRecord> getHistory() {
List<BrowserRecord> browserList = new ArrayList<BrowserRecord>();
// get history of default and chrome browsers
List<BrowserRecord> defaultList = getDefaultBrowserHistory();
List<BrowserRecord> chromeList = getChromeBrowserHistory();
Log.e(TAG, "=> size of Default browser:" + defaultList.size());
Log.e(TAG, "=> size of Chrome browser:" + chromeList.size());
// compare list A with B, update A item if equal item found in B and push it to tempList
for(int i=0; i<chromeList.size(); i++) {
BrowserRecord chromeBrowser = chromeList.get(i);
for(int j=0; j<defaultList.size(); j++) {
BrowserRecord defaultBrowser = defaultList.get(j);
if(chromeBrowser.equals(defaultBrowser)) {
if(chromeBrowser.getBookmark() != defaultBrowser.getBookmark())
chromeBrowser.setBookmark(1);
chromeBrowser.setVisits(chromeBrowser.getVisits() + defaultBrowser.getVisits());
}
}
browserList.add(chromeBrowser);
}
// compare list B with A, jump if equal item found in A, push to tempList if item not found
for(int i=0; i<defaultList.size(); i++) {
BrowserRecord defaultBrowser = defaultList.get(i);
boolean found = false;
for(int j=0; j<chromeList.size(); j++) {
BrowserRecord chromeBrowser = chromeList.get(j);
if(defaultBrowser.equals(chromeBrowser)) {
found = true;
break;
}
}
if(!found)
browserList.add(defaultBrowser);
}
Log.e(TAG, "=> size of final browser:" + browserList.size());
return browserList;
}
I have tested this method and is working fine. Since my history records on mobile device after 3 years didn't exceed more than 200 records on one list and 150 for others, I assume something similar is happening for other users. But I'm sure is not optimum way.
What do you recommend?
any suggestion would be appreciated. Thanks.
Not sure I understand correctly, but it seems like what you're trying to do is, given both lists, create a final list which will contain all of the elements from both lists, removing any duplicates.
If this is the case, then take a look at Java's TreeSet class. If you iterate over all of the elements from both your lists and insert them into a TreeSet, you will basically get the result you're looking for. You can then use an Iterator to create an ArrayList containing all of the non-duplicate items from both your lists. As a side-effect of using a TreeSet, they will ordered (you can also use either a HashSet if you don't care about the order or a LinkedHashSet if you want to preserve the order of insertion).
How do I replace a value from an array list dynamically when the user edits the array of values? I used arr_list.set(count,"replace value") inside button click.Action done by using the button click event. So I used count for index of arr_list. I have an issue as I click the button it replaces all the values in arr_list. I want to replace particular edit values done by user.
if (v == right) {
if (riskList.size() == 0) {
} else
{
try {
riskList.set(count2,key.getText().toString());
Log.i("dfDF", "" + count2);
key.setText(riskList.get(count2).toString());
toGetIndex = key.toString();
int indexPlus = riskList.indexOf(toGetIndex);
risk.setText(descList.get(count2).toString());
totalRiskin.setText(count2 + 1 + "/" + totalRisks);
} catch (IndexOutOfBoundsException ex) {
Toast.makeText(SalesEditActivity.this,
"There is no next element", Toast.LENGTH_SHORT)
.show();
}
count2 = count2 + 1;
}
}
I have used previous and next button to display array list values according to index.ie count. I also want edit array list values,it will be replace the current index value.
Try declaring your array list as static.