I have one singleton object which actually store user activity. I wanted to remove this data on certain time ( at every night 12 ). I wanted to know How we can achieve this with out having different thread running.
Add a method to the singleton that returns the last date it ran:
static Date lastRun = new Date(); //when the class initializes
Date lastDateRan() {
return lastRun;
}
Then add another method that checks if today > lastRun (pay attention to check only the date - not time/hour - in case you decide to use TimeStamp or any other library).
Whenever the object is called, check:
if (today > lastRun) {
lastRun = today;
// and clean the object.
}
It won't run every-day exactly at midnight, but it'll have the exact same effect! (the first call after midnight will get "fresh" data)
You can use following code :
new java.util.Timer().schedule(
new java.util.TimerTask() {
#Override
public void run() {
Object_name.close //your code to cleanup object
}
},
12*60*60*1000 /*time after which it will run again*/
);
Related
I have a data class that extends Application and one of the data sets its supposed to be storing is a HashMap of POI locations and Time visited
public class CharacterSheet extends Application {
private HashMap<PointOfInterest, Date> coolDowns = new HashMap<>();
public HashMap GetAllCoolDowns() { return coolDowns; } //dev only?
public Date GetCoolDown(PointOfInterest poi) {return coolDowns.get(poi);}
public Date PutCoolDown(PointOfInterest poi, Date date) {return coolDowns.put(poi, date);}}
Then on a google maps activity I grab the OnPOIclick
#Override
public void onPoiClick(final PointOfInterest poi) {
//POI Cool Down
Date currentTime = Calendar.getInstance().getTime();
Date lastTime = ((CharacterSheet) this.getApplication()).GetCoolDown(poi);//this ONLY returns null??
if (lastTime != null){
int timeDiff = currentTime.compareTo(lastTime);
makeToast("Time Since last visit: " + timeDiff );
} else { makeToast("First");
}
((CharacterSheet) this.getApplication()).PutCoolDown(poi, currentTime);
makeToast("This?" + ((CharacterSheet) this.getApplication()).GetCoolDown(poi));}
The order should be Click poi, Get current time.. get last time visited, if last time is null.. never been before, store time and date in a hashmap with poi as key
Next time turn up and this time last time should not be null as we stored this poi and time already.. but no matter what it returns null..
Last line of code is a makeToast helper telling me what is in the Data Class.. this gives me a date value of when I clicked not a null value
There is a fragment generated later on in the OnPOIClick, but still before the user can do anything, which you end up looking at and have to "back" out of, I don't know how this could effect it as all the code is finished before even calling for data for the fragment but feel It should be mentioned
PlacesClient placesClient = Places.createClient(this);
String placeId = poi.placeId;
List<Place.Field> placeFields = Arrays.asList(Place.Field.ID, Place.Field.TYPES);
FetchPlaceRequest request = FetchPlaceRequest.newInstance(placeId, placeFields);
placesClient.fetchPlace(request).addOnSuccessListener(new OnSuccessListener<FetchPlaceResponse>() {
#Override
public void onSuccess(FetchPlaceResponse fetchPlaceResponse) {
Place place = fetchPlaceResponse.getPlace();
PlaceDataHolder holder = new PlaceDataHolder(place);
String placeName = poi.name;
makeLootFragment(holder,placeName);
The Fragment launched is the entire point of clicking the POI so if this is the case I'll need to think of another way of handling the cooldowns.. but I really don't see why it would interfere.
I was not being thoughtful enough about the PointOfInterest that was returned. It comes with a UUID for every time the request is made, rendering it useless as a key as every time I clicked it changed.. this was discovered by changing my post operation check from making sure it had gone into the hashMap, to seeing the contents of the entire hashMap, soon saw that the entries where building up despite only clicking one poi
To solve this was simple enough. I created a new String variable from poi.name and used that in place of the poi, had to change the HashMap to accept a String rather than a PointOfInterest
So I am a noob at Android, and I'm writing a simple app that uses Google Fit to store the users fitness sessions and step count and then retrieve them.
I have two methods, one that fetches all the sessions from a given date range from the cloud, the next method iterates through these and adds up the step count.
Problem is, that although I call the the fetching method first, the result doesn't come back until after I've added the steps up, so step count is always zero.
Here's my code:
private ArrayList<> results;
#Override
public ArrayList<IndividualSession> readAllSessions(Date dateFrom, Date dateTo) {
/* I haven't included the following code in this question just to keep things clean, but here there was
- The initialisation of the results ArrayList
- Creating the calendar and date objects
- Building the session read request
*/
Fitness.SessionsApi.readSession(mGoogleApiClient, readRequest).setResultCallback(new ResultCallback<SessionReadResult>() {
#Override
public void onResult(SessionReadResult sessionReadResult) {
for (Session session : sessionReadResult.getSessions()) {
List<DataSet> dataSets = sessionReadResult.getDataSet(session);
for (DataSet dataSet : dataSets) {
for (DataPoint dataPoint : dataSet.getDataPoints()) {
// Create new IndividualSession object, add data to it then add it to arraylist
IndividualSession individualSessionObject = new IndividualSession();
individualSessionObject.setFromDate(new Date(session.getStartTime(TimeUnit.SECONDS)));
individualSessionObject.setToDate(new Date(session.getEndTime(TimeUnit.SECONDS)));
individualSessionObject.setStepCount(dataPoint.getValue(Field.FIELD_STEPS).asInt());
results.add(individualSessionObject);
}
}
}
Log.i(TAG, "Number of sessions found while reading: "+results.size());
}
});
return results;
}
#Override
public int getDaySteps(Date dateTo) {
int stepCount = 0; // to be returned
// Sort out the dates
Calendar calFrom = Calendar.getInstance();
calFrom.add(Calendar.HOUR, -24);
// Get the sessions for appropriate date range
ArrayList results = readAllSessions(calFrom.getTime(), dateTo);
Log.i(TAG, "Number of sessions found while trying to get total steps: "+results.size());
// Iterate through sessions to get count steps
Iterator<IndividualSession> it = results.iterator();
while(it.hasNext())
{
IndividualSession obj = it.next();
stepCount += obj.getStepCount();
}
return stepCount;
}
This outputs
"Number of sessions found while trying to get total steps: 0"
"Number of sessions found while reading: 8"
There are two solutions to this :
Option 1 : Use a blocking colleciton
Change the ArrayList<> results to an ArrayBlockingQueue<> results.
After the call to the readAllSessions method in the getDaySteps method, call while(results.take()!=null) { //rest of the logic }
You need some kind of mechanistm to exit the while loop in step 2 when all results are read
Option 2 : Use the await method from PendingResult
Looking at the documentation for SessionsAPI class, the readSessions method seems to return a PendingResult :
public abstract PendingResult readSession
(GoogleApiClient client, SessionReadRequest request)
Reads data from the user's Google Fit store of the specific type(s)
and for the specific session(s) selected from the request parameters.
Looking at the documentation of the await method in PendingResult class :
public abstract R await ()
Blocks until the task is completed. This is not allowed on the UI thread. The returned result object can have an additional failure mode
of INTERRUPTED.
This is what you can do. Instead of chaining the entire call to setResultCallBack, first call readSessions :
results = Fitness.SessionsApi.readSession(mGoogleApiClient, readRequest);
And then wait for the results in the getDaySteps method :
SessionReadResults sessionResults = results.await();
for (Session session : sessionReadResult.getSessions()) {
List<DataSet> dataSets = sessionReadResult.getDataSet(session);
for (DataSet dataSet : dataSets) {
for (DataPoint dataPoint : dataSet.getDataPoints()) {
// Create new IndividualSession object, add data to it then add it to arraylist
IndividualSession individualSessionObject = new IndividualSession();
individualSessionObject.setFromDate(new Date(session.getStartTime(TimeUnit.SECONDS)));
individualSessionObject.setToDate(new Date(session.getEndTime(TimeUnit.SECONDS)));
individualSessionObject.setStepCount(dataPoint.getValue(Field.FIELD_STEPS).asInt());
//use the results
}
}
}
*results must be declared as an instance/class level variable to be accessible in all the methods in the class. The variable result is of type PendingResult<SessionReadResults>. Also, looks like you can do away with the results ArrayList since everything you want can be extracted from the SessionReadResults returned by the await method. One last note, this answer has not been tested with your code because your code sample is not complete.
A single JUnit test being run under JUnit 4.11 fail the majority of the time while being run via either to module test suite (40 runs: 2 failures, 38 passes), or the class test suite (40 runs: 6 failures, 34 passes), but running the test method by itself did not produce a single failure (50 runs: 0 failures, 50 passes).
To summarize what is happening, the equals(Object MyObject) implementation returns true if the org.joda.time.DateTime corresponding to the key Stamp.START or the key Stamp.STOP is the same for the current instance as the one in instance passed to the method. Here's the code:
import org.joda.time.DateTime;
...
private final Map<Stamp, DateTime> timeStampMap;
...
#Override
public boolean equals(Object obj) {
if (this == obj) { return true; }
if (obj == null || getClass() != obj.getClass()) { return false; }
final MyObject other = (MyObject) obj;
return (Objects.equals(this.timeStampMap.get((Stamp.START)),
other.timeStampMap.get(Stamp.START))
&& Objects.equals(this.timeStampMap.get(Stamp.STOP),
this.timeStampMap.get(Stamp.STOP)));
}
...
public enum Stamp {
START,
STOP
}
And the test itself:
#Test
#Config(configuration = TestConfig.NO_CONFIG)
public void equalityTest() {
MyObject a = new MyObject(BigDecimal.TEN);
MyObject b = a;
assertThat(a.hashCode(), is(b.hashCode()));
assertTrue(a.equals(b));
b = new MyObject(BigDecimal.TEN);
// This line produces the failure
assertThat(a, is(not(b)));
}
Why would this test only fail when run under either test suite, but not when run on it's own?
Since you are using Joda time, an alternative approach might be to fix the current time to something of your choosing using DateTimeUtils.setCurrentMillisFixed(val).
For example:
#Test
#Config(configuration = TestConfig.NO_CONFIG)
public void equalityTest() {
DateTimeUtils.setCurrentMillisFixed(someValue);
MyObject a = new MyObject(BigDecimal.TEN);
MyObject b = a;
assertThat(a.hashCode(), is(b.hashCode()));
assertTrue(a.equals(b));
DateTimeUtils.setCurrentMillisFixed(someValue + someOffset);
b = new MyObject(BigDecimal.TEN);
// This line produces the failure
assertThat(a, is(not(b)));
}
I suggest making the code more testable. Instead of having the code get the date directly, you can pass in an interface named Clock:
public interface Clock {
DateTime now();
}
Then you could add Clock to the constructor:
MyObject(BigDecimal bigDecimal, Clock clock) {
timeStampMap.put(Stamp.START, clock.now());
}
For production code, you can make a helper constructor:
MyObject(BigDecimal bigDecimal) {
this(bigDecimal, new SystemClock());
}
...where SystemClock looked like this:
public class SystemClock implements Clock {
#Override
public DateTime now() {
return new DateTime();
}
}
Your tests could either mock Clock or you could create a fake clock implementation.
Over the process of trying to produce an MCVE and author the question, I discovered something interesting:
When the test is run at the method level, note the timestamp difference of 1 millisecond. The difference is never less than that:
[START: 2015-02-26T11:53:20.581-06:00, STOP: 2015-02-26T11:53:20.641-06:00, DURATION: 0.060]
[START: 2015-02-26T11:53:20.582-06:00, STOP: 2015-02-26T11:53:20.642-06:00, DURATION: 0.060]
But when I run the test ends up being run as part of the suites, this happens nearly every single time:
[START: 2015-02-26T12:25:31.183-06:00, STOP: 2015-02-26T12:25:31.243-06:00, DURATION: 0.060]
[START: 2015-02-26T12:25:31.183-06:00, STOP: 2015-02-26T12:25:31.243-06:00, DURATION: 0.060]
Zero difference. Weird right?
My best guess is that the JVM is proverbially all warmed up and has some momentum built by the time it reaches this particular test when running the test suites. So much so, that the instantiations occur so quickly as to be nearly simultaneous. The tiny amount of time that passes between the time that MyObject a is instantiated and b is assigned until b is reassigned as a new MyObject is so minute as to produce a MyObject with an identical pair of DateTimes.
Turns out, there are a few usable solutions:
The Solution I Went With:
This is really similar to Duncan's. Call DateTimeUtils.setCurrentMillisOffset(val) before reassigning MyObject b and then reset immediately afterward, since I only need the offset long enough to force a difference in the DateTimes between MyObjects a and b:
#Test
#Config(configuration = TestConfig.NO_CONFIG)
public void equalityTest() {
MyObject a = new MyObject(BigDecimal.TEN);
MyObject b = a;
assertThat(a.hashCode(), is(b.hashCode()));
assertTrue(a.equals(b));
// Force an offset
DateTimeUtils.setCurrentMillisOffset(1000);
b = new MyObject(BigDecimal.TEN);
// Clears the offset
DateTimeUtils.setCurrentMillisSystem();
assertThat(a, is(not(b)));
}
Namshubwriter's Solution (link to answer):
Easily the best solution in cases where this issue will likely be seen throughout a project and/or in actual use.
Duncan's Solution (link to answer):
Set the current time to return a fixed time by calling DateTimeUtils.setCurrentMillisFixed(val) at the beginning of the unit test, then adding an offset to that time by calling DateTimeUtils.setCurrentMillisFixed(val + someOffset) to force the difference before reassigning MyObject b. Click the link to jump right to his solution with the code.
It is worth pointing out that you'll need to call DateTimeUtils.setCurrentMillisSystem() at some point to reset the time, otherwise other tests dependent on the time could be affected.
Original Solution:
I think it is worth mentioning here that, it is my understanding this is the only solution that does not depend on the program having certain security privileges on the parent system.
Place a call to Thread.sleep() ensure that there is a time separation between the DateTime timestamps of the two MyObjects:
#Test
#Config(configuration = TestConfig.NO_CONFIG)
public void equalityTest() {
MyObject a = new MyObject(BigDecimal.TEN);
MyObject b = a;
assertThat(a.hashCode(), is(b.hashCode()));
assertTrue(a.equals(b));
try {
Thread.sleep(0, 1);
} catch (Exception e) {
e.printStackTrace();
}
b = new MyObject(BigDecimal.TEN);
// Line that was failing
assertThat(a, is(not(b)));
}
As an experiment I ran the following code snippet (simplified):
public class SGamePlay extends Activity implements View.OnClickListener
{
Calendar GlobalCal = null;
public void onCreate(Bundle savedInstanceState)
{
GlobalCal = Calendar.getInstance();
}
long time_in_ms()
{
long ans = -1;
long ans2 = -1;
Calendar LocalCal = Calendar.getInstance();
ans = LocalCal.getTimeInMillis();
ans2 = GlobalCal.getTimeInMillis();
Log.e("game","ans="+ans+" ans2="+ans2);
return ans;
}
// much more code here...
}
The time_in_ms() function is called from a sub thread. The problem is that while ans appears to be a correct, constantly updating value, ans2 appears frozen at its initial value. How could this be?
EDIT: I need to resolve this issue because I want to reduce the need for garbage collection in my program.
Calendar is to be thought of as a "mark" in a calendar. It's more like a point in time, than an interface to the current time. (Why else would it have set-functions?)
So, the reason why ans2 is "frozen" is because GlobalCal.getTimeInMillis(); will always refer to the time when you called Calendar.getInstance() in the constructor (which you did once).
I need to resolve this issue because I want to reduce the need for garbage collection in my program.
Is the garbage collection the bottle neck of your program? Is the number of Calendars the bottle neck of the GC? Have you profiled your program?
Never mind... call System.currentTimeMillis instead.
GlobalCal is initialized in the oncreate method. It is not modified after that. How would you want it to change then ?
By the way, a variable name in java begins with a lowercase letter and follows camel case.
I want to have thread save method that returns a unique current Timestamp.Even when the method is called by same time i want to get a unique current datetime.Even if this method is called by making multiple instances of MyClass i want it be be thread safe always
class Myclass{
Date getUniquetimeStam(){
synchronized(Myclass.class){
//return date here
}
}
Now if i make 2 instances of Myclass and call getUniqueStam at same ,is it gaurented to return uniue date time.
You can't guarantee unique time for each call. But you can for instance increment it manually if it didn't change yet:
private AtomicLong lastTime = new AtomicLong();
long getUniquetimeStam() {
while (true) { // way of working with atomics, but they are really fast
long now = System.currentTimeMillis();
long last = lastTime.get();
if (last < now) {
if (lastTime.compareAndSet(last, now))
return now;
} else
return lastTime.incrementAndGet();
}
}
No, you are not guaranteed. If your computer is fast enough then both method calls can happen in same millisecond and produce identical Date object.
You have 2 options here:
Use UUID instead of date. Read more about it here . UUID by specification is guaranteed to be unique each time you generate it - so it's the safest and easiest option you can get.
Store the date object, synchronize on it, and check if it's the same. Here's an example:
.
class Myclass {
//Static to make it possible to synchronize between instances of Myclass
static Date lastDate;
Date getUniqueTimeStamp() {
synchronized (Myclass.lastDate) {
Date newDate = new Date();
if (newDate.getTime() <= Myclass.lastDate.getTime()) {
newDate.setTime(Myclass.lastDate.getTime()+1);
}
Myclass.lastDate.setTime(newDate.getTime());
return newDate;
}
}
}
Not cool though - you can add a delay and then create the Data.
class Myclass {
Date getUniquetimeStam() {
//in try catch
Thread.sleep(100);
//
new Date();
}
}
Could you just change it to return a new instance of Date on every call?
class Myclass {
Date getUniquetimeStam() {
new Date();
}
}