2

This is the comple java class (GFXSurface). Inside this class, a second class is defined,

public class GFXSurface extends Activity implements OnTouchListener {

    AnotherSurface ourSurfaceView;
    float x, y;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // TODO Auto-generated method stub
        super.onCreate(savedInstanceState);
        ourSurfaceView = new AnotherSurface(this);
        ourSurfaceView.setOnTouchListener(this);
        x = 0;
        y = 0;
        setContentView(ourSurfaceView);
    }
    @Override
    protected void onPause() {
        // TODO Auto-generated method stub
        super.onPause();
        ourSurfaceView.ourPause();
    }
    @Override
    protected void onResume() {
        // TODO Auto-generated method stub
        super.onResume();
        ourSurfaceView.ourResume();
    }
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        // TODO Auto-generated method stub
        x = event.getX();
        y = event.getY();
        return true;  
    }

    /*------------------------Class within a class-------------------------------*/

    public class AnotherSurface extends SurfaceView implements Runnable {

        SurfaceHolder ourHolder;
        Thread ourThread = null;
        boolean isRunning;

        public AnotherSurface(Context context) {
            // TODO Auto-generated constructor stub
            super(context); //not auto-generated; set it up manually
            isRunning = false;
            ourHolder = getHolder();    
        }

        public void ourPause(){
            isRunning = false;
            while(true){
                try {
                    ourThread.join();
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                break;
            }
            ourThread = null;
        }

        public void ourResume(){
            isRunning = true;
            ourThread = new Thread(this);
            ourThread.start();
        }

        @Override
        public void run() {
            // TODO Auto-generated method stub
            while(true){
                if(!ourHolder.getSurface().isValid())
                    continue;

                Canvas canvas = ourHolder.lockCanvas();
                canvas.drawRGB(255, 0, 0);
                if(x!=0 && y!=0){
                    Bitmap ourBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.green_ball);
                    canvas.drawBitmap(ourBitmap, x-(ourBitmap.getWidth()/2), y-(ourBitmap.getHeight()/2), null);
                }
                ourHolder.unlockCanvasAndPost(canvas);
            }
        }
    }
}

Now, when I start the activity, it works as is required, it creates a bitmap at the place where the screen is clicked (centered at the point of click). The problem it gives is that, when I press the back key on my phone, the app stops responding and the phone gives an option to force shut the app. I think the it has got to do something with the "ourThread" thread not being joined properly.

Any idea where the problem lies? Thanks.


EDIT: I have actually found where I was going wrong. In the while loop:
while(true){
        if(!ourHolder.getSurface().isValid())
            continue;

        Canvas canvas = ourHolder.lockCanvas();
        canvas.drawRGB(255, 0, 0);
        if(x!=0 && y!=0){
            Bitmap ourBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.green_ball);
            canvas.drawBitmap(ourBitmap, x-(ourBitmap.getWidth()/2), y-(ourBitmap.getHeight()/2), null);
        }

I just changed "true" to "isRunning". And now the thread does end, and thus, the activity closes on pressing the back button. Thanks all for your valuable suggestions.

Born Again
  • 2,139
  • 4
  • 25
  • 27

1 Answers1

2

The problem is that, "ourThread" never stops when it is joined.

You have to realize that calling ourThread.join() only waits for the thread to finish -- it won't stop the thread. Your ourThread may be hung for some reason. A thread dump will show where it is running. Maybe it is stuck in a loop? Maybe it is waiting on a network connection?

If the join() returns successfully, by definition, the thread was was joined is no longer running. So the thread calling ourThread.join() will wait until the ourThread thread has completed.

If the thread is no longer running then maybe there are other threads running keeping your application open? A thread dump will show you what other non-daemon threads are still around. They will need to terminate before your application will stop.

In looking at your thread code, I don't see any way for you to exit the infinite loop unless a RuntimeException is thrown. When does the thread stop working? Did you mean to do a break; instead of a continue;?

while(true){
    if(!ourHolder.getSurface().isValid())
        continue; // should this be a break?
    Canvas canvas = ourHolder.lockCanvas();
    canvas.drawRGB(255, 0, 0);
    ourHolder.unlockCanvasAndPost(canvas);
}

Now that you've added more code, you need to make isRunning be volatile so that multiple threads can update it and see the updates and you should change the while loop in your run() method to be:

private volatile boolean isRunning;
...
while(!isRunning){
Community
  • 1
  • 1
Gray
  • 115,027
  • 24
  • 293
  • 354
  • 2
    join is not returning -- this is why he/she is seeing the ANR – Joseph Earl Jun 14 '13 at 16:05
  • "join is not returning"? I don't get it. What does it mean? – Born Again Jun 14 '13 at 16:09
  • @BornAgain it means you call join and that is where your program stays. The other thread never joins because it is in an endless loop. – Joseph Earl Jun 14 '13 at 16:10
  • `join()` only _waits_ for `ourThread` to finish. It doesn't stop the thread @BornAgain. The `ourThread` is still running so the caller is waiting in the `join()` method. – Gray Jun 14 '13 at 16:11
  • @Gray I have updated my question. Can you please narrow down the problem now? Thanks! – Born Again Jun 14 '13 at 16:26
  • @BornAgain We have narrowed down the problem to the infinite loop. Get rid of it. – Sotirios Delimanolis Jun 14 '13 at 16:33
  • @SotiriosDelimanolis I just did what you said. But it still is giving the same error. – Born Again Jun 14 '13 at 16:38
  • 1
    To put it more explicitly, change "while (true)" in the run method to "while (isRunning)" – user1676075 Jun 14 '13 at 19:27
  • +1 user1676075 although it needs to be `while(!isRunning)` and you need to make `isRunning` be `volatile @BornAgain. – Gray Jun 14 '13 at 19:37
  • @Gray Instead of "!isRunning", "isRunning" closes the activity. It does take me back to the previous activity. But then I get the error "Unfortunately, the app has stopped". PS: Sorry for the late reply, I was away for some time. – Born Again Jun 19 '13 at 11:25
  • @Gray I have made an edit to my question. Can you please help me with it. Thanks. – Born Again Jun 19 '13 at 19:21
  • Dude you can't change the question like that because it completely invalidates my answer and my work @BornAgain. Ask another question instead. – Gray Jun 19 '13 at 19:24
  • @Gray Okay. Sorry about that. Actually I have solved my problem. I have edited my question for that. Thanks for your help! – Born Again Jun 19 '13 at 20:01