Observe livedata inside a for loop - java

I want to update a list in my activity that depends on the data of another list. Both the data list are being observed from the activity from the my viewmodel. After I get the data from my firstlist I need to run a for loop on this list to get the required ids and get the data for the second list.
But keeping the livedata observer in the for loop is causing a lot of problems. The for loop runs as expected but the livedata observer is getting called almost double the amount of the for loop. This happens only the first time when the list in being brought from the api. When I do the same operation a second time where the list is cached and is being brought from the database, the problem does not occur. Below is the source code for the problem,
for (int i = 0; i < firstList.size(); i++) {
final String uId = firstList.get(i).item.uid;
final long id = firstList.get(i).item.id;
viewModel.initAnotherItemRepository(uId, id);
viewModel.getSecondItem().observe(this, new Observer<Resource<List<SecondItem>>>() {
#Override
public void onChanged(Resource<List<SecondItem>> listResource) {
if (listResource.data != null) {
secondItemList.addAll(listResource.data);
if (count == firstList.size() - 1) {
//Do something
}
count = count + 1;
}
if (listResource.state == Resource.STATE_FAILURE) {
showLoadingSpinner(false);
}
}
}
);
}

Try to observe SecondItem outside the for loop. It gets data whenever update
viewModel.getSecondItem().observe(this, new Observer<Resource<List<SecondItem>>>() {
#Override
public void onChanged(Resource<List<SecondItem>> listResource) {
if (listResource.data != null) {
secondItemList.addAll(listResource.data);
if (count == firstList.size() - 1) {
//Do something
}
count = count + 1;
}
if (listResource.state == Resource.STATE_FAILURE) {
showLoadingSpinner(false);
}
}
}
);
for (int i = 0; i < firstList.size(); i++) {
final String uId = firstList.get(i).item.uid;
final long id = firstList.get(i).item.id;
viewModel.initAnotherItemRepository(uId, id);
}

Related

How to know if there is an action on the DB in Java?

I have two applications A and B and I need to modify data in B that comes through a DB from A (check if there is a new record in a specific table).
I have put an infinite loop on B, however I think that is not the best solution.
int i = 0;
for(;;)
{
for(i = 0; i <= 600000;)
{
i++;
}
//Check if there is a new record in a table from app A.
String raw_xml = B.checkDB();
//if there is a new record in a table from app do the
// function doPingTest ()
if (raw_xml!= null)
{
new TestB().doPingTest(raw_xml);
}
i = 0;
}
After doing some tests with other alternatives, this is the best solution:
for(;;)
{
while(true)
{
//sleep one minute
Thread.sleep(60 * 1000);
//Check if there is a new record in the DB
String raw_xml = B.checkDB();
if (raw_xml!= null)
{
new TestB().doPingTest(raw_xml);
}
}
}

Use values from previous row to aggregate values when row missing

I have a whole bunch of rows that contain tax payments.
Each row contains PaymentDueDate.
If row is missing in between PaymentDueDates, I have to use same values from previous row to aggregate for all totals.
In below example, between Row="2" and Row="3", data is missing for months 2015/09, 2015/10, 2015/11, 2015/12, 2016/01, 2016/02.
So, I have to use Row="2" values to use to account for missing rows.
<PaymentChangeMaintenance>
<PaymentChangeMaintenanceTransaction Row="1">
<BuydownSubsidyAmount>0.00</BuydownSubsidyAmount>
<AnnualInterestRate>4.75000</AnnualInterestRate>
<PIAmount>689.79</PIAmount>
<PaymentDueDate>2015-07-01</PaymentDueDate>
<CityTaxAmount>23.22</CityTaxAmount>
<CountyTaxAmount>32.25</CountyTaxAmount>
</PaymentChangeMaintenanceTransaction>
<PaymentChangeMaintenanceTransaction Row="2">
<BuydownSubsidyAmount>0.00</BuydownSubsidyAmount>
<AnnualInterestRate>4.75000</AnnualInterestRate>
<PIAmount>689.79</PIAmount>
<PaymentDueDate>2015-08-01</PaymentDueDate>
<CityTaxAmount>125.25</CityTaxAmount>
<CountyTaxAmount>666.22</CountyTaxAmount>
</PaymentChangeMaintenanceTransaction>
<PaymentChangeMaintenanceTransaction Row="3">
<BuydownSubsidyAmount>0.00</BuydownSubsidyAmount>
<AnnualInterestRate>4.75000</AnnualInterestRate>
<PIAmount>689.79</PIAmount>
<PaymentDueDate>2016-03-01</PaymentDueDate>
<CityTaxAmount>125.25</CityTaxAmount>
<CountyTaxAmount>666.22</CountyTaxAmount>
</PaymentChangeMaintenanceTransaction>
</PaymentChangeMaintenance>
Here is code someone wrote, but it is not clean-looking. I would like to use for-each :/
private void aggregateEscrowPaymountAmounts(List<PaymentChangeMaintenanceFieldsV214Type> fieldsType,
PaymentChangeMaintenance paymentChangeMaintenance, final int numberOfTrialPayments) {
AtomicInteger cnt = new AtomicInteger(1);
Iterator<PaymentChangeMaintenanceFieldsV214Type> fieldsTypeIterator = fieldsType.iterator();
PaymentChangeMaintenanceFieldsV214Type fieldType = fieldsTypeIterator.next();
PaymentChangeMaintenanceFieldsV214Type nextFieldType = null;
if (fieldsTypeIterator.hasNext()) {
nextFieldType = fieldsTypeIterator.next();
}
LocalDate monthDate = fieldType.getNextPaymentDueDate();
while (cnt.getAndIncrement() <= numberOfTrialPayments) {
PaymentChangeMaintenance tempPaymentChangeMaintenance = createPaymentChangeMaintenanceEscrow(fieldType);
paymentChangeMaintenance.aggregate(tempPaymentChangeMaintenance);
monthDate = monthDate.plusMonths(1);
if (nextFieldType != null) {
LocalDate nextFieldTypeDate = nextFieldType.getNextPaymentDueDate();
if (nextFieldTypeDate.getMonthValue() == monthDate.getMonthValue()) {
fieldType = nextFieldType;
if (fieldsTypeIterator.hasNext()) {
nextFieldType = fieldsTypeIterator.next();
} else {
nextFieldType = null;
}
}
}
}
}
For this certain case you can use a following approach: determine a step - for you it's a month. Then initialize a default value for a case of absence of the value on the next step. Then use some method that will take a next value and default value and depends on a step presence will return one of them
Here is a pseudocode:
List<Item> items;
Item nextItem = items.get(0);
Value step = month;
for (int i = 1; i < items.size(); i++) {
nextItem = getNextItem(items.get(i), nextItem, step);
****
}
Item getNextItem(Item nextItem, Item defaultItem, Value step) {
if (!nextItem.getStepValue().equals(calcNext(step))) {
return defaultItem;
} else {
return nextItem;
}
}
StepValue calcNext(Value step) {
/*some calculations. In your case month increment*/
}

(Java) How do I make a database delete a stored value until the value has been stored more than 5 times?

I'm kinda trying to make a VERY basic replication of memory in a way.
Basically, I want my program to take in user input and forget it (delete it from database)after about 18 seconds, but remember it (permanently store it in database) if input is repeated 5 times or more.
Here's the code I have so far (It's a JavaFX program by the way):
TextField userText = new TextField();
Timeline time;
String message;
message = userText.getText();
ArrayList<String> memory = new ArrayList<>();
if(message.contains(message) && message.contains(" ") && !memory.contains(message)){
String[] splitMessage = message.split(" ");/*To split the sentence*/
for(int i = 0; i<splitMessage.length; i++)
memory.add(splitMessage[i]); /*To add the individual words of a sentence*/
memory.add(message); /*To add the sentence itself*/
time = new Timeline(new KeyFrame(Duration.millis(18000),
ae -> memory.remove(message)));
time.play();
}
So I have this so far and it works at storing data for 18 seconds. But I want it so the data is permanently stored into "memory" after the program has attempted to store the same message more than 5 times, whether consecutively or in random order.
Is there a way to do this?
Hope this made sense. I'm known for not wording questions properly haha.
Thanks in advance :).
This is my attempt at providing an additional layer of complexity to suffice your needs (if I understand them correctly).
I would replace:
ArrayList<String> memory = new ArrayList<>();
with
MemorySpace memorySpace = new MemorySpace();
The only problem that I see is the proper interpretation of:
!memory.contains(message);
It could be
memorySpace.isMemoryPermanent(message);
or
memorySpace.isMemoryActive(message);
Hopefully the API is clear enough for you to understand my intentions and how it could help in your situation. As I understand it a word is remembered permanently the first time but a sentence needs five time to become permanent.
public class MemorySpace {
private final Map<String, Memory> memorySpace;
public MemorySpace() {
this.memorySpace = new HashMap<>();
}
public void addWord(String word) {
Memory m = this.memorySpace.get(word);
if (m == null) {
this.memorySpace.put(word, new Memory(true, word))
}
}
public void addSentence(String sentence) {
Memory m = this.memorySpace.get(sentence);
if (m == null) {
this.memorySpace.put(sentence, new Memory(false, sentence))
}
else {
m.increaseSeenCount();
}
}
public boolean isMemoryPermanent(String workOrSentence) {
Memory m = this.memorySpace.get(wordOrSentence)
if (m != null) {
return m.isMemoryPermanent();
}
return false;
}
public boolean isMemoryActive(String workOrSentence) {
Memory m = this.memorySpace.get(wordOrSentence)
if (m != null) {
return m.isMemoryActive();
}
return false;
}
private class Memory {
private final boolean isWordMemory;
private final String wordOrSentence;
private int seenCount;
private long lastSeenAtMilliseconds;
Memory(boolean isWordMemory, String newWordOrSentence) {
this.isWordMemory = isWordMemory;
this.wordOrSentence = newWordOrSentence;
this.seenCount = 1;
this.lastSeenAtMilliseconds = System.currentTimeMillis();
}
boolean isWordMemory() {
return this.isWordMemory;
}
void increaseSeenCount() {
if (!this.isWordMemory) {
if (this.seenCount < 5) { // Stop overflow
this.seenCount++;
}
this.lastSeenAtMilliseconds = System.milliseconds();
}
}
void isMemoryPermanent() {
return this.isWordMemory || this.seenCount >= 5;
}
void isMemoryActive() {
return this.isWordMemory || this.isMemoryPermanent() || (System.currentTimeMillis() - this.lastSeenAtMilliseconds) < (18 * 1000);
}
}
}

How can I refactor this code and apply OO patterns?

I have four RichTable instances in my class and there is a notion of current table instance . Depending on a flag resetAll I need to clear out selections of either all the tables or all tables except the current one . If resetAll is true then clear out everything , otherwise leave out the current one . The index of the current table is passed as a parameter to the method that does the clean up action.
The call for clearing out everything looks like this :
clearSubTypeSettings(true,-1);
The call for clearing all but the current one looks like this :
clearSubTypeSettings(true, col);
The implementation of the above method is this :
private void clearSubTypeSettings(boolean resetAll, int exceptControl) {
if (!resetAll) {
clearAllExceptCurrent(exceptControl);
} else {
clearAll();
}
}
Now these two methods clearAllExceptCurrent(exceptControl) and clearAll() look almost the same . Here are the implementations :
private void clearAll() {
for (int i = 0; i < SUBTYPE_TABLES; i++)
if (getSubTypeTable(i).getSelectedRowKeys() != null) {
RichTable richTable = getSubTypeTable(i);
RowKeySet rowkeySet = richTable.getSelectedRowKeys();
rowkeySet.clear();
AdfFacesContext.getCurrentInstance().addPartialTarget(richTable);
}
}
And
private void clearAllExceptCurrent(int exceptControl) {
for (int i = 0; i < SUBTYPE_TABLES; i++)
if (i != exceptControl && getSubTypeTable(i).getSelectedRowKeys() != null) {
RichTable richTable = getSubTypeTable(i);
RowKeySet rowkeySet = richTable.getSelectedRowKeys();
rowkeySet.clear();
AdfFacesContext.getCurrentInstance().addPartialTarget(richTable);
}
}
I feel like I am writing duplicate redundant code here and will complicate maintenance in future . How can I improve this code and make it more object oriented ?
You can let clearAll() delegate (=> OOP pattern) to clearAllExceptCurrent() (=> improve code by removing duplicated code, make it more maintainable):
private void clearAll() {
clearAllExceptCurrent(-1);
}
The only difference between your two methods is the condition i != exceptControl in clearAllExceptCurrent(). By passing -1 this condition is always true and therefore effectively non-existent.
The bulk of the repeated code is the bit that clears the table. So how about:
private void clearTable(int id) {
if (getSubTypeTable(i).getSelectedRowKeys() != null) {
RichTable richTable = getSubTypeTable(i);
RowKeySet rowkeySet = richTable.getSelectedRowKeys();
rowkeySet.clear();
AdfFacesContext.getCurrentInstance().addPartialTarget(richTable);
}
}
Then:
private void clearAll() {
for (int i = 0; i < SUBTYPE_TABLES; i++) {
clearTable(i);
}
}
private void clearAllExceptCurrent(int exceptControl) {
for (int i = 0; i < SUBTYPE_TABLES; i++) {
if (i != exceptControl) {
clearTable(i)
}
}
}
EDIT: Moved if statement inside clearTable

How can I convert existing procedural code to use classes?

I'm trying to learn Java and basically my approach has been to take the procedural style I learned with python, and apply it to Java. So I never use classes and just put everything in a single class with many methods(which I just use as python functions). I think I've hit a problem, and need to bite the bullet and use classes, but I'm having trouble wrapping my head around how to do it.
To simplify my problem(ignore the poor design- it's just to illustrate the point), I have a program that takes a list and within a for loop does some math on each item(in this case adds 1 to the value of the list). I only want it to do work on 2 items on the list and then stop(in this example it's the first 2 items but in my real program it could be anywhere in the list). Here's the working code that is similar to how I'm already doing it:
No Classes:
public class LearningClasses {
public static void main(String[] args) {
int[] list = new int[]{1,2,3,4,5,6,7,8,9,10};
int[] data_list = new int[list.length];
for (int current_location = 0; current_location<list.length;current_location++) {
for (int i =0; i<100; i++){
if (check_size(data_list) == false ) {
break;
}
data_list[current_location] = (list[current_location]+1);
}
}
//its done now lets print the results
for (Integer item : data_list) {
System.out.println(item);
}
}
private static boolean check_size(int[] data_list) {
// TODO Auto-generated method stub
int count = 0;
for (int item : data_list) {
if (item != 0) {
count++;
if (count>=2) {
break;
}
}
}
if (count>=2) {
return false;
} else {
return true;
}
}
}
The problem with this code is although it works it's inefficient because it calculates the count on every iteration of the second for loop. In my program I cannot put anything above the first for loop but I can put anything below it, so I thought instead of doing the count every time maybe I could use a class to somehow maintain state and just increment the number as oppose to recalculating every time.
With classes:
public class LearningClassesCounter {
/**
* #param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
int[] list = new int[]{1,2,3,4,5,6,7,8,9,10};
int[] data_list = new int[list.length];
for (int current_location = 0; current_location<list.length;current_location++) {
//can only put commands in here. Nothing above.
Counter checker = new Counter(data_list);
System.out.println(checker.check_data());
for (int i =0; i<100; i++){
data_list[current_location] = (list[current_location]+1);
}
}
//its done now lets print the results
for (Integer item : data_list) {
System.out.println(item);
}
}
}
class Counter {
private int count; // current value
private boolean continue_or_not;
private int[] data_list;
// create a new counter with the given parameters
public Counter(int[] data_list) {
data_list = this.data_list;
count = 0;
continue_or_not = true;
}
public boolean check_data() {
// TODO Auto-generated method stub
int count = 0;
for (int item : data_list) {
if (item != 0) {
count++;
if (count>=3) {
break;
}
}
}
if (count>=3) {
return false;
} else {
return true;
}
}
// increment the counter by 1
public void increment() {
count++;
}
// return the current count
public int value() {
return count;
}
}
This doesn't work because it thinks the data_list is a null pointer(I know I'm declaring it null, but if I make it private int[] data_list = data_list it doesn't compile either). My ultimate goal is to have some kind of controls, in this case its limiting it to 2 items but I want to also add other limits like total value of al items cannot exceed X or cannot be lower than X and want to save CPU power by not having to do full calculations every time. So I think I need to be able to increment the values and then need to check that those increments haven't exceeded thresholds.
Can anyone help me understand what I'm doing wrong? Am I only wrong with syntax; or am I designing this wrong?
//can only put commands in here. Nothing above.
Counter checker = new Counter(data_list);
System.out.println(checker.check_data());
When you are calling checker.check_data(), its trying to parse through the data_list, but its empty. So, it throws a NullPointerException. The data_list is empty because inside your constructor, you may need to initialize like this this.data_list = data_list instead of data_list = this.data_list (here this.data_list has no reference so NULL)
If you avoid that call, the output will be 2,3,4,5,6,7,8,9,10,11.

Categories

Resources