I'm writing an android app which should take pictures in a user-defined interval (20 sec - 1 min). It should take the pictures even while it is running in background or while the device is sleeping. The app will run for a very long time period. If it is necessary to wake up the device, it should put back to sleep as soon as possible to save batterie life. After taking a picture the app will process some additional work (comparison of two pictures).
I read some stuff about sheduling alarms (http://developer.android.com/training/scheduling/alarms.htm), creating Services (also # android training) and Android AsyncTasks, Java threads (http://www.mergeconflict.net/2012/05/java-threads-vs-android-asynctask-which.html)
... but I'm still not sure what is the best way to achieve this.
My questions are:
Should I use thread or a task to take the pictures in background?
(the comparison of the two pictures might take longer than a few
milliseconds but i don't know anything about the cpu load of this
operation)
Should I use an alarm to wake the device up or are there any alternative solutions?
How can both (alarms and thread/task) work together? (Include the Alarm in the Task/Thread?)
Many thanks for your help in advance.
As to our question I know I can help get started with the aspect of repeating the picture taking task at a user defined time interval. For such a task you can user a Timer to achieve this. The code would look something like this:
mTmr = new Timer();
mTsk = new TimerTask() {
#Override
public void run() {
//Take picture or do whatever you want
}
};
mTmr.schedule(mTsk, 0, USER_DEFINED_EXECUTION_INTERVAL);
schedule begins the timer. The first parameter of schedule used here is the task to run which is mTsk. The second parameter is the delay until the first execution (in milliseconds), in this case no delay. The third parameter is what you'll want to manipulate which is the interval of executions. The parameter is the time between executions so if it were 20 seconds you'd pass in 20,000. If it were a minute it would be 60,000. You can get this value from the user using any method you'd like.
To keep the timer running make sure you don't call mTmr.cancel in onPause because for your case you want to keep the timer running while the user isn't on the app. Not calling cancel means the timer will hold it's resources until the app is closed by the user.
OR you can look at this How to schedule a periodic task in Java? If you'd like to use ScheduledExecutorService instead of a Timer.
I have made this app - Lenx. It uses Camera extensively and I am processing image in the background. I have used AsyncTask to process the image and it has never given any problems. The app also has a timer which starts the process after certain interval. The logic that I have used is very simple.
I have not used Camera2 API yet, so the code might be deprecated. I created CameraPreview class which implements Camera.PreivewCallback.
#Override
public void onPreviewFrame(byte[] data, Camera camera) {
if (data == null) {
return;
}
int expectedBytes = previewWidth * previewHeight *
ImageFormat.getBitsPerPixel(ImageFormat.NV21) / 8;
if (expectedBytes != data.length) {
Log.e(TAG, "Mismatched size of buffer! Expected ");
mState = STATE_NO_CALLBACKS;
mCamera.setPreviewCallbackWithBuffer(null);
return;
}
if (mProcessInProgress || mState == STATE_PROCESS_IN_PROGRESS) {
mCamera.addCallbackBuffer(data);
return;
}
if (mState == STATE_PROCESS) {
mProcessInProgress = true;
processDataTask = new ProcessDataTask();
processDataTask.execute(data);
}
}
public void startProcessing() {
mState = STATE_PROCESS;
}
And my AsyncTask is something like this
private class ProcessDataTask
extends
AsyncTask<byte[], Void, Boolean> {
#Override
protected Boolean doInBackground(byte[]... datas) {
mState = STATE_PROCESS_IN_PROGRESS;
Log.i(TAG, "background process started");
byte[] data = datas[0];
long t1 = java.lang.System.currentTimeMillis();
// process your data
long t2 = java.lang.System.currentTimeMillis();
Log.i(TAG, "processing time = " + String.valueOf(t2 - t1));
mCamera.addCallbackBuffer(data);
mProcessInProgress = false;
return true;
}
#Override
protected void onPostExecute(Boolean result) {
mState = STATE_PROCESS_WAIT;
}
}
onPreviewFrame() will always get called as long as the camera preview is running. You need to take the data and process it only when you trigger something. So simply change the state of a variable, in this case, mState, and based on the state, call your AsyncTask.
Related
I have an app in which when a user's post gets liked, I want the user to get a notification.
I can use the ChildValueEventListener but that is too fast.
I don't want the user to get bombarded with notifications every time a 'like' happens. Because if another user constantly keeps 'liking' and 'unliking' a post, the post author user will be bombarded with notifications.
My plan is to run the SingleValueEventListener inside a Runnable/Handler and check for notifications every 20 seconds. Something like this below:
Handler handler = new Handler();
int delay = 20000; // 20 seconds
handler.postDelayed(new Runnable(){
public void run(){
databaseRef.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if (dataSnapshot.hasChild("USER_NOTIFICATION") {
// new notification exists - alert user
}
handler.postDelayed(this, delay);
}
}, delay);
I have two questions. 1) Is it okay to do this? I mean, is it expensive fetch for data every x seconds? 2) Is it okay to run that piece of code inside a Service so that user can still get notifications even when the app is closed or killed?
You're in one go negating the biggest advantage of the Firebase Database (its realtime updates), and reintroducing a big disadvantage it solves (each time you will now download all data, instead of only getting incremental updating).
You're likely better off instead throttling the number of changes you surface to your users in the client-side code. So use a regular ChildValueEventListener and simply throttle the updates on the client.
E.g.
public void onChildAdded(DataSnapshot snapshot, String previousChildKey) {
if (System.currentTimeMillis() - lastShownTimestamp > 20000) {
// TODO: show latest data on screen
lastShownTimestamp = System.currentTimeMillis();
}
}
I am a newbie to android development so bear with me. I have scoured the site and implemented several suggested answers but I am still running into a problem. I want to iterate through an object array and display the contents of the array with delay to allow user interaction(The user gets to say if the object and the text displayed is what they were looking for by clicking on a yes or no button). My objects however display last first and then start zooming real fast in a seemingly endless loop. Here is the method I call to load the images:
private void displayInstructions() {
for (Emergency_Instructions instruction : instructions) {
final Emergency_Instructions instruction2 = instruction;
final Handler handler = new Handler();
handler.postDelayed(new Runnable()
{
public void run() {
displayimages(instruction2.getStep(), instruction2.getStepImage());
handler.postDelayed(this, 5000);
}
}, 5000);
}
void displayimages(String text, Bitmap image)
{
instructiontext.setText(text);
instructionbmp.setImageBitmap(image);
}
Any help will be greatly appreciated
You create multiple Handlers where you need only one. You tell each one to post a Runnable to the current thread's message queue, to be run after the same delay. That delay expires at pretty much the same time for all the tasks, so they are then executed one right after another, as fast as the queue can go. Each of those tasks also posts a message via the handler, to be run after the same delay. Once that delay expires, that will produce a second group of messages posted rapidly one right after the other, as fast as the device can go.
If you just want to schedule what is effectively a slide show, you might do it like this:
private void displayInstructions() {
final Handler handler = new Handler();
int delay = 0;
int step = 5000;
for (Emergency_Instructions instruction : instructions) {
final Emergency_Instructions instruction2 = instruction;
handler.postDelayed(new Runnable() {
public void run() {
displayimages(instruction2.getStep(), instruction2.getStepImage());
// handler.postDelayed(this, 5000);
}
}, delay);
delay += step;
}
}
Note there that each task is posted with a larger delay than the last -- this is a delay with respect to when the message it posted, not with respect to when the preceding message was displayed.
With that said, I'm doubtful that this is really what you want to do, or at least that it is all you want to do. As it stands, this approach will cause all the messages to be displayed (eventually) regardless of any user interaction. At minimum, you will probably want to provide for subsequent messages to be canceled in the event that the user accepts one, or cancels the overall operation.
I'm building a barcode scanner which, different from other implementations, does the scanning part continuously in the background rather than waiting the user to trigger the process.
Now, the most (or what I think is the most) obvious way to achieve this is to process the scanning part in another thread to make sure that the main thread won't be interrupted. So that the user won't be bothered with UI lags, stutters, and whatnot.
I'm not the brightest guy when it comes to concurrency. But I've did my homework and done some research about it which, in turn has lead me to write this:
...
mScannerExecutor = Executors.newFixedThreadPool(3);
...
Camera.PreviewCallback previewCallback = new Camera.PreviewCallback() {
public void onPreviewFrame(byte[] data, Camera camera) {
Camera.Parameters parameters = camera.getParameters();
Camera.Size size = parameters.getPreviewSize();
final Image barcode = new Image(size.width, size.height, "Y800");
barcode.setData(data);
Runnable scan = new Runnable() {
#Override
public void run() {
int result = mBarcodeScanner.scanImage(barcode);
if (result != 0) {
if(isInPreview) {
isInPreview = false;
mCamera.stopPreview();
}
SymbolSet symbolSet = mBarcodeScanner.getResults();
mListener.onBarcodeScanned(symbolSet.iterator().next());
if (enableRepeatedScanning) {
new Handler().postDelayed(restartPreview, mRescanIntervalMillis);
}
}
}
};
mScannerExecutor.execute(scan);
}
};
But the above code has been causing a lot of error in its execution. I can't even keep the app running for more than a mere couple of seconds. The error message varies from time to time, but this below was shown the most:
Fatal signal 8 (SIGFPE), code -6, fault addr 0x17b8 in tid 6410 (pool-1-thread-1)
I have a strong feeling that this design in general is heavily flawed. Thus the constant crashing.
What can I do to make this right? Did I miss something really important here?
p.s., The previewCallback defined above will be called very frequently; once every 2000ms (2 secs).
I'm trying to implement a countdown timer into a pre-existing public class and I have a few questions.
An overview: I want to have a timer within a program that counts down from 60 (seconds) once the program is initialized.
If the timer reaches zero, the program quits.
If the user meets certain parameters within the 60 second time frame, the timer resets to 60, presents a new set of parameters, and begins the countdown again. It should be able to do this an infinite number of times, until the user fails to meet parameters within 60 seconds.
There will also be some sort of (TBD) GUI representation of the timer, most likely either numerical countdown or JProgressBar.
I'm semi-new (~3 months) to programming, self-taught, and still learning lots (so be gentle) :)
My questions are:
What is the best way to implement this?
I'm assuming this needs to run in a thread?
Will the timer be easily configurable? (not important, just interesting)
Thanks for your help. If you need to see code, I can find some.
EDIT: Just for some clarification/context:
This is for a timed racing video game I'm working on to develop my skills as a programmer. The idea is that a player has 60 seconds to complete a lap. If the player completes a successful lap, the timer resets to 60 seconds and the track changes to be slightly more difficult. The game runs until the player is unable to complete a lap in 60 seconds due to the difficulty. The game records the number of laps as a high score, and asks to player if they would like to try again.
If I were you, I'd use:
an AtomicInteger variable which would keep the current countdown value;
a timer thread that would wake up every 1s and decrementAndGet() the variable, comparing the result to zero and terminating the app if the result is zero;
(possibly) a thread that would also wake up every 1s to repaint the GUI -- the best approach here depends on your GUI framework.
Finally, whenever you need to reset the count back to 60s, you just call set(newValue) from any thread.
The timer thread's run() method could be as simple as:
for (;;) {
if (counter.decrementAndGet() <= 0) {
// TODO: exit the app
}
Thread.sleep(1000);
}
I think it's much easier to get this right than trying to manage multiple Timer objects.
The best way to impliment timer in your application is using some sheduler frameworks like Quartz
You could use java.util.Timer to schedule an execution of a method and then cancel it if the requirements is met.
Like this:
timer = new Timer();
timer.schedule(new Task(), 60 * 1000);
And then make a class like this to handle the timerschedule:
class Task extends TimerTask {
public void run() {
System.exit(0);
}
}
If the requirements is met, then do this to stop it from executing:
timer.cancel();
If you need to update your GUI better to use SwingWorker http://en.wikipedia.org/wiki/SwingWorker
I would write something like this:
SwingWorker<String, Integer> timer = new SwingWorker<String, Integer>() {
Integer timer=60;
#Override
protected String doInBackground() throws Exception {
//update guiModel
//label.setText(timer.toString());
while(timer>0){
Thread.sleep(1000);
timer--;
}
return null;
}
#Override
public void done(){
System.exit(0);
}
};
JButton restart = new JButton(){
{
addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
timer.cancel(true);
timer.execute();
}
});
}
};
Inside of the onReceive(Content context, Intent intent) method of my public class MediaButtonIntentReceiver extends BroadcastReceiver I need to count the number of headset button clicks (single, double, triple), which is denoted by KeyEvent.ACTION_DOWN of the ACTION_MEDIA_BUTTON.
What I have almost works, but my current algorithm sucks and is unreliable after a few times. Basically every successive ACTION_DOWN (hit within a certain number of milliseconds to the previous ACTION_DOWN) I do numClicks++. But also I need to see when the user is done pressing, so after each event I start a CountDownTimer, and if by the time it runs out there are no new clicks, then I'm done and now know the number of clicks.
The problems I'm running into are as follows: for one, the button itself seems noisy - if I press it too fast I usually miss a click. Two, after a few trials when the app it loaded, it starts getting random and I'm assuming that there are multiple CountDownTimer threads (is that the right word?) still running which screws my stuff up.
Anyways here's the main code snippet:
//note: thisClickTime uses System.currentTimeMillis()
if (action == KeyEvent.ACTION_UP) {
if (isDown == true) {
if (numClicks == 0 && lastClickTime == 0) {
//we have a new click
numClicks++;
lastClickTime = thisClickTime; //update the click time
isDown = false;
elapsedTime = thisClickTime - lastClickTime;
} else if (thisClickTime - lastClickTime < clickDelay) { //&& thisClickTime - lastClickTime > 10
numClicks++;
lastClickTime = thisClickTime;
isDown = false;
}
final int oldNumClicks = numClicks;
final CountDownTimer checkIfDone = new CountDownTimer(clickDelay, 10) {
public void onTick(long millisUntilFinished) {
if (oldNumClicks != numClicks) {
cancel();
}
}
public void onFinish() { //code that executes when counter is done
if (oldNumClicks == numClicks) {
//if user doesn't click anymore in time clickDelay + X milliseconds, then it's done
Toast.makeText(context, "Number of clicks: " + Integer.toString(numClicks), Toast.LENGTH_SHORT).show();
//reset state variables
numClicks = 0;
lastClickTime = 0;
}
}
}.start();
} else {
//?
}
}
For reference, I've been looking around at stuff like:
http://musicqueueproject.googlecode.com/svn-history/r83/trunk/src/com/yannickstucki/android/musicqueue/old/PlayerService.java
To see if there's a good way to register number of clicks. I don't really understand their code too well though, and from what I can see they only deal with single/double clicks (I may need triple and quadruple).
EDIT - uploaded the current code I'm working with. It works pretty decently most of the time. Here's what I've noticed though: if I do my button testing too close together in time, the results start screwing up and under counting the clicks. I think this is because other CountDownTimers from previous attempts are still open, and when they finish, they reset certain state variables (numClicks = 0, for one). So am I misusing the timer? I can't think of another solution though as I need some concept of elapsed time after the last click to determine when the clicking is done.
Thanks for any help.
If your BroadcastReceiver is registered in the manifest, the BroadcastReceiver will only exist for a single call to onReceive() -- subsequent broadcasts may result in another BroadcastReceiver instance. And a manifest-registered BroadcastReceiver cannot fork threads, as the whole process may get shut down once onReceive() is over.
I am skeptical that there a clean way to get your code to be reliable, as the media button simply was not designed for your intended use pattern.