Start objects faster and update Textview faster - java

I want to create multiple timers.
I initialize this in an ArrayList in the MainActivity. These are then added in a ReyclerView so that they are also displayed. To start, I go through a for loop and execute the startTimer () method for each individual object.
Unfortunately, the times are not correct for every timer. That means one timer is faster, the second is slower and so on. So each timer starts at different times or the text changes at different times.
My question now is, are there other approaches to start the timers and change the texts in the TextView so that the GUI is updated faster and the program itself runs faster?
The goal should be that all timers are equally fast and there is no delay. Thanks in advance. Looking forward to answer!
MainActivity
timerList= new ArrayList<>();
for (int i = 1; i <= 10; i++) {
timerList.add(new Timer(i, 600000 * i))); //
Each timer has a different time
}
recyclerView.setLayoutManager(recyclerViewLayoutManager);
adapter = new TimerAdapter(this, timerList);
recyclerView.setAdapter(adapter);
context = this;
button_start.setOnClickListener(v -> {
for (Timer timer: timerList) {
timer.startTimer();
});
#Override
public void updateMyText(int index, long time) {
timerList.get(index-1).setTime(time);
adapter.notifyDataSetChanged();
}
Timer
public interface MyCallback {
public void updateMyText(int index, long time);
}
public Timer(int index, long startTimeMilliseconds) {
this.index = index;
this.time = startTimeMilliseconds;
mTimeLeftInMillis = startTimeMilliseconds;
startTime = startTimeMilliseconds;
}
public void startTimer() {
mCountDownTimer = new CountDownTimer(mTimeLeftInMillis, 1000) {
#Override
public void onTick(long millisUntilFinished) {
mTimeLeftInMillis = millisUntilFinished;
updateCountDownText();
}
#Override
public void onFinish() {
mTimerRunning = false;
}
}.start();
mTimerRunning = true;
}
public void resetTimer() {
mCountDownTimer.cancel();
mTimerRunning = false;
mTimeLeftInMillis = startTime;
timeLeftFormatted = formattedTime(startTime);
changeText(index-1);
}
public void updateCountDownText() {
//MainActivity.timerList.get(getIndex()-1).setTime(mTimeLeftInMillis);
//MainActivity.adapter.notifyDataSetChanged();
if(myCallback != null) {
myCallback.updateMyText(getIndex(), mTimeLeftInMillis);
}
}

Use Live Data and Binding or MVVM design pattern. You don't have to worry about faster update operation of views.

The reason the code you wrote works slowly (and time isnt updated on all views together), is because you are creating a separate CountDownTimer for each of your timers.
You dont have to do that. All you need to do is have a single CountDownTimer, that runs every second and updates all of your views simultaneously.
Make Timer class only store the start time of the timer, and a string with the time it should show, dont create a CountDownTimer inside it.
Instead create a method inside it - "updateTimer()" for updating the string, based on
the current time and the start time of the counter.
Using a single CountDownTimer in your Activity, loop through the list of timers and call updateTimer() on each of your timers, and call adapter.notifyDataSetChanged() when the loop is done.
This will make all your views update together, remove the inefficiency of using multiple CountDownTimers, and only call adapter.notifyDataSetChanged() once every second (as opposed to the amount of timers you have - every second)

i think the main issue is the sequential executing of instructions, and adding Threads concept may resolve the issue ,what i think is Threads and Multi threading will allow timers to start at the same time and any updates or other instructions of code execution will not effect the already running code .
Multi threading refers to two or more tasks executing concurrently within a single program. Tutorial
now To start the threads at exactly the same time (at least as good as possible),we can use a CyclicBarrier:
// We want to start just 10 threads at the same time, but let's control that
// timing from the button_start click thread. That's why we have 11 "parties" instead
//of 10.
final CyclicBarrier gate = new CyclicBarrier(11);
button_start.setOnClickListener(v - > {
for (Timer timer: timerList) {
new Thread() {
public void run() {
gate.await(); // waiting for the gate to open
timer.startTimer();
}
// At this point, all the 10 timers are blocked on the gate.
// Since we gave "11" as the argument, gate is not opened yet.
// Now if we block on the gate from the main thread, it will open
// and all threads will start to do stuff!
gate.await(); // this is the extra 11th which will open the gate
};
This still can't make sure that they are started exactly at the same time on standard JVMs, but you can get pretty close.
replicate the same solution if it works , for the update part

Related

How do I parse data or use Room data correctly?

i'm new to Room database but have been working on it for last 1.5 week. I have recently come across a problem.
I am unable to parse the size of the list of journeys. When I try it always return a 0 even if I use a global variable. This is due to the override method, I believe.
I am trying to get the variable numberOfJourneys = journeys.size. Is there any way round this. Also this is in a fragment.
private JourneyDatabase db;
private List<Journey> journeys;
private int numberOfjourneys;
public void arrayAdapter(){
db = Room.databaseBuilder(getContext(), JourneyDatabase.class, "MyJourneyDatabase").build();
AsyncTask.execute(new Runnable() {
#Override
public void run() {
journeys = db.journeyDao().getAllJourneys();
// journeys.size returns the correct size all the time
}
});
numberOfJourneys = journeys.size();
// journeys.size() returns 0 all the time
for(int i=0; i<numberOfJourneys; i++){
listOfJourneys.add(String.format("Journey %d", i));
}
}
The AsyncTask will execute on a separate thread. Your code will execute the AsyncTask and will immediately move on to the for loop regardless of whether the AsyncTask finished its execution or not. I'll mention a few ways that you can handle this.
Method 1: You can move the for loop inside the AsyncTask itself. This will ensure that the for loop will execute after the data is fetched from the db.
Method 2: Allow this query to be run on the UI thread. AFAIK, Room allows queries to be run on the UI thread if explicitly mentioned.
Method 3: Use a callback. After, the AsyncTask finishes, you can use a callback (implemented using an interface) which will let your activity/fragment know that the AsyncTask has finished and you can carry on with your work.
As the name might suggest, an AsyncTask is being executed asynchronously ... and that's exactly why journeys.size() returns 0 there - because you've never have assigned the records to it.
AsyncTask.execute(new Runnable() {
#Override
public void run() {
/* first retrieve the data */
journeys = db.journeyDao().getAllJourneys();
for(int i = 0; i < journeys.size(); i++){
listOfJourneys.add(String.format("Journey %d", i));
}
/* and then notify the adapter */
arrayAdapter.notifyDataSetChanged();
}
});
see the documentation.

Java Timer For Game for food system

I need a java timer to recognize when it hits a certain time for the game I am making. I am new to timers and I was wondering if this code works somehow. I need the if statement to work.
Timer timer = new Timer(whatevergoeshere,this);
public void farmingTimer()
{
timer.start();
if(timer == 1000)
{
food++;
timer.restart();
timer.start();
{
}
I found a good example page.
But I don't think you should be using timers for this kind of thing. You are probably better off updating things as often as you can, and keeping track of the time between updates. Then in the object that has then timer in, can just keep track of the amount of time passed.
public class FoodTimer
{
public int food = 0;
private double timer = 0;
public void update(double dt)
{
timer += dt;
if(timer > 1000)
{
food++;
timer = 0;
}
}
}
I suggest you read this: How to setup a timer (Java 7).
What you basically want to do is create an instance of the class Timer eg:
Timer timer = new Timer();
In your question above, your constructor call used two parameters. If you read the docs, you will find out those two parameters accept a string (name) and a boolean (isDaemon) eg
Timer(String name, boolean isDaemon)
If you want to learn more about daemon threads, I suggest you read this article: Daemon Threads in Java.
Now, once you have your instance ready, do this:
timer.scheduleAtFixedRate(new TimerTask() { //scheduleAtFixedRate means execution will repeat
#Override
public void run() {
//your code here eg food++;
}
}, 0, 60*1000); // the two values at the end are delay and period - delay is 0 seconds and period states that the block will be executed every minute (both values are in milliseconds)

How to calculate run-time for a multi-threaded program?

I am trying to test the performance (in terms of execution time) for my webcrawler but I am having trouble timing it due to multi-threading taking place.
My main class:
class WebCrawlerTest {
//methods and variables etc
WebCrawlerTest(List<String> websites){
//
}
if(!started){
startTime = System.currentTimeMillis();
executor = Executors.newFixedThreadPool(32); //this is the value I'm tweaking
started=true;
}
for(String site : websites){
executor.submit(webProcessor = new AllWebsiteProcessorTest(site, deepSearch));
}
executor.shutdown();
//tried grabbing end time here with no luck
AllWebsiteProcessorTest class:
class AllWebsiteProcessorTest implements Runnable{
//methods and var etc
AllWebsiteProcessorTest(String site, boolean deepSearch) {
}
public void run() {
scanSingleWebsite(websites);
for(String email:emails){
System.out.print(email + ", ");
}
private void scanSingleWebsite(String website){
try {
String url = website;
Document document = Jsoup.connect(url).get();
grabEmails(document.toString());
}catch (Exception e) {}
With another class (with a main method), I create an instance of WebCrawlerTest and then pass in an array of websites. The crawler works fine but I can't seem to figure out how to time it.
I can get the start time (System.getCurrentTime...();), but the problem is the end time. I've tried adding the end time like this:
//another class
public static void main(.....){
long start = getCurrent....();
WebCrawlerTest w = new WebCrawlerTest(listOfSites, true);
long end = getCurrent....();
}
Which doesn't work. I also tried adding the end after executor.shutdown(), which again doesn't work (instantly triggered). How do I grab the time for the final completed thread?
After shutting down your executors pool
executor.shutdown();
//tried grabbing end time here with no luck
You can simply
executor.awaitTermination(TimeUnit, value)
This call will block untill all tasks are completed. Take the time, subtract T0 from it and voila, we have execution time.
shutdown() method just assures that no new tasks will be accepted into excution queue. Tasks already in the queue will be performed (shutdownNow() drops pending tasks). To wait for all currently running tasks to complete, you have to awaitTermination().

How to create a Java function which Once called, cannot be called Again unless there is some DELAY?

I'm trying to make a function which can ONLY be called again after there is some amount of time delay between the two calls, (Say 5 seconds).
I require this functionality for an android app I'm creating.
Since it is possible that the user would be calling that function too frequently within a few seconds, it would destroy his experience. Hence, I'm desperately looking for an answer on this.
public void doSomethin(){
//code here which makes sure that this function has not been called twice within the specified delay of 5 seconds
//Some code here
}
Any help would be awesome!
Adit
You could hold the time in milliseconds and check if the current time is greater than or equal to the previous time + 5 seconds. If it is, execute the method and replace the previous time with the current time.
See System.currentTimeMillis()
public class FiveSeconds {
private static Scanner scanner = new Scanner(System.in);
private static long lastTime = 0;
public static void main(String[] args) {
String input = scanner.nextLine();
while(!input.equalsIgnoreCase("quit")){
if(isValidAction()){
System.out.println(input);
lastTime = System.currentTimeMillis();
} else {
System.out.println("You are not allowed to do this yet");
}
input = scanner.nextLine();
}
}
private static boolean isValidAction(){
return(System.currentTimeMillis() > (lastTime + 5000));
}
}
If the code runs on your main thread, Thread.sleep(5000) is not an option. The easiest way to go then would be:
private long previous = 0;
public void doSomething() {
long now = Calendar.getInstance().getTimeInMillis();
if (now - previous < 5000)
return;
previous = now;
// do something
}
use a static field, which saves the datetime of last execution and before executing check the current datetime against this timestamp.
I won't write code for you but if you think a bit about this it's not that hard. You want to make sure it's not called before 5 seconds has passed since last function call. Let's split this into parts.
1) Get current time
2) Compare to stored time that keeps it value between calls.
3) If less than 5 seconds has passed don't do anything
4) Otherwise store the new value and do stuff.
I never did coding in Android. But if Android has threads (which is most likely, it does). Then within this function sleep the thread for 5 seconds, it means even though it is called, it won't be executed further until 5 seconds are passed
public void doSomething()
{
Thread.sleep(5000); // Please find the corresponding Android method
}
make doSomethin() as a private method.
Expose another function say exposedDoSomething().
public void exposeDoSomething(){
// Add to a queue
}
In a separate thread read the queue in every 5 mins and call doSomethin()
Maybe a TimerTask will help you, more details here:
TimerTask|Android Developers
Example:
private TimerTask tiemrTast= new TimerTask() {
#Override
public void run() {
}
};
And then use this method: public void scheduleAtFixedRate (TimerTask task, long delay, long period)
One problem is that you'll have to have a session level timer for each and every user. This could be a fair amount of overhead depending on how many simultaneous users you have.
It's easy for one user: start a timer on request. It's distinguishing between users that's the problem. Your service is now stateful, which is usually a bad thing. You're giving away idempotence.
You could also maintain state in a database. Don't worry about calls; check persistent operations to make sure they don't happen too frequently.
It's not clear to me whether you mean to exclude all users for five seconds once the method is called by anyone, or if every user is prevented from calling the method again for five seconds once it's called the first time.
This sounds like a throughput killer. I'd reconsider this design.
you can use hander.postDalayed method to call method to run after specific delay
you can use your method something like this
int delay=5000;
int k;
int iDelayTimeInMiliSeconds=2000;
for( k=0;k<arrBatch.size();k++)
{
delay=delay+iDelayTimeInMiliSeconds;
callAllDocumentList(arrBatch.get(k),k,delay);
}
public void callAllDocumentList(final String strInvoiceId,final int count,int delay)
{
mHandler.postDelayed(new Runnable()
{
#Override
public void run()
{
// call your function here that you want to call after specific delay
//getOrderDetails(strInvoiceId,count,true);
}
}, delay);
}

Decrement at Regular Intervals in Java

I'm writing an application in Java, but need to know how to subtract from a variable once every second. What's the easiest way to do this? Thanks!
The name of the very Java class you need to use to do repeating operations is already sitting there in one of your tags! ;)
While the Timer class will work, I recommend using a ScheduledExecutorService instead.
While their usage is extremely similar, ScheduledExecutorService is newer, more likely to receive ongoing maintenance, fits in nicely with other concurrent utilities, and might offer better performance.
class YourTimer extends TimerTask
{
public volatile int sharedVar = INITIAL_VALUE;
public void run()
{
--sharedVar;
}
public static void main(String[] args)
{
Timer timer = new Timer();
timer.schedule(new YourTimer(), 0, 1000);
// second parameter is initial delay, third is period of execution in msec
}
}
Remeber that Timer class is not guaranteed to be real-time (as almost everything in Java..)
What are you trying to achieve? I would not try relying on the timer to properly fire exactly once per second. I would simply record the start time, and whenever a timer fires, recalculate what the value of the variable should be. Here's how I would do it...
class CountdownValue {
private long startTime;
private int startVal;
public CountdownValue(int startVal)
{
startTime = System.currentTimeMillis();
}
public int getValue()
{
return startVal - (int)((System.currentTimeMillis() - startTime)/1000);
}
}
Use a java.util.Timer to create a TimerTask.

Categories

Resources