Home Tutorials Hands on The Android Message Queue - Lets get quacking
The Android Message Queue - Lets get quacking
Monday, 03 November 2008 00:00
Article Index
The Android Message Queue
Lets get quacking
All Pages

The interesting stuff is in the handler definition within the CustomView inner class. When a message arrives instructing it to recalculate the babies positions, it walks through their position list and tests each one to see is it is already in position. If they all are, no further messages are sent. If even just one isn't, the message is sent to update again when all the babies have been processed.

One word of caution - this example is purely to show the message queueing system and is not the way you'd normally write an app to solve this particular ducks-in-a-row problem - that would be just quackers ;-)

/*
 * Copyright (c) 2009 OTAMate Technology Ltd. All Rights Reserved.
 * http://www.androidacademy.com
 */

package com.androidacademy.tutorials.messagequeue;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.Region;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.MotionEvent;
import android.view.View;

/**
 * This shows how to update the UI in response to messages.
 * A duck pond is drawn, and on a finger press event momma duck is placed
 * along with a few smaller randomly positioned baby ducks. The baby ducks
 * will always try to line up behind momma duck. If they are not in position,
 * they know of it because momma duck sends them all a message each time
 * she moves. Every movement from a baby duck is therefore in response
 * to a message.
 */
public class MessageQueueActivity extends Activity {
    
    /**
     * Handle the onCreate event
     */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(new DuckPondView(this));
    }

    /**
     * Create a DuckPondView which draws the duck pond and the ducks, and
     * handles the finger press events by sending and handling the appropriate
     * messages.
     */
    private static class DuckPondView extends View {
        private int mBabyDuckCount;
        private static final int MSG_RECALC_BABYDUCK_POSITIONS = 1;
        private static final int BABY_UPDATE_TICKTIME = 200;

        private final Paint mPaint = new Paint();
        private Bitmap mBmDuckPond;
        private Bitmap mBmMommaDuck;
        private Bitmap mBmBabyDuck;

        private int mMommaDuckXPos = -1;
        private int mMommaDuckYPos = -1;

        private List<Point> mBabyDuckPositions = new ArrayList<Point>();

        public DuckPondView(Context context) {
            super(context);
            setFocusable(true);

            // Create the bitmaps
            mBmDuckPond = BitmapFactory.decodeResource(getResources(),
                R.drawable.duckpond);
            mBmMommaDuck = BitmapFactory.decodeResource(getResources(),
                R.drawable.mommaduck);
            mBmBabyDuck = BitmapFactory.decodeResource(getResources(),
                R.drawable.babyduck);

            // Place the baby ducks randomly
            Random generator = new Random();
            mBabyDuckCount = 5 + generator.nextInt(3);
            for (int i = 0; i < mBabyDuckCount; i++) {
                Point position = new Point ( 50 + generator.nextInt(250),
                    50 + generator.nextInt(350) );
                mBabyDuckPositions.add(position);
            }
        }

        /**
         * The main duck pond draw handler
         */
        @Override
        protected void onDraw(Canvas canvas) {
            canvas.drawBitmap(mBmDuckPond, 0, 0, mPaint);

            // Draw Momma duck if she's present
            if (!(mMommaDuckXPos < 0 && mMommaDuckYPos < 0)) {
                canvas.drawBitmap(mBmMommaDuck, mMommaDuckXPos, mMommaDuckYPos, mPaint);
            }

            // Draw the baby ducks
            for (Point position: mBabyDuckPositions) {
                canvas.drawBitmap(mBmBabyDuck, position.x, position.y, mPaint);
            }
        }

        /**
         * Handle the finger press events
         */
        @Override
        public boolean onTouchEvent(MotionEvent event) {
            switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN: {
                    if (mMommaDuckXPos < 0 && mMommaDuckYPos < 0) {

                        // No Momma duck present so set it
                        mMommaDuckXPos = (int) event.getX() -
                            (mBmMommaDuck.getWidth() / 2);
                        mMommaDuckYPos = (int) event.getY() -
                            (mBmMommaDuck.getHeight() / 2);
                    }
                    invalidate();
                    break;
                }

                case MotionEvent.ACTION_MOVE: {

                    // Was this a press within the Momma Duck Region?
                    if (!(mMommaDuckXPos < 0 && mMommaDuckYPos < 0)) {
                        Region r = new Region(mMommaDuckXPos, mMommaDuckYPos,
                            mMommaDuckXPos + mBmMommaDuck.getWidth(),
                            mMommaDuckYPos + mBmMommaDuck.getHeight());
                        if (r.contains((int) event.getX(), (int) event.getY())) {
                            mMommaDuckXPos = (int) event.getX() -
                                (mBmMommaDuck.getWidth() / 2);
                            mMommaDuckYPos = (int) event.getY() -
                                (mBmMommaDuck.getHeight() / 2);
                        }
                        Message msg = Message.obtain();
                        msg.arg1 = MSG_RECALC_BABYDUCK_POSITIONS;
                        handler.sendMessageDelayed(msg, BABY_UPDATE_TICKTIME);
                    }
                    invalidate();
                    break;
                }
            }
            return true;
        }

        /**
         * Handle incoming messages
         */
        private Handler handler = new Handler() {

            @Override
            public void handleMessage(Message msg) {
                switch (msg.arg1) {
                    case MSG_RECALC_BABYDUCK_POSITIONS: {

                        // Iterate through the duck position List checking
                        // each one is in position. If any are not, recalculate
                        // their positions. If they are all in position, set
                        // the allInPosition flag because it means no more
                        // recalc messages are needed.
                        boolean allInPosition = true;
                        boolean thisDuckHasMoved;
                        int duckCount = 0;
                        int finalDuckXPos;
                        int finalDuckYPos;
                        int newDuckXPos;
                        int newDuckYPos;

                        for (Point position: mBabyDuckPositions) {
                            thisDuckHasMoved = false;

                            // Calc where duck should be
                            finalDuckXPos = mMommaDuckXPos
                                + mBmMommaDuck.getWidth()
                                + (duckCount * mBmBabyDuck.getWidth());
                            finalDuckYPos = mMommaDuckYPos
                                + (mBmMommaDuck.getHeight() / 2);

                            // Is this duck in position?
                            // Do we need to move this duck in the X axis?
                            if (finalDuckXPos != position.x) {
                                thisDuckHasMoved = true;
                                newDuckXPos = position.x;
                                if (finalDuckXPos < position.x) {
                                    newDuckXPos--;
                                } else {
                                    newDuckXPos++;
                                }
                                position.x = newDuckXPos;
                            }

                            // Do we need to move this duck in the Y axis?
                            if (finalDuckYPos != position.y) {
                                thisDuckHasMoved = true;
                                newDuckYPos = position.y;
                                if (finalDuckYPos < position.y) {
                                    newDuckYPos--;
                                } else {
                                    newDuckYPos++;
                                }
                                position.y = newDuckYPos;
                            }
                            if (thisDuckHasMoved) {
                                mBabyDuckPositions.set(duckCount, position);
                                allInPosition = false;
                            }
                            duckCount++;
                        }

                        if (!allInPosition) {
                            Message msgUpdate = Message.obtain();
                            msgUpdate.arg1 = MSG_RECALC_BABYDUCK_POSITIONS;
                            handler.sendMessageDelayed(msgUpdate,
                                BABY_UPDATE_TICKTIME);
                            invalidate();
                        }
                        break;
                    }
                }
            }
        };
    }
}
Joomla Templates and Joomla Extensions by JoomlaVision.Com


 

Add comment


Security code
Refresh

Portions are modifications based on work created and shared by Google and used according to terms described in the Creative Commons 3.0 Attribution License. Android Academy is independent from Google. All trademarks acknowledged.
 
Glossary
We have 22 guests online