Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Issue with the android camera and thread safety

As pointed out in the Android documentation on handling the camera, it is recommended to use a separate thread to open the camera.

Well, I am doing just that but do have some difficulties:

For my camera object I am using a global instance variable. Now, when I start my app, I create a separate thread in onResume() and do all initializations for that camera object in that thread.

Later when I leave the app, I release the camera in onPause(). This works all just fine.

But the problem is: When I did some stress tests and switched really fast between onResume() and onPause() (by hitting the multitask button excessively fast) my app crashed. The reason was that there was a Method called after release().

This makes sense since it is possible that the camera may be released in onPause() but at the same time the thread hasn't finished with its initialization. Thus, the thread tries to make a call on a camera object that was already released.

Now, what can I do to fix this? Maybe not use a global camera object? Or how can I make this thread safe?

like image 349
user2426316 Avatar asked Mar 08 '14 16:03

user2426316


People also ask

What is thread-safe Android?

By design, Android View objects are not thread-safe. An app is expected to create, use, and destroy UI objects, all on the main thread. If you try to modify or even reference a UI object in a thread other than the main thread, the result can be exceptions, silent failures, crashes, and other undefined misbehavior.

What is the thread in Android?

When an application is launched in Android, it creates the first thread of execution, known as the “main” thread. The main thread is responsible for dispatching events to the appropriate user interface widgets as well as communicating with components from the Android UI toolkit.

Is it possible to increase the number of threads in Android?

Technically there is no limit, but at some point having more threads is going to be less efficient than having less. If you want to see a pretty much optimal implementation of a ThreadPool look at the source code of the AsyncTask .

Which thread is responsible for updating the screen in an Android app?

The thread, sometimes called the UI thread, is responsible for updating the screen in an Android app.


2 Answers

You have a couple of options.

Option #1: only touch the Camera from the UI thread.

This is pretty straightforward, since you can manage the camera in onPause() and onResume(). If you want to do work with the Camera object from another thread, you can just use runOnUiThread(). The problem with this approach is that you don't want to do significant amounts of work on the UI thread, so you have to send the preview data elsewhere.

This approach was used in the "Show + capture camera" activity in Grafika. There's a long-winded comment about the thread management here. Note that the camera preview gets handled by the GL rendering thread.

Option #2: only touch the Camera from a dedicated camera thread.

For this to work, you need to send messages to the thread every time you want it to do something with the Camera. This is most easily done with the usual Handler and Looper arrangement. The trick is that, when you send a message, the call returns immediately. If you send a message to tell the thread to shut the camera down from onPause(), the actual camera shutdown may not happen for a while -- and in the mean time, the activity is shutting other things down, and (if events are happening quickly) might be back in onResume() before the shutdown has completed. (I suspect this is what's happening to you.)

For startup and shutdown, you need to wait for completion. You can see an example of this in a different (non-Camera) Grafika activity, where it waits for the render thread to finish initializing before sending it messages. The shutdown is synchronized by join()ing the thread as it stops.

The key thing to remember is that you can only call Camera methods from a single thread -- whatever thread you use to open the camera is the only thread that gets to touch that instance. After that, it's a "simple" matter of concurrency management. (Strictly speaking, the doc says "this class's methods must never be called from multiple threads at once", so you can use multiple threads if you serialize the access carefully. The easiest way to serialize access is to only do the calls from one thread.)

like image 112
fadden Avatar answered Sep 23 '22 00:09

fadden


You can use a boolean flag for camera thread to indicate that the camera is no longer necessary (for example in the case of pause).

so your code is going to be something like this:

    private boolean isNeeded;
    private boolean isInitialized;

    @Override
    protected void onResume(){
        super.onResume();
        Thread thread = new Thread(){
            @Override
            public void run(){
                // getCamera();
                // initializeCamera();
                if (isNeeded){
                    inInitialized = true;
                    // do stuff with Camera


                } else {
                    //release camera here
                }
            }

        }
        thread.start();
    }

    protected void onPause(){
        super.onPause();
        isNeeded = false;
        if (isInitialized){
            //release camera here
        }
    }

so your initializing thread checks if the camera isn't needed and release it if so, or initialize the camera successfully and you release the camera from the onPause.

like image 32
Mr.Me Avatar answered Sep 27 '22 00:09

Mr.Me