在SurfaceView中加载图像时出现问题

时间:2013-02-19 18:30:17

标签: android surfaceview

我需要加载汽车的不同图像,这些图像基本保存在drawable中以模拟360度旋转,当用户拖动视图时,我设置了拖动距离,一旦用户越过它我将加载下一帧。我正在使用表面视图并在画布上绘制图像。由于图像太大,我无法一次将所有图像加载到内存中,所以我通过仅将当前图像保存在内存中来动态加载图像。但这种做法太迟钝了。谁能指出我做错了什么?或任何其他更好的方法来实现同样的目标。谢谢你的帮助。

这是我的代码

/ **  * @author rajeshcp  *作为视图中顶视图的类  * CarDetailsActivity的层次结构  * @since 2013年2月13日  * /

public class VirtualView extends SurfaceView implements SurfaceHolder.Callback, OnTouchListener, TweenListener {



private final int frame_width  = 1024;
private final int frame_height = 462;

private InteractionListener mInteractionListener;



private final int mSnapVelocity = 1000;

private VelocityTracker mVelocityTracker;

protected int mTouchSlop;

private int mMaxVelocity;



private Rect mViewArea;

private IQTweener mValueanimator;


private ColorVariationVO mColorVariationVO;

/**************Indicates the current frame*********************/
private int mCurrentFrameIndex;

/**********Initial touch x coordinate**************/
private int mInitialTouchX;

/***********The drag distance for frame change***********/
private int mDragInterWell = 10;

private final int mTotalFrames   = 36;

protected final int mMaxFrameSkip  = 3;

/**************Identity matrix**********************/
private Matrix mIdentityMatrix;


private Paint mPaint;

/*********The bitmap to be drawn over the canvas*********/
private Bitmap mCurrentFrame;


private ViewUpdater mViewUpdater;



/*++++++++++++++++++++++++++++++++++++++++++++++*/
/*+++++++++++++Getters and Setters++++++++++++++*/
/*++++++++++++++++++++++++++++++++++++++++++++++*/

/**
 * @param of type null
 * @return mColorVariationVO of type ColorVariationVO
 * getter function for mColorVariationVO
 * @since Feb 13, 2013 
 * @author rajeshcp 
 */
public ColorVariationVO getmColorVariationVO() {
    return mColorVariationVO;
}

/**
 * @param mColorVariationVO of type ColorVariationVO
 * @return of type null
 * setter function for mColorVariationVO
 * @since Feb 13, 2013
 * @author rajeshcp 
 */
public void setmColorVariationVO(ColorVariationVO mColorVariationVO) {
    this.mColorVariationVO = mColorVariationVO;
    loadNextFrame();
}

/**
 * @param context of type Context
 * @return of type VirtualView
 * Constructor function
 * @since Feb 13, 2013 
 * @author rajeshcp
 */
public VirtualView(Context context) {
    super(context);
    init();
}

/**
 * @param context of type Context
 * @param attrs of type AttributeSet
 * @return of type VirtualView
 * Constructor function
 * @since Feb 13, 2013 
 * @author rajeshcp
 */
public VirtualView(Context context, AttributeSet attrs) {
    super(context, attrs);
    init();
}

/**
 * @param context of type Context
 * @param attrs of type AttributeSet
 * @param defStyle of type int 
 * @return of type VirtualView
 * Constructor function
 * @since Feb 13, 2013 
 * @author rajeshcp
 */
public VirtualView(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
    init();
}


/**
 * @param of type null
 * @return of type null
 * function which will initialize the values for the view 
 * @since 13 Feb 2013
 */
private void init()
{
    setZOrderOnTop(true);  
    getHolder().setFormat(PixelFormat.TRANSPARENT);
    mPaint                                = new Paint(Paint.FILTER_BITMAP_FLAG | Paint.DITHER_FLAG | Paint.ANTI_ALIAS_FLAG);
    mIdentityMatrix                       = new Matrix(); 
    mCurrentFrameIndex                    = 0;
    mViewUpdater                          = new ViewUpdater();
    mInteractionListener                  = new InteractionListener();
    final ViewConfiguration configuration = ViewConfiguration.get(getContext());
    mTouchSlop                            = configuration.getScaledTouchSlop();
    mMaxVelocity                          = configuration.getScaledMaximumFlingVelocity();

    getHolder().addCallback(this);
    setOnTouchListener(this);
    setLayerType(View.LAYER_TYPE_HARDWARE, mPaint);
}


/**
 * @param direction of type int
 * @return of type null
 * function which will change the current frame index
 * @since Feb 13, 2013
 * @author rajeshcp
 */
private void initiateFrameChange(final int direction)
{
    mCurrentFrameIndex += Math.max(-mMaxFrameSkip, Math.min(mMaxFrameSkip, direction));

    if( mCurrentFrameIndex > (mTotalFrames - 1) )
    {
        mCurrentFrameIndex = (mCurrentFrameIndex % ( mTotalFrames - 1) );
    }else if( mCurrentFrameIndex < 0 )
    {
        mCurrentFrameIndex = (mTotalFrames - 1) + (mCurrentFrameIndex % (mTotalFrames - 1));
    }
    loadNextFrame();

}


/**
 * @param index of type int 
 * @return of type Bitmap 
 * function which will create the bitmap form the 
 * resources
 * @since Feb 13, 2013
 * @author rajeshcp
 */
@SuppressLint("UseSparseArrays")
private Bitmap getFrame(final int index)
{
    Bitmap bitmap = null;
    if( mColorVariationVO != null)
    {
        final int drawableId = getResourceId(index);
        try
        {
            bitmap = BitmapFactory.decodeResource(getResources(), drawableId);
        }catch (Exception e) {
            Log.d(getClass().getName(), e.getLocalizedMessage());
        }
    }
    return bitmap;
}



/**
 * @param index of type int 
 * @return of type int 
 * function which create the resource id 
 * from index
 * @since Feb 18, 2013
 * @author rajeshcp
 */
private int getResourceId(final int index)
{
    final String frameName = mColorVariationVO.getmCarAssetPath() + "_" + index;
    int drawableId = 0;
    try {
        @SuppressWarnings("rawtypes")
        Class res   = R.drawable.class;
        Field field = res.getField(frameName);
        drawableId  = field.getInt(null);
    }
    catch (Exception e) {
        Log.e(getClass().getName(), "Failure to get drawable id.", e);
    }
    return drawableId;
}




/* (non-Javadoc)
 * @see android.view.View#onDraw(android.graphics.Canvas)
 * @since Feb 13, 2013
 * @author rajeshcp 
 */
@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    if( mCurrentFrame != null && canvas != null )
    {
        canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
        mIdentityMatrix.reset();

        //          mPaint.setStyle(Paint.Style.STROKE);
        //          mPaint.setStrokeWidth(1);
        //          mPaint.setColor(Color.MAGENTA);
        //          mPaint.setTextSize(100);
        //
        //          canvas.drawText(String.valueOf(mCurrentFrameIndex), (getWidth() / (mTotalFrames - 1) ) * mCurrentFrameIndex, (getHeight() - 100) / 2, mPaint);

        mIdentityMatrix.postTranslate(getWidth() - frame_width, (getHeight() - frame_height) / 2);
        canvas.drawBitmap(mCurrentFrame, mIdentityMatrix, mPaint);
    }
}

/* (non-Javadoc)
 * @see android.view.SurfaceHolder.Callback#surfaceChanged(android.view.SurfaceHolder, int, int, int)
 * @since Feb 13, 2013
 * @author rajeshcp 
 */
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}

/* (non-Javadoc)
 * @see android.view.SurfaceHolder.Callback#surfaceCreated(android.view.SurfaceHolder)
 * @since Feb 13, 2013
 * @author rajeshcp 
 */
@Override
public void surfaceCreated(SurfaceHolder holder) {

    if( mViewArea == null )
    {
        int top   = (getHeight() - frame_height) / 2;
        int left  = getWidth() - frame_width;
        mViewArea = new Rect(left, top, frame_width + left, frame_height + top);
    }

    mDragInterWell = (int)(mViewArea.width() / (2 * mTotalFrames));

    if( mViewUpdater == null)
    {
        init();
    }
    mViewUpdater.start();
    mInteractionListener.start();
}

/* (non-Javadoc)
 * @see android.view.SurfaceHolder.Callback#surfaceDestroyed(android.view.SurfaceHolder)
 * @since Feb 13, 2013
 * @author rajeshcp 
 */
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
    if(mViewUpdater != null)
    {
        mViewUpdater.setRun(false);
        mViewUpdater                    = null;
        mInteractionListener.mIsRunning = false;
        mInteractionListener            = null;
    }
}

private boolean isScrolled = false;

/* (non-Javadoc)
 * @see android.view.View.OnTouchListener#onTouch(android.view.View, android.view.MotionEvent)
 * @since Feb 13, 2013
 * @author rajeshcp 
 */
@Override
public boolean onTouch(View v, MotionEvent event) {
    mInteractionListener.queueEvent(event);
    return true;
}

/**
 * @param velocity of type int
 * @return of type null
 * function which will initiate the 
 * fling animation
 * @since Feb 15, 2013
 * @author rajeshcp
 */
private void initiateFling(int velocity)
{
    return;
    //      int maxDuration  = mMaxFrameSkip * mSnapVelocity;
    //      velocity         = Math.max(-maxDuration, Math.min(maxDuration, velocity));
    //      int end          = ((int)( velocity / mSnapVelocity )) * mTotalFrames;
    //      
    //      if( mValueanimator == null )
    //      {
    //          mValueanimator = new IQTweener(mCurrentFrameIndex, mTotalFrames - 1);
    //          mValueanimator.setmListener(this);
    //      }
    //      mValueanimator.setMduration(2000);
    //      mValueanimator.setmStart(mCurrentFrameIndex);
    //      mValueanimator.setmEnd(end);
    //      mValueanimator.start();
}




/**
 * @param of type null
 * @return of type null
 * function which will clear 
 * the touch values
 * @since Feb 15, 2013
 * @author rajeshcp
 */
private void onTouchEnd()
{
    isScrolled = false;
    mVelocityTracker.clear();
    mVelocityTracker.recycle();
    mVelocityTracker = null;
    mInitialTouchX   = 0;
}


/* (non-Javadoc)
 * @see com.inkoniq.iqpromomultitouch.animations.IQTweener.TweenListener#onUpdate(java.lang.Object)
 * @since Feb 15, 2013
 * @author rajeshcp 
 */
@Override
public void onUpdate(float mCurrent) {

    final int mIndex = (int) mCurrent;

    if( mIndex > (mTotalFrames - 1) )
    {
        mCurrentFrameIndex = (mIndex % ( mTotalFrames - 1) );
    }else if( mIndex < 0 )
    {
        mCurrentFrameIndex = (mTotalFrames - 1) + (mIndex % (mTotalFrames - 1));
    }
}

/**
 * @param of type null
 * @return of type null
 * function which will load the next frame from local storage 
 * @since Feb 13, 2013
 * @author rajeshcp
 */
private void loadNextFrame()
{
    final Bitmap frame = getFrame(mCurrentFrameIndex);

    if(mCurrentFrame != null)
    {
        Bitmap temp   = mCurrentFrame;
        mCurrentFrame = frame;
        temp.recycle();
        temp = null;
    }else
    {
        mCurrentFrame = frame;
    }
}


/**
 * @author rajeshcp
 * class which will take care of updating the view
 * @since 13 Feb 2013 
 */
private class ViewUpdater extends Thread
{
    private SurfaceHolder surface;


    private boolean run = true;

    /**
     * @param run of type boolean 
     * @return of type null 
     * setter function for run 
     * @since 13 Feb 2013
     */
    public void setRun(boolean run) {
        this.run = run;
    }

    /**
     * @param surface of type SurfaceHolder
     * @param gameView of type GameView
     * Constructor function 
     * @since 13 Feb 2013
     */
    public ViewUpdater()
    {
    }


    /*
     * (non-Javadoc)
     * @see java.lang.Thread#run()
     * @since Feb 13, 2013
     * @author rajeshcp
     */
    @Override
    public void run() {
        Canvas canvas;

        while (run) {
            canvas = null;
            try {
                surface = getHolder();
                canvas = surface.lockCanvas(null);
                synchronized (surface) {
                    onDraw(canvas);
                }
            } finally {
                if (canvas != null) {
                    surface.unlockCanvasAndPost(canvas);
                }
            }
        }
    }
}




/**
 * @author rajeshcp
 * Class which will handle the touch 
 * events 
 * @since 19 Feb 2013
 */
private class InteractionListener extends Thread 
{

    ArrayList<MotionEvent> mEventQueue;

    boolean mIsRunning = false;

    /**
     * @param of type null
     * @return of type InteractionListener
     * Constructor function
     * @since Feb 19, 2013 
     * @author rajeshcp
     */
    public InteractionListener()
    {
        init();
    }


    /**
     * @param of type null
     * @return of type null
     * @since Feb 19, 2013
     * @author rajeshcp
     */
    private void init()
    {
        mIsRunning  = true;
        mEventQueue = new ArrayList<MotionEvent>();
    }

    /**
     * @param event of type MotionEvent
     * @return of type null
     * function which will add the event to 
     * the mEventQueue
     * @since Feb 19, 2013
     * @author rajeshcp
     */
    private void queueEvent(MotionEvent event)
    {
        mEventQueue.add(event);
    }

    /**
     * @param event of type MotionEvent
     * @return of type null
     * function which will process the touch event 
     * @since Feb 19, 2013
     * @author rajeshcp
     */
    private void onTouch(MotionEvent event) {

        if( event == null )
            return;

        if( mVelocityTracker == null )
        {
            mVelocityTracker = VelocityTracker.obtain();
        }
        mVelocityTracker.addMovement(event);
        if( !mViewArea.contains((int)event.getX(), (int)event.getY()) )
        {
            return;
        }

        switch(event.getAction())
        {
        case MotionEvent.ACTION_DOWN :
        {
            if( mValueanimator != null )
            {
                mValueanimator.cancel();
            }
            isScrolled = false;
            mInitialTouchX = (int)event.getX();
            break;
        }
        case MotionEvent.ACTION_MOVE :
        {
            final int currentX        = (int)event.getX();
            final int draggedDistance = (currentX - mInitialTouchX);
            if( draggedDistance != 0 && draggedDistance % mDragInterWell == 0 )
            {
                isScrolled     = true;
                initiateFrameChange(draggedDistance / mDragInterWell);
                Log.d(getClass().getName(), "frameIndex = " + mCurrentFrameIndex);
                mInitialTouchX = currentX;
            }
            break;
        }
        case MotionEvent.ACTION_UP :
        {
            if( isScrolled )
            {
                final VelocityTracker velocityTracker = mVelocityTracker;
                velocityTracker.computeCurrentVelocity(1000, mMaxVelocity);
                int velocityX = (int) velocityTracker.getXVelocity();
                if( (velocityX > mSnapVelocity) || (velocityX < -mSnapVelocity) )
                {
                    initiateFling(velocityX);
                }
            }
            onTouchEnd();
            break;
        }
        case MotionEvent.ACTION_CANCEL :
        {
            onTouchEnd();
            break;
        }
        default :
        {
            break;
        }
        }
    }


    /* (non-Javadoc)
     * @see java.lang.Thread#run()
     * @since Feb 19, 2013
     * @author rajeshcp 
     */
    @Override
    public void run() {
        while ( mIsRunning ) {
            while ( mEventQueue.size() > 0 ) {
                onTouch(mEventQueue.remove(0));
                try
                {
                    Thread.sleep(16);
                }catch (Exception e) {
                }
            }

        }
    }

}
}

1 个答案:

答案 0 :(得分:1)

由于尝试显示模拟的360度视图的复杂性,您可能需要考虑使用OpenGL来处理此渲染。这将为您提供更多关于内容显示方式的能力,并将简化您的实施。

然而;这并不是说这是一个简单的实现。但这将是实现此类目标的最佳方式。