3

I'm implementing a custom camera and i use onPreviewFrame() for real-time fx. The main effect (fx1) is a runnable and seems to be ok, dropping frames when needed.
A second simpler fx (fx2) runs when fx1 is off.
When fx2 was running on the main thread was ok (it runs in 2msec) but sometimes i saw an ANR so i decided to move it to a second runnable, but now causing app to freeze.

class FX2Runnable implements Runnable {
    private byte[] data;
    FX2Runnable(byte[] _data) {
        data = _data;
    }

    public void run() {
        hview.FX2(data);

        hview.post(new Runnable() {
            public void run() {
                hview.postInvalidate();
                //.invalidate(); caused ANR!!
            }
        });
        FLAG_FX2_PROCESSING = false;
    }
}

here is how i call it

private PreviewCallback previewCallback=new PreviewCallback() {
    public void onPreviewFrame(byte[] data, Camera cam) {
        if(FX==1) {
            // FX1
            if(FLAG_FX1_PROCESSING) {
                //skip
            } else {
                FLAG_FX1_PROCESSING = true;
                FX1Thread = new Thread(new FX1Runnable());
                FX1Thread.start();
            }
        } else {
            // FX2
            if(FLAG_FX2_PROCESSING) {
                //skip
            } else {
                FLAG_FX2_PROCESSING = true;
                FX2Thread = new Thread(new FX2Runnable(data));
                FX2Thread.start();
            }
            /* this was the old code and was working fine
               but i needed to solve some spare ANR
            //hview.FX2(data);
            //hview.invalidate();
            */
        }
    }
}

What am i doing wrong!?

By the way, it seems i cannot freeze the app on the emulator, but only on my device.

EDIT

Tried with runOnUiThread(Runnable) instead of hview.post(Runnable), it seemed to work but i just had to wait some minutes to see freezing app again! It happens later but it happens again!

Here's a logcat

08-26 17:32:13.398: I/ActivityManager(250): Displayed it.jcsoft.abbracadabbra/.EnhancedCameraPreviewActivity: +3s576ms
08-26 17:32:13.414: W/IInputConnectionWrapper(459): showStatusIcon on inactive InputConnection
08-26 17:32:13.441: I/GPS(9149): new network location: Location[mProvider=network,mTime=1377531132668,mLatitude=44.1459721,mLongitude=12.4545174,mHasAltitude=false,mAltitude=0.0,mHasSpeed=false,mSpeed=0.0,mHasBearing=false,mBearing=0.0,mHasAccuracy=true,mAccuracy=43.887,mExtras=Bundle[mParcelledData.dataSize=212]]
08-26 17:32:15.441: D/dalvikvm(250): WAIT_FOR_CONCURRENT_GC blocked 0ms
08-26 17:32:15.867: D/dalvikvm(250): GC_EXPLICIT freed 1300K, 23% free 16030K/20615K, paused 3ms+41ms, total 428ms
08-26 17:32:37.707: D/dalvikvm(250): GC_CONCURRENT freed 1878K, 22% free 16105K/20615K, paused 4ms+110ms, total 888ms
08-26 17:32:37.855: D/dalvikvm(9149): null clazz in OP_INSTANCE_OF, single-stepping
08-26 17:32:49.375: D/dalvikvm(834): GC_CONCURRENT freed 512K, 9% free 9179K/9991K, paused 336ms+218ms, total 4454ms
08-26 17:32:49.375: D/dalvikvm(834): WAIT_FOR_CONCURRENT_GC blocked 1740ms
08-26 17:32:58.605: D/dalvikvm(250): GC_CONCURRENT freed 1934K, 22% free 16098K/20615K, paused 5ms+32ms, total 284ms
08-26 17:33:00.070: D/SizeAdaptiveLayout(335): com.android.internal.widget.SizeAdaptiveLayout@422dcb90child view android.widget.FrameLayout@422edb18 measured out of bounds at 95px clamped to 96px
08-26 17:33:00.093: D/SizeAdaptiveLayout(335): com.android.internal.widget.SizeAdaptiveLayout@4231b860child view android.widget.FrameLayout@4231d180 measured out of bounds at 95px clamped to 96px
08-26 17:33:10.257: D/dalvikvm(9149): GC_CONCURRENT freed 455K, 4% free 14709K/15303K, paused 3ms+4ms, total 78ms
08-26 17:33:20.082: D/dalvikvm(250): GC_CONCURRENT freed 1933K, 22% free 16091K/20615K, paused 5ms+30ms, total 282ms
08-26 17:33:23.379: I/InputDispatcher(250): Application is not responding: Window{425f23b0 it.jcsoft.abbracadabbra/it.jcsoft.abbracadabbra.EnhancedCameraPreviewActivity paused=false}.  It has been 5002.6ms since event, 5002.5ms since wait started.  Reason: Waiting because the touched window has not finished processing the input events that were previously delivered to it.
08-26 17:33:23.379: I/WindowManager(250): Input event dispatching timed out sending to it.jcsoft.abbracadabbra/it.jcsoft.abbracadabbra.EnhancedCameraPreviewActivity
08-26 17:33:28.437: I/InputDispatcher(250): Dropped event because it is stale.

please help!

j.c
  • 2,825
  • 3
  • 31
  • 45

2 Answers2

0

Instead of using hview.post..., try using runOnUiThread(new Runnable()...

In Android Documentation following words are there.

Runs the specified action on the UI thread. If the current thread is the UI thread, then the action is executed immediately. If the current thread is not the UI thread, the action is posted to the event queue of the UI thread.

So whenever you want to update your views from your Thread, you need to use runOnUiThread.

All the views are rendered on UIThread. If you don't do that, it will crash because background threads are different then UIThread.

Chintan Rathod
  • 25,864
  • 13
  • 83
  • 93
  • I was using View.Post that "Causes the Runnable to be added to the message queue. The runnable will be run on the user interface thread". What's the difference? – j.c Aug 26 '13 at 14:07
  • @j.c UI means User Interface. The screen which you are viewing, is running on UI thread. Camera is also serving us using canvas. So it is also one type of UI view. You can not modify that in background. UI thread do task like updating widgets, views, event handling etc. – Chintan Rathod Aug 26 '13 at 14:10
  • @j.c, Upvote and acceptance will be great pleasure.. This will make future Googler help to find efficient answer. :) – Chintan Rathod Aug 26 '13 at 14:15
  • Ok, i thought View.post() acts the same, posting on UI thread the "results" from my background thread, and actually i still don't understand why it didn't work, anyway thanx for your help! – j.c Aug 26 '13 at 14:17
  • sorry, cannot upvote cause i've no enough reputation, i'm a novice :( – j.c Aug 26 '13 at 14:18
  • @j.c, please visit http://stackoverflow.com/questions/10558208/android-whats-the-difference-between-activity-runonuithread-and-view-post – Chintan Rathod Aug 26 '13 at 14:22
  • Ohnooo! Freeze is back!! Tried many times, runOnUiThread() helps making freeze later (few minutes) than View.post(), but it's still freezing!! I edited and added a logcat to my answer. – j.c Aug 26 '13 at 16:16
  • 1
    @j.c you should not up vote because the answer is not correct. – dcow Oct 08 '13 at 00:22
  • view.post also runs on the UI thread (although it's posted to the view's event queue). This question does not solve it. – Joakim Engstrom Jan 09 '14 at 09:54
0

You should really use a Handler for this kind of operation.

Have the runnable post a message once it's done with it's operation and then do the hview.postInvalidate(); method call.

There are tons of guides how to do it.

Some links include: http://developer.android.com/reference/android/os/Handler.html

http://androidexample.com/Thread_With_Handlers_-_Android_Example/index.php?view=article_discription&aid=58&aaid=83

http://www.vogella.com/tutorials/AndroidBackgroundProcessing/article.html

Joakim Engstrom
  • 6,243
  • 12
  • 48
  • 67
  • thank you! Of course i cannot remember how i solved that problem, anyway i think handler is the correct way. Probably i did something like: Thread fx2=new Thread(new Runnable() { public void run() { hview.fx2(data); updateUIHandler.post(new Runnable() { public void run() {hview.invalidate();} }); } }); fx2.start(); Is this right? – j.c Jan 13 '14 at 14:52
  • From just looking at the comment code it looks quite good. Except you don't have to do a .post on the handler. – Joakim Engstrom Jan 14 '14 at 15:25
  • Then, how to use handler!? I'd use updateUIHandler to update hview in UIthread, how to do that? – j.c Jan 15 '14 at 19:58
  • A handler is a way to post message from another thread to the UI thread. So if you send handler.sendMessage("key") in the non-ui thread, then you have to create a callback with the handler that recives the message and then runs the code in the UI-thread. You don't have to post it to the view anymore (unless the view is not yet drawn). – Joakim Engstrom Jan 16 '14 at 18:33
  • Let me explain... onPreviewFrame() is called 30 times per second by the camera engine, i NEED to update the view (hview) after fx2(data) ends to display the fx2 results, that's why i used hview.post. The only thing that must be run on UIthread is hview.invalidate() to let onDraw() be called and update hview. Why should i use messages? Is there something wrong in my reasoning? – j.c Jan 18 '14 at 07:26
  • There is not something wrong with you reasoning, and it's a valid complaint From looking at your code a handler is one of the better ways to do it. Instead of letting the view post when it's ready, inside a thread, you let the thread post it to the view and the view can invalidate. A queue is created and the view will do it's stuff separated from the thread. (it probably wont update 30 times a sec, depending on phone, ofc). To get really high performance you can look at SurfaceView which is a dedicated drawing view, which is more suitable for fast updates. – Joakim Engstrom Jan 20 '14 at 10:43