1

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:

  1. 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)
  2. Should I use an alarm to wake the device up or are there any alternative solutions?
  3. How can both (alarms and thread/task) work together? (Include the Alarm in the Task/Thread?)

Many thanks for your help in advance.

little_planet
  • 1,005
  • 1
  • 16
  • 35

2 Answers2

0

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.

Community
  • 1
  • 1
Benyam Ephrem
  • 448
  • 6
  • 20
0

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.

Froyo
  • 17,947
  • 8
  • 45
  • 73
  • interesting solution. i never thought about using Camera.PreviewCallback. I will look into this. Thank you very much for your suggestion. – little_planet May 15 '15 at 15:37