Search code examples
androidlayoutcolorssetbackgroundjavaosc

Why setBackgroundColor on a layout sometimes crash my app


I'm building an application that can send and received OSC. I'm using JavaOSC, it feets perfectly my needs.

I'm sending color value in OSC message, and receiving them also.

I send the color from a colorpicker based on this color picker http://code.google.com/p/color-picker-view/ it works great.

My problem is :

  • When I choose the color in the color picker i'm setting the background of the layout (where the color picker is) view with :

private ColorPickerView.OnColorChangedListener colorListener = new ColorPickerView.OnColorChangedListener(){

    @Override
    public void onColorChanged(int color) {
        caller.sending("color", color);
        mScreen.setBackgroundColor(color);
    }
};

where mScreen is a LinearLyout

mScreen = (LinearLayout) findViewById(R.id.myScreen);

It works as expected.

  • When I'm receiving an OSC message with color I'd like to change the background too, but it crashes.

My listener is

OSCListener listener = new OSCListener() {

        public void acceptMessage(java.util.Date time, OSCMessage message) {
            //en cas de message vide
            if (message.getArguments().length == 0) return;
            //sinon on recupere les elements et on les tries
            Object[] args = message.getArguments();
            if (args[0].toString().contains("alpha")) Log.i("receiver osc", "Message received!");

            //Instructions
            if (args[0].toString().contains("color")) {
                int color = (Integer)args[1];                   
                //mColorPickerView.setColor((Integer)args[1]);
                mScreen.setBackgroundColor(color);
            }
            else return;
        }

You can find the crash report below. Do the function setBackgroundColor need to be in a particular function to work properly (in a onClick function for example) or when it redraws something on the screen ?

Crash report

08-05 15:18:15.035: WARN/dalvikvm(18083): threadid=7: thread exiting with uncaught exception (group=0x4001d7d0) ERROR/AndroidRuntime(18083): FATAL EXCEPTION: Thread-8 ERROR/AndroidRuntime(18083): android.view.ViewRoot$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views. ERROR/AndroidRuntime(18083): at android.view.ViewRoot.checkThread(ViewRoot.java:2811) ERROR/AndroidRuntime(18083): at android.view.ViewRoot.requestLayout(ViewRoot.java:594) ERROR/AndroidRuntime(18083): at android.view.View.requestLayout(View.java:8180) ERROR/AndroidRuntime(18083): at android.view.View.requestLayout(View.java:8180) ERROR/AndroidRuntime(18083): at android.view.View.requestLayout(View.java:8180) ERROR/AndroidRuntime(18083): at android.view.View.setBackgroundDrawable(View.java:7535) ERROR/AndroidRuntime(18083): at android.view.View.setBackgroundColor(View.java:7429) ERROR/AndroidRuntime(18083): at com.taprik.Remote.RemoteMain$4.acceptMessage(RemoteMain.java:202) ERROR/AndroidRuntime(18083): at com.illposed.osc.utility.OSCPacketDispatcher.dispatchMessage(Unknown Source) ERROR/AndroidRuntime(18083): at com.illposed.osc.utility.OSCPacketDispatcher.dispatchPacket(Unknown Source) ERROR/AndroidRuntime(18083): at com.illposed.osc.utility.OSCPacketDispatcher.dispatchBundle(Unknown Source) ERROR/AndroidRuntime(18083): at com.illposed.osc.utility.OSCPacketDispatcher.dispatchPacket(Unknown Source) ERROR/AndroidRuntime(18083): at com.illposed.osc.OSCPortIn.run(Unknown Source) ERROR/AndroidRuntime(18083): at java.lang.Thread.run(Thread.java:1096) WARN/ActivityManager(6722): Force finishing activity com.taprik.Remote/.RemoteMain


Solution

  • android.view.ViewRoot$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.

    You can only alter UI elements on the UI thread: Note: Anything performed on the UI thread will block other UI actions. Ergo, if you're cycling through some long list on the UI thread, the user cannot interact with the UI while it's happening.

    MyActivity.this.runOnUiThread(new Runnable() {
        public void run() {
            mScreen.setBackgroundColor(color);
        }
    });
    

    Or:

    private Handler mHandler;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        /* ... */
    
        // Create the handler
        mHandler = new Handler();
    }
    
    private void changeBgColor(final int color) {
        mHandler.post(new Runnable() {
            public void run() {
                mScreen.setBackgroundColor(color);
            }
        }
    }