2013-02-19 81 views
0

我需要加載保存在drawable中的汽車的不同圖像,以便模擬360度旋轉,當用戶拖動視圖時我已經設置了拖動距離,加載下一幀。我正在使用曲面視圖並在畫布上繪製圖像。由於圖像太大,我無法一次將所有圖像加載到內存中,因此我通過僅將當前圖像保留在內存中來實時加載圖像。但是這種方法太慢了。任何人都可以指出我做錯了什麼嗎?或任何其他更好的方式來實現相同。謝謝你的幫助。在SurfaceView中加載圖像時發生的問題

這是我的代碼

/** * @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

由於嘗試顯示模擬360度視圖的複雜性,您可能需要考慮使用OpenGL來處理此渲染。這將爲您提供更多的內容顯示權力,並且會簡化您的實施。

但是;這並不是說這是一個簡單的實施。但這將是實現這樣的最好方式。

+0

你能指出我做錯了什麼嗎?或者什麼是渲染滯後的主要原因。我嘗試了所有可能從本地資源加載圖像的事情,這可能是造成這種滯後的原因,那麼我該如何擺脫這種滯後? – Triode 2013-02-19 18:48:15

+1

Itsa對SurfaceView的限制,認爲你在處理過程中對Bitmap做了很多工作,只是這樣做會花費很多時間。因爲位圖的工作與它必須處理的像素數(分辨率)成正比。它並不是說你做錯了什麼,但是你使用了錯誤的方法。 – JoxTraex 2013-02-19 18:52:44

+0

http://stackoverflow.com/questions/1039393/iphone-app-png-sequence-animation-how-to-use-opengle-optimally-without-crashin但這是iPhone的情況,雖然 – Triode 2013-02-19 18:56:13