创建新气泡时出现错误消息

时间:2014-11-08 14:57:49

标签: java android touch

当我的应用程序尝试创建新的气泡时,我遇到了错误。

我在那个框架中有一个框架有一个自定义视图,当我触摸一个空白区域时,当用户触摸一个气泡时,它会创建一个新的气泡,气泡就会消失并播放一个流行音。

这是我的代码:

public class BubbleActivity extends Activity {

// These variables are for testing purposes, do not modify
private final static int RANDOM = 0;
private final static int SINGLE = 1;
private final static int STILL = 2;
private static int speedMode = RANDOM;

private static final String TAG = "Lab-Graphics";

// The Main view
private RelativeLayout mFrame;

// Bubble image's bitmap
private Bitmap mBitmap;

// Display dimensions
private int mDisplayWidth, mDisplayHeight;

// Sound variables

// AudioManager
private AudioManager mAudioManager;
// SoundPool
private SoundPool mSoundPool;
// ID for the bubble popping sound
private int mSoundID;
// Audio volume
private float mStreamVolume;

BubbleView bubbleView;


// Gesture Detector
private GestureDetector mGestureDetector;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    setContentView(R.layout.main);

    // Set up user interface
    mFrame = (RelativeLayout) findViewById(R.id.frame);

    // Load basic bubble Bitmap
    mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.b64);

}

@Override
protected void onResume() {
    super.onResume();

    // Manage bubble popping sound
    // Use AudioManager.STREAM_MUSIC as stream type

    mAudioManager = (AudioManager) getSystemService(AUDIO_SERVICE);

    mStreamVolume = (float) mAudioManager
            .getStreamVolume(AudioManager.STREAM_MUSIC)
            / mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);

    // TODO - make a new SoundPool, allowing up to 10 streams
    mSoundPool = new SoundPool(10, AudioManager.STREAM_MUSIC, 0);

    // TODO - set a SoundPool OnLoadCompletedListener that calls
    // setupGestureDetector()
    mSoundPool.setOnLoadCompleteListener(new OnLoadCompleteListener() {
        @Override
        public void onLoadComplete(SoundPool soundPool, int sampleId,
                int status) {
            if (0 == status) {
                setupGestureDetector();
            } else {
                Log.i(TAG, "Unable to load sound");
                finish();
            }

        }
    });

    // TODO - load the sound from res/raw/bubble_pop.wav
    mAudioManager.loadSoundEffects();

}

@Override
public void onWindowFocusChanged(boolean hasFocus) {
    super.onWindowFocusChanged(hasFocus);
    if (hasFocus) {

        // Get the size of the display so this View knows where borders are
        mDisplayWidth = mFrame.getWidth();
        mDisplayHeight = mFrame.getHeight();

    }
}

// Set up GestureDetector
private void setupGestureDetector() {

    mGestureDetector = new GestureDetector(this,
            new GestureDetector.SimpleOnGestureListener() {

                // If a fling gesture starts on a BubbleView then change the
                // BubbleView's velocity

                @Override
                public boolean onFling(MotionEvent event1,
                        MotionEvent event2, float velocityX, float velocityY) {

                    // TODO - Implement onFling actions.
                    // You can get all Views in mFrame one at a time
                    // using the ViewGroup.getChildAt() method
                    if (bubbleView.intersects(velocityX, velocityY)) {
                        bubbleView.deflect(velocityX,velocityY);
                    }

                    return true;
                }

                // If a single tap intersects a BubbleView, then pop the
                // BubbleView
                // Otherwise, create a new BubbleView at the tap's location
                // and add
                // it to mFrame. You can get all views from mFrame with
                // ViewGroup.getChildAt()

                @Override
                public boolean onSingleTapConfirmed(MotionEvent event) {

                    // TODO - Implement onSingleTapConfirmed actions.
                    // You can get all Views in mFrame using the
                    // ViewGroup.getChildCount() method
                    mFrame.setOnTouchListener(new OnTouchListener() {
                        public boolean onTouch(View v, MotionEvent event) {
                            switch (event.getActionMasked()) {

                            case MotionEvent.ACTION_DOWN:

                                float pointerX = event.getX();
                                float pointerY = event.getY();
                                int pointerIndex = event.getActionIndex();
                                int pointerID = event.getPointerId(pointerIndex);

                                if (bubbleView.intersects(pointerX,pointerY)) {
                                    bubbleView = (BubbleView) mFrame.getChildAt(pointerID);
                                    bubbleView.stopMovement(true);
                                } else {
                                    bubbleView = new BubbleView(
                                            getApplicationContext(),
                                            mBitmap);

                                    mFrame.addView(bubbleView);
                                }
                            }
                            return true;
                        }
                    });

                    return true;
                }
            });
}

@Override
public boolean onTouchEvent(MotionEvent event) {

    // TODO - Delegate the touch to the gestureDetector
    return mGestureDetector.onTouchEvent(event);

}

@Override
protected void onPause() {

    // TODO - Release all SoundPool resources
    if (null != mSoundPool) {
        mSoundPool.unload(mSoundID);
        mSoundPool.release();
        mSoundPool = null;
    }

    mAudioManager.setSpeakerphoneOn(false);
    mAudioManager.unloadSoundEffects();
    super.onPause();
}

// BubbleView is a View that displays a bubble.
// This class handles animating, drawing, and popping amongst other actions.
// A new BubbleView is created for each bubble on the display

public class BubbleView extends View {

    private static final int BITMAP_SIZE = 64;
    private static final int REFRESH_RATE = 40;
    private final Paint mPainter = new Paint();
    private ScheduledFuture<?> mMoverFuture;
    private int mScaledBitmapWidth;
    private Bitmap mScaledBitmap;

    // location, speed and direction of the bubble
    private float mXPos, mYPos, mDx, mDy, mRadius, mRadiusSquared;
    private long mRotate, mDRotate;

    BubbleView(Context context, float x, float y) {
        super(context);

        // Create a new random number generator to
        // randomize size, rotation, speed and direction
        Random r = new Random();

        // Creates the bubble bitmap for this BubbleView
        createScaledBitmap(r);

        // Radius of the Bitmap
        mRadius = mScaledBitmapWidth / 2;
        mRadiusSquared = mRadius * mRadius;

        // Adjust position to center the bubble under user's finger
        mXPos = x - mRadius;
        mYPos = y - mRadius;

        // Set the BubbleView's speed and direction
        setSpeedAndDirection(r);

        // Set the BubbleView's rotation
        setRotation(r);

        mPainter.setAntiAlias(true);

    }

    public BubbleView(Context applicationContext, Bitmap mBitmap) {
        // TODO Auto-generated constructor stub
        super(getBaseContext());
    }

    private void setRotation(Random r) {
        if (speedMode == RANDOM) {

            // TODO - set rotation in range [1..3]
            mDRotate = r.nextInt(3);
            //mDRotate = r.nextInt(n)

        } else {
            mDRotate = 0;
        }
    }

    private void setSpeedAndDirection(Random r) {

        // Used by test cases
        switch (speedMode) {

        case SINGLE:

            mDx = 20;
            mDy = 20;
            break;

        case STILL:

            // No speed
            mDx = 0;
            mDy = 0;
            break;

        default:

            // TODO - Set mDx and mDy to indicate movement direction and
            // speed
            // Limit speed in the x and y direction to [-3..3] pixels per
            // movement.

        }
    }

    private void createScaledBitmap(Random r) {

        if (speedMode != RANDOM) {
            mScaledBitmapWidth = BITMAP_SIZE * 3;
        } else {

            // TODO - set scaled bitmap size in range [1..3] * BITMAP_SIZE
            mScaledBitmapWidth = r.nextInt(3)*BITMAP_SIZE;

        }

        // TODO - create the scaled bitmap using size set above
        mBitmap.createScaledBitmap(mScaledBitmap, mDisplayWidth, mDisplayHeight, false);
    }

    // Start moving the BubbleView & updating the display
    private void startMovement() {

        // Creates a WorkerThread
        ScheduledExecutorService executor = Executors
                .newScheduledThreadPool(1);

        // Execute the run() in Worker Thread every REFRESH_RATE
        // milliseconds
        // Save reference to this job in mMoverFuture
        mMoverFuture = executor.scheduleWithFixedDelay(new Runnable() {
            @Override
            public void run() {

                // TODO - implement movement logic.
                // Each time this method is run the BubbleView should
                // move one step. If the BubbleView exits the display,
                // stop the BubbleView's Worker Thread.
                // Otherwise, request that the BubbleView be redrawn.
                if(!isOutOfView()){
                    moveWhileOnScreen();
                }
                else{
                    stopMovement(true);
                }

            }
        }, 0, REFRESH_RATE, TimeUnit.MILLISECONDS);
    }

    // Returns true if the BubbleView intersects position (x,y)
    private synchronized boolean intersects(float x, float y) {

        // TODO - Return true if the BubbleView intersects position (x,y)
        if ( (x>mXPos && x<(mXPos+mScaledBitmapWidth)) && (y>mYPos && y<(mYPos+mScaledBitmapWidth)) ) {
            return true;
        }
        return false;

    }

    // Cancel the Bubble's movement
    // Remove Bubble from mFrame
    // Play pop sound if the BubbleView was popped

    private void stopMovement(final boolean wasPopped) {

        if (null != mMoverFuture) {

            if (!mMoverFuture.isDone()) {
                mMoverFuture.cancel(true);
            }

            // This work will be performed on the UI Thread
            mFrame.post(new Runnable() {
                @Override
                public void run() {

                    // TODO - Remove the BubbleView from mFrame
                    mFrame.removeView(BubbleView.this);
                    // TODO - If the bubble was popped by user,
                    // play the popping sound
                    if (wasPopped) {
                        mSoundPool.play(mSoundID, 1, 1, 1, 0, 1);
                    }
                }
            });
        }
    }

    // Change the Bubble's speed and direction
    private synchronized void deflect(float velocityX, float velocityY) {
        mDx = velocityX / REFRESH_RATE;
        mDy = velocityY / REFRESH_RATE;
    }

    // Draw the Bubble at its current location
    @Override
    protected synchronized void onDraw(Canvas canvas) {

        // TODO - save the canvas
        canvas.save();
        // TODO - increase the rotation of the original image by mDRotate
        mRotate = mRotate + mDRotate;
        // TODO Rotate the canvas by current rotation
        // Hint - Rotate around the bubble's center, not its position
        canvas.rotate(mRotate, mXPos + mScaledBitmapWidth/2, mYPos + mScaledBitmapWidth/2);
        // TODO - draw the bitmap at it's new location
        canvas.drawBitmap(mScaledBitmap, mXPos, mYPos,mPainter);
        // TODO - restore the canvas
        canvas.restore();
    }

    // Returns true if the BubbleView is still on the screen after the move
    // operation
    private synchronized boolean moveWhileOnScreen() {

        // TODO - Move the BubbleView
        mXPos = mDx+mXPos;
        mYPos = mDy+mYPos;

        postInvalidate();

        return isOutOfView();

    }

    // Return true if the BubbleView is still on the screen after the move
    // operation
    private boolean isOutOfView() {

        // TODO - Return true if the BubbleView is still on the screen after
        // the move operation
        if(mXPos + mScaledBitmapWidth/2 >= mDisplayWidth - mScaledBitmapWidth/2 || mXPos  <0
                ||mYPos + mScaledBitmapWidth/2 >= mDisplayHeight - mScaledBitmapWidth/2 || mYPos  <0){
            return true;
        }
        return false;

    }
}

这是Logcat MSG:

enter image description here

1 个答案:

答案 0 :(得分:0)

这是因为您没有在代码中的任何位置创建BubbleView实例。由于您要在点击时添加气泡,请修改onSingleTapConfirmed(),如下所示:

       @Override
        public boolean onSingleTapConfirmed(MotionEvent event) {

            // TODO - Implement onSingleTapConfirmed actions.
            // You can get all Views in mFrame using the
            // ViewGroup.getChildCount() method
            boolean createBubble = true;
            float x = event.getX();
            float y = event.getY();
            for(int i = 0 ; i < mFrame.getChildCount(); i++){
                BubbleView view = (BubbleView) mFrame.getChildAt(i);
                if(view.intersects(x, y)){
                    view.stopMovement(true);
                    createBubble = false;
                }
            }
            if(createBubble){
                BubbleView bv = new BubbleView(getApplicationContext(), x, y);
                mFrame.addView(bv);
            }

            return true;
        }
    });
}