0

What I am trying to do is to have my program wait 3 seconds before changing the images. I did my research, and it seems like this could fix it, but it is telling me that I need to make c1 and c2 final. However, that will ruin the rest of my code.

I am trying to run these two lines after 3 seconds:

c1.getImg().setImageResource(R.drawable.facedown);
c2.getImg().setImageResource(R.drawable.facedown);

What is a solution to this? Thanks!

private Thread thread;

public void checkMatch(int num) {
    flips++;
    President c1 = null;
    President c2 = cards.get(num - 1);
    if (flips % 2 != 0) {
        return;
    } else {
        for (President c : cards) {
            if (c.isFlipped() == true && c.isMatched() == false && c != c2) {
                c1 = c;
            }
        }

        if (c1.getPresident() == c2.getPresident()) {
            cards.get(c1.getCard() - 1).setMatched(true);
            cards.get(c2.getCard() - 1).setMatched(true);
        } else {

            cards.get(c1.getCard() - 1).setFlipped(false);
            cards.get(c2.getCard() - 1).setFlipped(false);

             thread = new Thread() {
             @Override
             public void run() {
             try {
             synchronized (this) {
             wait(3000);
             }
             } catch (InterruptedException ex) {
             }

             // TODO
//THESE TWO LINES ARE THE ONES I WANT TO RUN AFTER 3 SECONDS
                    c1.getImg().setImageResource(R.drawable.facedown);
                    c2.getImg().setImageResource(R.drawable.facedown);
             }
             };

             thread.start();
        }
    }
}

 @Override
 public boolean onTouchEvent(MotionEvent evt) {
 if (evt.getAction() == MotionEvent.ACTION_DOWN) {
 synchronized (thread) {
 thread.notifyAll();
 }
 }
 return true;
 }

09-07 17:04:19.937: E/AndroidRuntime(6822): FATAL EXCEPTION: Thread-4693
09-07 17:04:19.937: E/AndroidRuntime(6822): android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
09-07 17:04:19.937: E/AndroidRuntime(6822):     at android.view.ViewRootImpl.checkThread(ViewRootImpl.java:4746)
09-07 17:04:19.937: E/AndroidRuntime(6822):     at android.view.ViewRootImpl.requestLayout(ViewRootImpl.java:823)
09-07 17:04:19.937: E/AndroidRuntime(6822):     at android.view.View.requestLayout(View.java:15473)
09-07 17:04:19.937: E/AndroidRuntime(6822):     at android.view.View.requestLayout(View.java:15473)
09-07 17:04:19.937: E/AndroidRuntime(6822):     at android.view.View.requestLayout(View.java:15473)
09-07 17:04:19.937: E/AndroidRuntime(6822):     at android.view.View.requestLayout(View.java:15473)
09-07 17:04:19.937: E/AndroidRuntime(6822):     at android.widget.RelativeLayout.requestLayout(RelativeLayout.java:318)
09-07 17:04:19.937: E/AndroidRuntime(6822):     at android.view.View.requestLayout(View.java:15473)
09-07 17:04:19.937: E/AndroidRuntime(6822):     at android.widget.ImageView.setImageResource(ImageView.java:352)
Evorlor
  • 7,263
  • 17
  • 70
  • 141

1 Answers1

1

Declare c1 and c2 as global variables.

private Thread thread;

President c1, c2;

public void checkMatch(int num) {
    flips++;
    c1 = null;
    c2 = cards.get(num - 1);
    ....
    ....
}

Edit:

You are attempting to change the UI from a non-UI thread. Instead of the following:

thread = new Thread() {
         @Override
         public void run() {
             try {
                 synchronized (this) {
                     wait(3000);
                 }
             } catch (InterruptedException ex) {
         }

         // TODO
         //THESE TWO LINES ARE THE ONES I WANT TO RUN AFTER 3 SECONDS
                c1.getImg().setImageResource(R.drawable.facedown);
                c2.getImg().setImageResource(R.drawable.facedown);
         }
         };

         thread.start();

Use a Handler:

new Handler().postDelayed(new Runnable() {

    @Override
    public void run() {
        c1.getImg().setImageResource(R.drawable.facedown);
        c2.getImg().setImageResource(R.drawable.facedown);
    }
}, 3000L);
Vikram
  • 51,313
  • 11
  • 93
  • 122
  • hmmm...that works but then it crashes at the end of 3 seconds instead of changing the images – Evorlor Sep 07 '13 at 21:03
  • @Evorlor Can you post the logcat output? – Vikram Sep 07 '13 at 21:04
  • 1
    @Evorlor You are attempting to change UI from a non-UI thread. Wait, I'll edit my answer. – Vikram Sep 07 '13 at 21:06
  • you are amazing! so just so i learn from this...handler is for interface, and thread is for code? also, what does the L at the end of 3000 do? – Evorlor Sep 07 '13 at 21:11
  • @Evorlor Handlers are associated with a single thread. In this case, we invoked `Handler.postDelayed()` from the UI thread. That's why you don't get an exception anymore. So, if the Handler had been created from a non-UI thread, updating UI from it would **not** have worked. You could have updated UI from your original thread by calling `runOnUiThread(Runnable)` as well. I rarely use `Threads` in my code. To execute code on a non-UI thread, I use `AsyncTasks`. The `L` signifies that `3000` (delay in milliseconds) is of type `long`. Not using `L` works fine too. Lowercase `l` works fine too. – Vikram Sep 07 '13 at 21:23
  • Instead of manipulating global variables, you may want to use a simple callback method on a weakly referenced local listener inside the handler. That way you can avoid problems caused by standard life cycle methods that would unexpectedly destroy your views. – Collin Flynn Sep 07 '13 at 21:29
  • @CollinFlynn Yea, good point. Would keeping a reference to `handler` and calling `handler.removeCallbacksAndMessages(null)` in `onStop()` be an alternative to your suggestion? – Vikram Sep 07 '13 at 21:42
  • @user2558882 Yep, that would be an alternative - I'd even consider placing the remove callbacks in onPause(). – Collin Flynn Sep 08 '13 at 03:45