Android PictureCallback needs to execute first then continue to other code - java

I have code to take a picture that works, but after it gets to PictureCallback(), it continues chugging on code-wise and I end up executing other code before I have my byte array. Is there any way to halt this? It only takes milliseconds and I don't think I would mind halting the UI thread.
private static byte[] patronImage;
.
.
.
takePatronPicture();
//I want to do something with patronImage here, but the next line
//gets executed almost immediately while getJpegCallback is still
//doing its thing.
code that does something with patronImage;
.
.
.
public void takePatronPicture(){
if (camera != null) {
try {
SurfaceView surfaceView = (SurfaceView)getView().findViewById(R.id.surfaceView1);
camera.setPreviewDisplay(surfaceView.getHolder());
camera.startPreview();
camera.takePicture(null, null, getJpegCallback);
}
catch(Exception e) {
e.printStackTrace();
}
}
}
final PictureCallback getJpegCallback = new PictureCallback() {
#Override
public void onPictureTaken(byte[] data, Camera camera) {
try {
patronImage = data;
camera.release();
camera = null;
} catch (final Exception e) {
e.printStackTrace();
}
}
};

The purpose of a callback is that it will call you later when its done. If you have additional code to run that requires the operation's data, you put it in the callback. You don't freeze your current thread waiting for it. In fact doing so may lead to deadlock if the operation posts an event to the main thread's looper.

Related

AsyncTask stops after some time

I have a CustomAsyncTask class that enables infinite barcode scanner and I execute it in CustomApplication.
Unfortunately CustomAsyncTask::doInBackground stops after some time (minute or two).
private class ScanAsync extends AsyncTask<Void, String, Void>
{
boolean blocked = false;
#Override
protected Void doInBackground(Void... params)
{
while(true)
{
if (!blocked)
{
String received = GlobalAccess.scan.scan(500);
if (received != null && !received.isEmpty())
{
blocked = true;
publishProgress(received);
}
}
else
{
try
{
Thread.sleep(500);
}
catch (InterruptedException ex)
{
ex.printStackTrace();
}
}
}
}
#Override
protected void onProgressUpdate(String... values)
{
super.onProgressUpdate(values);
//TODO: something with received value
blocked = false;
}
}
I need this background task to be always on. Is there any good solution for this? I have tried IntentService, but the result was the same - after some time it stopped working.
EDIT
I have created this Service, although it block my main thread, but it should work in background right? Also If I put a breakpoint on if(!blocked) and press F9 it works fine (scanning part), but if I remove breakpoint and let it run - after few seconds it just turns off (scanner), but if I put a breakpoint again - it works again (sic!).
public class ScanService extends Service
{
boolean blocked = false;
public ScanService()
{
}
#Nullable
#Override
public IBinder onBind(Intent intent)
{
return null;
// TODO: Return the communication channel to the service.
//throw new UnsupportedOperationException("Not yet implemented");
}
#Override
public int onStartCommand(Intent intent, int flags, int startId)
{
while(true)
{
if (!blocked)
{
String received = GlobalAccess.scan.scan(500);
if (received != null && !received.isEmpty())
{
//blocked = true;
}
}
else
{
try
{
Thread.sleep(500);
}
catch (InterruptedException ex)
{
ex.printStackTrace();
}
}
}
}
}
Use a Service instead of AsyncTask. AsyncTasks are only designed to run with shorter background tasks. Keep in mind that whatever you run in a Service will execute on the main thread, so you should use a background thread within your Service.
Can you tell why the AsyncTask or IntentService is stopping? With an IntentService, with your while(true) loop, it should run indefinitely unless the app gets shut down for some reason.
Edit -
You need to do this to prevent your loop from blocking the main thread -
#Override
public int onStartCommand(Intent intent, int flags, int startId)
{
Thread t = new Thread(new Runnable() {
#Override
public void run() {
while(true) {
// your code here
}
}
});
t.start();
}
I don't know why your Service is stopping. You need to be looking at your Logcat output. Set the filter to Error and you're crash should show up there.
Yes, there is an elegant solution for this type of thing. Use a service. In particular, the JobScheduler api is meant to handle this kind of stuff. Reason for using this is, as you stated, you have a long running task and you don't want to have to manage it dying. In addition, the JobScheduler is built to handle side effects of the OS. I assume that you want your job to run, but allow the app to perform its normal set of operations. Though, as a note, the API is smart in considering factors, such as battery levels, OS resources being used, wifi connectivity, so the jobs can be deferred.
The official documentation is here https://developer.android.com/reference/android/app/job/JobScheduler.html
An example of how to use it can be found here
https://code.tutsplus.com/tutorials/using-the-jobscheduler-api-on-android-lollipop--cms-23562

How do I stop a thread?

I am starting a new thread in my app's onCreate() method like so:
stepsLogger = new Runnable() {
while(!Thread.currentThread().isInterrupted()){
//my code
try {
Thread.currentThread().sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
loggerThread = new Thread(stepsLogger);
loggerThread.start();
While it is not interrupted, it is supposed to do its thing every 10 seconds.
I am logging some text at the start of the Runnable to see how often the code gets run. The first time I run the app it's fine, but every time i restart, the text gets logged more frequently which means that more threads are running.
I have tried to stop them in the onDestroy() method:
#Override
protected void onDestroy() {
super.onDestroy();
loggerThread.interrupt();
loggerThread = null;
}
How do I make sure that the old thread gets stopped whenever the app is restarted?
Thread.interrupt() will wake up a sleeping thread with an InterruptedException, so you're most of the way there already. I'd change your loop in the following way:
while (true) {
// some code
try {
Thread.currentThread().sleep(10000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt(); // restore the thread's interrupted flag
break;
}
}
The bit about re-interrupting the thread is subtle. You can read more about it in this post from one of the primary JVM architects: https://www.ibm.com/developerworks/library/j-jtp05236/
In case this link ever dies, the gist of it is that there can be multiple "recipients" of thread interruption. Catching the exception implicitly clears the thread's interrupted flag, so it's useful to set it again.
You could use a volatile boolean variable to determine when to stop. Something like this:
class WorkerRunnable implements Runnable {
private volatile boolean shouldKeepRunning = true;
public void terminate() {
shouldKeepRunning = false;
}
#Override
public void run() {
while (shouldKeepRunning) {
// Do your stuff
}
}
}
To start it:
WorkerRunnable runnable = new WorkerRunnable();
new Thread(runnable).start();
To stop it:
runnable.terminate();

IllegalArgumentException in unlockCanvasAndPost (android live wallpaper)

I've created my first live wallpaper implementing drawing in a separate thread. So now I have a WallpaperService and my WallpaperPainter who does the job. The problem is that I getting a IllegalArgumentException in unlockCanvasAndPost method on some of devices (Samsung Note is the one). I've read all recomendations I could find but couldn't fix that bug. Seems like the unlockCanvasAndPost is called when surface is destroyed so canvas is invalid. Here is the essential parts of code:
In wallpaper service:
#Override
public void onSurfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
super.onSurfaceChanged(holder, format, width, height);
painting.setSurfaceSize(width, height);
}
#Override
public void onSurfaceCreated(SurfaceHolder holder) {
super.onSurfaceCreated(holder);
painting.start();
}
#Override
public void onSurfaceDestroyed(SurfaceHolder holder) {
boolean retry = true;
painting.stopPainting();
while (retry) {
try {
painting.join();
retry = false;
} catch (InterruptedException e) { }
}
super.onSurfaceDestroyed(holder);
}
In the painting thread:
public void stopPainting() {
this.run = false;
synchronized(this) {
this.notify();
}
}
public void run() {
this.run = true;
Canvas c = null;
while (run) {
try {
synchronized (this) {
Thread.sleep(50);
c = this.surfaceHolder.lockCanvas();
doDraw(c);
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
if (c != null) {
this.surfaceHolder.unlockCanvasAndPost(c); // << -- HERE IS THE PROBLEM
}
}
// if pause...
synchronized (this) {
if (wait) {
try {
wait();
} catch (Exception e) { }
}
}
}
}
Can anyone give me any clue what I'm doing wrong? I'm new both for Java and Android.
If error is: UnlockAndPost Failed, it means it unlocked no buffer.
After this.surfaceHolder.unlockCanvasAndPost(c);
you can append
this.surfaceHolder.lockCanvas();
(sorry for my poor English proficiency)
When you open the preview of wallpaper, creates the object WallpaperService and further creates an instance of Engine. Then the stream starts drawing wallpaper.
Then, when you click "Set wallpaper" - a new instance of WallpaperService is not created. But he call the onCreateEngine() method, which returns another (second) instance of Engine. Which also runs its own thread.
Now you have two competing thread!!! So they lead to an exception being thrown.
All you need to do to fix the bug - is to write a correct method onCreateEngine().
replace this:
#Override
public Engine onCreateEngine() {
return new SampleEngine();
}
to this:
private SampleEngine engine;
#Override
public Engine onCreateEngine() {
if (engine!=null) {
engine.painting.stopPainting();
engine = null;
}
engine = new SampleEngine();
return engine;
}
I don't see a definitive problem but here are some thoughts.
There is a chance that you unlock a canvas that has not been locked. I would set c = null; at the top of your while loop otherwise the previous value of c would be unlocked the next time through the loop.
while (run) {
Canvas c = null;
...
Your run field should be marked as volatile because it is accessed by multiple threads.
Never call Thread.sleep(...) inside of a synchronized block. That's a very bad practice since it blocks other threads unnecessarily.
Make sure you at least log your exceptions. Be extremely careful about catch (Exception e) {}. All that does is mask your problems.
There isn't much point in doing the join() inside a while loop. If your thread gets interrupted you should interrupt the painting thread and quit.
Since you are both sleeping and waiting, it would make more sense to remove the sleep and do something like:
try {
synchronized (this) {
if (wait) {
wait();
else {
wait(50);
}
}
} catch (Exception e) {
e.printStackTrace();
}
I had the same problem with my live wallpaper. On a Nexus 5 emulator it runs fine, but when I run it on a Nexus 10 emulator it crashes the moment the app loads.
I found out that the problem was because the default Skin for the emulator has the wrong resolution. After I changed the Skin to "No Skin" then I don't get the crash anymore.
For more information on how to fix the Skin with wrong resolution, please see:
Android Studio - Tablet emulator not showing correct resolution

Setting up the correct multi threading

Unfortunately I have a pretty bad understanding of how to properly set up threading. I know there is a bunch of info on this both here on SO.SE and on other sites but I can't seem to relate what I read correctly to what I'm doing.
My problem is that I have a method that takes two parameters where one is divided by the other. The quotient (result) is used to fill up a visual progress bar. When the quotient gets to 1, (readBytes/contentLength == 1), I want some thread (I guess) to wait for a given time before the progress bar is removed from the layout. I know all the code needed to set the value to the progress bar and how to remove it from the view, my question is how do I make it wait for, say, 2000 ms before the action is triggered to remove the component?
This is probably basic threading knowledge but I'm having huge problems with it.
So far I've tried these two approaches:
#Override
public void updateProgress(long readBytes, long contentLength) {
this.contentLength = contentLength;
if(readBytes != 0 && contentLength != 0 && fileListItem != null) {
fileListItem.getProgressIndicator().setValue(readBytes/contentLength);
synchronized (this) {
while(readBytes/contentLength != 1) {
try {
wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
};
fileListItem.removeProgressIndicator();
}
}
}
if(!itemIsAdded) {
checkFileCompatibility(contentLength);
}
}
AND
#Override
public void updateProgress(long readBytes, long contentLength) {
this.contentLength = contentLength;
if(readBytes != 0 && contentLength != 0 && fileListItem != null) {
if(readBytes/contentLength == 1) {
Thread t = new Thread();
t.start();
try {
t.wait(2000);
fileListItem.removeProgressIndicator();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
t.interrupt();
} else {
fileListItem.getProgressIndicator().setValue(readBytes/contentLength);
}
}
if(!itemIsAdded) {
checkFileCompatibility(contentLength);
}
}
With no success. In the first example the main thread seems to be the one waiting and nothing happens. And in the second example I get an exception on the t.wait(2000);. I'm at a loss of how I should do..
EDIT: With the input from Bohemian I got it working.
#Override
public void updateProgress(final long readBytes, final long contentLength) {
this.contentLength = contentLength;
if(readBytes != 0 && contentLength != 0 && fileListItem != null) {
if(!threadIsRunning) {
new Thread(new Runnable() {
#Override
public void run() {
threadIsRunning = true;
while(!fileIsAdded) {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
LOGGER.error(e.getMessage());
break;
}
}
fileListItem.removeProgressIndicator();
threadIsRunning = false;
}
}).start();
}
fileListItem.getProgressIndicator().setValue(readBytes/contentLength);
if(readBytes == contentLength)
fileIsAdded = true;
}
if(!itemIsAdded) {
checkFileCompatibility(contentLength);
}
}
It still needs some tidying up but the basics are now working!
In all probability SwingWorker is the right tool for your task. There is a full code sample in the Javadoc. Notice the method setProgress -- that's ideal to update your progress bar.
If all you need is really just a fixed 2 second delay for clearing the progress bar, then you want to use a Swing Timer. It doesn't even involve multithreading, you just write a callback handler that will be executed after the specified delay.
I wouldn't have the main thread wait. It's bad practice because it isn't scalable and makes your GUI jittery.
Instead, I would pass a timeout value and a couple of callbacks to the worker thread to execute when it exceeds its timeout/completes its work. That way the main thread is free to go back to doing whatever it wants to.
Just for illustration purposes, your "completion" callback might look like:
new Runnable() {
public void run() {
// code that hides the progress bar
}
}
Your "timeout" callback might look like:
new Runnable() {
public void run() {
// code that displays an error message
}
}
By the way, to get a thread to do something, you also pass it a Runnable:
new Thread(new Runnable() {
public void run() {
// code that runs when your thread starts
}
}).start();
I think what you really need is
Thread.sleep(2000);
instead of wait. While wait can be used for sleeping, its primary function is for inter-thread signaling and requires a lock on the object being waited on, which you have not acquired, hence the exception.
Edit: Upon further inspection I notice that you are not doing things correctly. You are just creating a thread with no associated run method:
Thread t = new Thread();
t.start();
Hence your thread is not executing anything.
I suggest reading a Java threading tutorial on how to set up threads correctly: http://docs.oracle.com/javase/tutorial/essential/concurrency/runthread.html

Proper multitasking for android

Hi im developing an android application and im wondering how i make the app use less CPU while backgrounded. For example, my application pauses once it loses focus but the cpu usage is still 50%
Edit
while (!pause) {
Canvas c = null;
try {
c = sHolder.lockCanvas(null);
synchronized (sHolder) {
doDraw(c);
powerUps();
}
} finally {
if (c != null) {
sHolder.unlockCanvasAndPost(c);
}
}
}
Then when you pause and resume it just changes the pause variable
IMO, you should not be looping at all while your app is paused.
See this page for more details about the "proper" lifecycle of an android app.
Also note that with any busy loop design your app will be using 100% of the CPU - I'm not sure if starting a loop from the onResume() method is correct; my instinct is to have each iteration of your loop performed by a separate call initiated by a call to Handler.post(), with the last statement re-posting the next call. Otherwise, the application's main thread will be starved, right?
Maybe something like this:
void iterate() {
Canvas c = null;
try {
c = sHolder.lockCanvas(null);
synchronized (sHolder) {
doDraw(c);
powerUps();
}
} finally {
if (c != null) {
sHolder.unlockCanvasAndPost(c);
}
}
this.handler.post(this.iterateRunnable);
}
void onResume() {
this.handler = new Handler();
this.iterateRunnable = new Runnable() {
#Override public void run() { iterate(); }
};
this.handler.post(this.iterateRunnable);
}

Categories