I have an AppWidget that may receive two consecutive update request. To be shown it has to programmatically draw five 50x50 bitmaps, setting some PendingIntent and get some configuration (just to give you a little idea of the work load). It takes around 60 milliseconds between the two calls.
The option I have found so far to avoid the unnecessary update is to have a static field, something like:
public class myWidget extends AppWidgetProvider {
private static long lastUpdate;
#Override
public void onReceive(Context context, Intent intent) {
if((System.currentTimeMillis()-lastUpdate) > 200) {
doUpdates(context);
}
lastUpdate = System.currentTimeMillis();
}
}
With performance and "best practice" in mind...
Which do you think is the best solution in this case?
1) Use the static field (like in the example)
2) Just let the widget update twice
3) Other
In other words, is the use of the static field more harmful than just letting the widget update twice?
To be shown it has to programmatically draw five 50x50 bitmaps, setting some PendingIntent and get some configuration (just to give you a little idea of the work load). It takes around 60 milliseconds between the two calls.
Note that this will cause your UI to drop frames if you happen to have your UI in the foreground at the time the update request(s) come in.
Which do you think is the best solution in this case?
Both #1 and #2.
There is no guarantee that your process will still be around between the two subsequent update requests. Probably it will be around, given that you appear to be optimizing for two updates within 200ms. But it's not guaranteed. So, use the static data member for optimization purposes, but ensure that your code will survive the process being terminated in between.
I'd suggest using SystemClock.elapsedRealtime(), though, instead of System.currentTimeMillis(). System.currentTimeMillis() is based on the real-time clock, which can be adjusted on the fly (e.g., NITZ signals, SNTP updates, user manually changing the clock). SystemClock.elapsedRealtime() is guaranteed to be monotonically increasing, and so it is a better choice for this sort of scenario. Only use SystemClock.elapsedRealtime() when you need to tie something to "real world" time (e.g., as part of work with Calendar objects), not for interval timing.
Related
I am calling MixPanel.flush in my onDestroy method but it looks as if the application is ending before MixPanel has a chance to send / flush its data.
I do not see any data in my MixPanel analytics screen unless I pause my android app using a breakpoint in onDestroy right after MixPanel.flush() is called.
Is there any way I can have my app stay open for MixPanel to finish?
You have to call flush() in your Activity onDestroy()
Like this:
#Override
protected void onDestroy() {
mMixpanel.flush();
super.onDestroy();
}
Notice you call flush() before calling super.onDestroy();, otherwise the activity lifecycle will continue and your call might never be on time, this way the destroy process will at least start after the flush.
It works for me.
It's kinda clumsy (MixPanel should have done a better job) because you might not know what activity the user is leaving your app from and to counteract that problem you have to put that code in your base activity (inherited by all your activities) therefore, causing a flush every time you change activities, which -in turn- defeats the purpose of queueing events…
UPDATE: It's true that the last events may not be flushing even tho Mixpanel recommends to do the above (they probably never thought about it, but since the SDK is open source, we might want to take a look)
In spite of Mixpanel's quality, I recommend calling flush() as early as possible. You can even call flush in the onStop() method of every activity (before super.onStop()) and that way you make sure each Activity flushes its events every time it's stopped.
Although this may defeat the purpose of the mixpanel network friendly queuing, it may e the only way (without resorting to strange hacks) to keep the events synced.
Because of all this, I took a look at mixpanel's source code (which I had checked out) and they also have a method to define the flush frequency:
/**
* Sets the target frequency of messages to Mixpanel servers.
* If no calls to {#link #flush()} are made, the Mixpanel
* library attempts to send tracking information in batches at a rate
* that provides a reasonable compromise between battery life and liveness of data.
* Callers can override this value, for the whole application, by calling
* <tt>setFlushInterval</tt>.
*
* #param context the execution context associated with this application, probably
* the main application activity.
* #param milliseconds the target number of milliseconds between automatic flushes.
* this value is advisory, actual flushes may be more or less frequent
*/
public static void setFlushInterval(Context context, long milliseconds);
Maybe reducing this number might help.
The default value seems to be:
// Time interval in ms events/people requests are flushed at.
public static final long FLUSH_RATE = 60 * 1000;
What flush() does, is just post a message to the worker thread always running.
The Worker thread intercepts this here:
else if (msg.what == FLUSH_QUEUE) {
logAboutMessageToMixpanel("Flushing queue due to scheduled or forced flush");
updateFlushFrequency();
sendAllData();
}
After updating the FlushFrequency (based upon the current systemTime), it sends the data using HTTP.
I can see why if your main process is dying (last activity) this code may not execute in time…
Last but not least, if you switch to use the library in source code (as opposed to just using the jar), you can change in MPConfig the value of:
public static final boolean DEBUG = false;
to get a lot of logging (among those are the flushes and posts to server). Might help to see what events are actually being sent to the server (and when).
There is also an upper limit to the number of queued items before que queue is forced to flush:
// When we've reached this many track calls, flush immediately
public static final int BULK_UPLOAD_LIMIT = 40;
This is seen in the queue code:
if (queueDepth >= MPConfig.BULK_UPLOAD_LIMIT) {
logAboutMessageToMixpanel("Flushing queue due to bulk upload limit");
updateFlushFrequency();
sendAllData();
}
Good luck :)
I need to get the current value of the proximity sensor (rather than implementing a continuous listener). On some devices, the first reported value will be a default value (e.g. "FAR") that isn't necessarily accurate, and actual values will only start appearing after the second or third reading. At the moment, I've implemented a 1-second Handler and use the last reported value (after the second has elapsed) as the "true" value, but this solution seems crude (and slow). Is there a better approach that works on all 4.0+ devices? I could simply count up until I've received 3 readings, but on some devices (e.g. GNex), the first value will be correct, and the value will only change after that if there is actually a change in the sensor.
You can do what I did:
You probably have an if statement on the listener - one logic flow for near and one for far.
Instead of waiting on the handler - do this:
if(near) {
myHandler.removeCallbacks(yourRunnableForFar);
myHandler.postDelayed(yourRunnableForNear,100);
else {
myHandler.removeCallbacks(yourRunnableForNear);
myHandler.postDelayed(yourRunnableForFar,100);
}
Notice that the inaccurate first reading(s) will immediately be followed by an accurate one, so the last one "wins".
This code works well if you didn't register sensors other than proximity. If you have a flow of readings from other sensors, than use a static flag (such as the boolean near) to trigger the handler calls only on state change.
Elaboration:
yourRunnableForFar and yourRunnableForNear - are placeholders that implement Runnable to hold your app logic on what to do when the proximity sensor returns "near" (event.values[0] == 0) or "far" (not 0).
myHandler is just any Handler you might created, or declare one just for this with Handler myHandler = new Handler(Looper.getMainLooper());
You might want to acquire a proximity lock on near, and release it and clear the listener on far. But this is app logic that might be completely different from app to app.
I have a test case for my app which fills in the TextViews in an Activity and then simulates clicking the Save button which commits the data to a database. I repeat this several times with different data, call Instrumentation.waitForIdleSync(), and then check that the data inserted is in fact in the database. I recently ran this test three times in a row without changing or recompiling my code. The result each time was different: one test run passed and the other two test runs reported different data items missing from the database. What could cause this kind of behavior? Is it possibly due to some race condition between competing threads? How do I debug this when the outcome differs each time I run it?
Looks like a race condition.
remember in the world of threading there is no way to ensure runtime order.
I'm not an android dev so I'm only speculating but UI is only on one event thread generally so when you call the method from another thread (your test) you're probably breaking that as you're outside of the event thread.
You could try using a semaphore or more likely a lock on the resource.
http://docs.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/locks/Lock.html
http://docs.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/Semaphore.html
I (finally!) found a solution to this problem. I now call finish() on the tested Activity to make sure that all of its connections to the database are closed. This seems to ensure consistency in the data when I run the assertions.
I would suggest making a probe for the database data rather than a straight assert on it. By this I mean make a piece of code that will keep checking the database for up to a certain amount of time for a condition rather than waiting for x seconds (or idle time) then check, I am not on a proper computer so the following is only pseudo code
public static void assertDatabaseHasData(String message, String dataExpected, long maxTimeToWaitFor){
long timeToWaitUntil = System.getCurrentTimeMillis() + maxTimeToWaitFor;
boolean expectationMatched = false;
do {
if(databaseCheck() == dataExpected){
expecttionMatched == true;
}
}while(!expectationMatched && System.getCurrentTimeMillis() < timeToWaituntil);
assertTrue(message, expectationMatched);
}
When i get to a computer i will try to relook into the above and make it better (I would actually of used hamcrest rather than asserts but that is personal preference)
Ive got an app with a class that implements Runnable. Where a thread is started and the run() methid overridden. This runs my graphics.
1.st question : how often is the run() called upon? i havent set a time for this so it must be a default value?
2.nd question : i want stuff to be done after a certain amount of time (2min,5min,10min) etc. What would be the best way to go about doing this, i was thinking about using an int as an counter and once it hits a specific value does what i want.
1.st question : how often is the run() called upon? i havent set a time for this so it must be a default value?
The run() method in your Thread is called when you call it eg. yourThread.start();
2.nd question : i want stuff to be done after a certain amount of time (2min,5min,10min) etc. What would be the best way to go about doing this, i was thinking about using an int as an counter and once it hits a specific value does what i want.
There are to options. Either you could call Thread.sleep() method (NB: Never do this in your UI thread).
Or you can do it the way you described above. So in your run() method you would have a while() loop and check on every iteration if the difference of the lastUpdate and the current time in milli seconds is bigger than the wanted period eg. 2 min, 5 min or 10 min.
I hope this helps.
Regarding question 2 - use ScheduledExecutor
1.st question : how often is the run() called upon?
You can find out for yourself, put this at the start of your Runnable:
Log.v("Running Runnable", System.currentTimeMillis() + "");
2.nd question : i want stuff to be done after a certain amount of time (2min,5min,10min) etc.
Extend a HandlerThread (it initializes the Looper for you!), add a Handler as a class variable, and use the Handler's postDelayed() or postAtTime() methods.
The exact amount of time in between calls to run() depends on the processor. The time between each call is the sort of thing that's really visible by the nanosecond. If you're trying to create a timer, I'd recommend using System.currentTimeMillis(), calling it in the run() method, and once the difference is greater than or equal to 1000 milliseconds, the actual timer decrements by one. This will keep track of seconds, and you can use it as a base for minutes and generating other events at specific times.
I collect some information inside a Spinner and this information can change
for example something may disappear or something new may come
I want the application to store this information every 100 seconds in a database
is it possible to do something like this?
I'm thinking of creating a database and within this database storing this information
but I'm not sure about this "every 100 seconds" part, how would I do this?
I'm thinking that maybe I will have to create a process that will be running in parallel, this process will have a time counter and when 100 seconds have passed, the function that will store the information in the database will be called
But I'm not sure if this is possible. I mean, creating such a counter that will run in parallel with the other application.
maybe there is something easier
thanks in advance
On Second Thought:
This is probably not the way to go(AlarmManager). A much better way would be to bind a listener to the spinner. That way you will only react and save data when there is new data to save.
Can you provide some details on the Spinner you are using and perhaps we can work out the event binding.
For the storage, use SQlite: http://developer.android.com/reference/android/database/sqlite/package-summary.html
For the 100 second interval, use the AlarmManager:
This class provides access to the system alarm services. These allow
you to schedule your application to be run at some point in the
future. When an alarm goes off, the Intent that had been registered
for it is broadcast by the system, automatically starting the target
application if it is not already running. Registered alarms are
retained while the device is asleep (and can optionally wake the
device up if they go off during that time), but will be cleared if it
is turned off and rebooted.
http://developer.android.com/reference/android/app/AlarmManager.html
Take a look at this answer for a code sample and further discussion: Android: How to use AlarmManager
I have some same requirement and done this in My application using CountDownTimer
and Created one Custom Class extending CountDownTimer and in that when Finish, I just did perform my data loading and initialized the same object agian to run after using Start
public class MyCounter extends CountDownTimer {
public MyCounter(long millisInFuture, long countDownInterval) {
super(millisInFuture, countDownInterval);
}
#Override
public void onFinish() {
MCObject.cancel();
MCObject = new MyCounter(_intMCCounter, 1000);
MCObject.start();
new tempAysnc().execute(paramList); // code to get data or store data write your code to insert data into database
}
#Override
public void onTick(long millisUntilFinished) {
}
}
In your Activity onCreate() write this code to initiate it first time.
_intMCCounter = 60000 * 5; //set interval to every 5 minutes
MCObject = new MyCounter(_intMCCounter, 1000);
MCObject.start();
and in onDestroy of your Activity write this code to cancel the Timer.
MCObject.cancel();
I think better way is to create a Listener which will check for the data change. If it founds any change of data then it make a function call which will store data in database.
You can use SQLite
I don't see any reason why this couldn't be done. (Only problem is maybe you run out of storage space after a while if you are planning to insert new data constantly)
Check ScheduledThreadPoolExecutor
http://developer.android.com/reference/java/util/concurrent/ScheduledThreadPoolExecutor.html
Android natively supports SQLite so you can use it as your database.