ntgCleaner
ntgCleaner

Reputation: 5985

Android Fatal Exception Threads Hierarchy (please explain)

I've run into an error about thread hierarchy. I know where the issue is, but I don't understand threads enough to understand why this is happening to me.

I have this as my basic code:

public class CameraPage extends Activity implements ImageSaver.OnImageSavedListener {
    public int numPics = 0;
    public Timer gifTimer;

    protected void onCreate(Bundle savedInstanceState) {
        gif_button.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                countdownTimer = new CountDownTimer((seconds * 1000 + 500), 1000) {
                public void onTick(long millisUntilFinished) {
                    // Do things
                }
                public void onFinish() {
                    numPics = 0;
                    gifTimer = new Timer();
                    gifTimer.scheduleAtFixedRate(new TimerTask(){
                        @Override
                        public void run(){
                            numPics++;
                            if(numPics <= 5) {
                                Log.d("********", "Take a picture " + numPics);
                            } else {
                                gifTimer.cancel();
                                Log.d("********", "No More Pictures " + numPics);
                                setCameraSpace();
                            }
                        }
                    },0,500);
                }
            }.start();
         }  
    });

Then the method for setCameraSpace() is here. None of what it does is important to the answer, except changing the visibility of any View.

public void setCameraSpace(){
    Log.d("***********", "Finish " + bitmapArray);

    if (icon_alert_int == 1) {
        icon_alert.setVisibility(View.VISIBLE);
    } else {
        icon_alert.setVisibility(View.GONE);
    }
    if(gallery){
        gallery_button.setVisibility(View.VISIBLE);
    } else {
        gallery_button.setVisibility(View.GONE);
    }
    camera_preview_container.setVisibility(View.GONE);
    countdown_timer.setVisibility(View.GONE);
    picture_button.setVisibility(View.VISIBLE);
    back_button.setVisibility(View.VISIBLE);
    front_flash.setVisibility(View.GONE);
    front_flash.setAlpha(0f);
    countdown_timer.setText("");
    camera_text.setText(pref_session_start_inp);

    if (pref_session_auto_live_view) {
        //Countdown until Live view reappears
        live_view_timer = new CountDownTimer((pref_session_auto_live_view_inp * 1000 + 50), 1000) {
            public void onTick(long millisUntilFinished) {
                auto_live_view_text.setText("" + ((millisUntilFinished / 1000) - 1));
            }

            public void onFinish() {
                latest_picture_container.setVisibility(View.GONE);
                camera_preview_container.setVisibility(View.VISIBLE);
                auto_live_view_text.setText(String.valueOf(pref_session_auto_live_view_inp));
                camera_text.setText(pref_session_start_inp);
            }
        }.start();
    }
}

so, I'm unsure about threads and when one is started/ended and how to put things in different places. I assume the UI elements in the setCameraSpace() are not in a different, data-type thread because it's in a run() ?

Anyways, I'm getting this error:

FATAL EXCEPTION: Timer-0
Process: com.cleanercoding.cleanerphotobooth, PID: 14355
android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
at android.view.ViewRootImpl.checkThread(ViewRootImpl.java:7647)
at android.view.ViewRootImpl.invalidateChildInParent(ViewRootImpl.java:1107)
at android.view.ViewGroup.invalidateChild(ViewGroup.java:5029)
at android.view.View.invalidateInternal(View.java:12953)
at android.view.View.invalidate(View.java:12917)
at android.view.View.setFlags(View.java:10850)
at android.view.View.setVisibility(View.java:7233)
at android.widget.ImageView.setVisibility(ImageView.java:1420)
at com.cleanercoding.cleanerphotobooth.CameraPage.setCameraSpace(CameraPage.java:1263)
at com.cleanercoding.cleanerphotobooth.CameraPage$6$2$1.run(CameraPage.java:552)
at java.util.Timer$TimerImpl.run(Timer.java:284)

Upvotes: 0

Views: 69

Answers (1)

Kiskae
Kiskae

Reputation: 25573

Looking at the documentation of Timer (http://developer.android.com/reference/java/util/Timer.html) it appears that the Timer object has its own thread in which it executes tasks sequentially. This means that the UI is accessed from the thread owned by the Timer, not the thread owned by the UI.

See http://developer.android.com/training/multiple-threads/communicate-ui.html for information on how to communicate with the UI when using threads.

Upvotes: 1

Related Questions