性能優化專題四--內存優化(長圖加載)

public class BigView extends View implements GestureDetector.OnGestureListener, View.OnTouchListener {

    private Rect mRect;
    private BitmapFactory.Options mOptions;
    private GestureDetector mGestureDetector;
    private Scroller mScroller;
    private int mImageWidth;
    private int mImageHeight;
    private BitmapRegionDecoder mDecoder;
    private int mViewWidth;
    private int mViewHeight;
    private float mScale;
    private Bitmap bitmap;

    public BigView(Context context) {
        this(context, null, 0);
    }

    public BigView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public BigView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        //指定要加載的區域
        mRect = new Rect();
        //需要複用
        mOptions = new BitmapFactory.Options();
        //手勢識別類
        mGestureDetector = new GestureDetector(context, this);
        //設置onTouchListener
        setOnTouchListener(this);


        //滑動幫助
        mScroller = new Scroller(context);

    }

    /**
     * 由使用者輸入一張圖片
     */
    public void setImage(InputStream is) {
        //先讀取原圖片的信息   高,寬
        mOptions.inJustDecodeBounds = true;
        BitmapFactory.decodeStream(is, null, mOptions);
        mImageWidth = mOptions.outWidth;
        mImageHeight = mOptions.outHeight;
        //開啓複用
        mOptions.inMutable = true;
        //設置格式成RGB_565
        mOptions.inPreferredConfig = Bitmap.Config.RGB_565;
        mOptions.inJustDecodeBounds = false;

        //創建一個區域解碼器
        try {
            mDecoder = BitmapRegionDecoder.newInstance(is, false);
        } catch (IOException e) {
            e.printStackTrace();
        }

        requestLayout();
    }

    /**
     * 在測量的時候把我們需要的內存區域獲取到  存入到mRect中
     */
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        //獲取測量的view的大小
        mViewWidth = getMeasuredWidth();
        mViewHeight = getMeasuredHeight();

        //確定要加載的圖片的區域
        mRect.left = 0;
        mRect.top = 0;
        mRect.right = mImageWidth;
        //獲取一個縮放因子
        mScale = mViewWidth / (float) mImageWidth;
        //高度就根據縮放比進行獲取
        mRect.bottom = (int) (mViewHeight / mScale);
    }

    /**
     * 畫出內容
     */
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //如果解碼器拿不到,表示沒有設置過要顯示的圖片
        if (null == mDecoder) {
            return;
        }
        //複用上一張bitmap
        mOptions.inBitmap = bitmap;
        //解碼指定的區域
        bitmap = mDecoder.decodeRegion(mRect, mOptions);
        //把得到的矩陣大小的內存進行縮放  得到view的大小
        Matrix matrix = new Matrix();
        matrix.setScale(mScale, mScale);
        //畫出來
        canvas.drawBitmap(bitmap, matrix, null);
    }

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        //交給手勢處理
        return mGestureDetector.onTouchEvent(event);
    }

    /**
     * 手按下的回調
     *
     * @param e
     * @return
     */
    @Override
    public boolean onDown(MotionEvent e) {
        //如果移動還沒有停止,強制停止
        if (!mScroller.isFinished()) {
            mScroller.forceFinished(true);
        }
        //繼續接收後續事件
        return true;
    }

    /**
     * @param e1        接下
     * @param e2        移動
     * @param distanceX 左右移動時的距離
     * @param distanceY 上下移動時的距離
     * @return
     */
    @Override
    public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
        //上下移動的時候,需要改變顯示區域   改mRect
        mRect.offset(0, (int) distanceY);
        //處理移動時已經移到了兩個頂端的問題
        if (mRect.bottom > mImageHeight) {
            mRect.bottom = mImageHeight;
            mRect.top = mImageHeight - (int) (mViewHeight / mScale);
        }
        if (mRect.top < 0) {
            mRect.top = 0;
            mRect.bottom = (int) (mViewHeight / mScale);
        }
        invalidate();
        return false;
    }

    /**
     * 處理慣性問題
     *
     * @param e1
     * @param e2
     * @param velocityX 每秒移動的x點
     * @param velocityY
     * @return
     */
    @Override
    public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
        //做計算
        mScroller.fling(0, mRect.top,
                0, (int) -velocityY,
                0, 0,
                0, mImageHeight - (int) (mViewHeight / mScale));
        return false;
    }

    /*
    使用上一個接口的計算結果
     */
    @Override
    public void computeScroll() {
        if (mScroller.isFinished()) {
            return;
        }
        //true 表示當前滑動還沒有結束
        if (mScroller.computeScrollOffset()) {
            mRect.top = mScroller.getCurrY();
            mRect.bottom = mRect.top + (int) (mViewHeight / mScale);
            invalidate();
        }
    }

    @Override
    public void onShowPress(MotionEvent e) {
    }

    @Override
    public boolean onSingleTapUp(MotionEvent e) {
        return false;
    }

    @Override
    public void onLongPress(MotionEvent e) {

    }

}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章