写点什么

如何加载 100M 的图片却不撑爆内存,- 撑爆了怎么处理?100M- 的大图,如何预防 -OOM

用户头像
Android架构
关注
发布于: 8 小时前

mCurrentScale = mScale;}


onSizeChanged方法在布局期间,当此视图的大小发生更改时,将调用此方法,第一次在onMeasure之后调用,可以方便的拿到 View 的宽高。


然后给我们自定义的矩形mRect的上下左右的边界赋值。一般情况下我们使用这个自定义的 View 显示大图,都是占满这个 View,所以这里矩形初始大小就让它跟 View 一样大。


mScale用来记录原始的所方比,mCurrentScale用来记录当前的所方比,因为有双击放大和手势缩放,mCurrentScale随着手势变化。

第四步,绘制

@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);if(mRegionDecoder == n


《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》
浏览器打开:qq.cn.hn/FTe 免费领取
复制代码


ull){return;}//复用内存 mOptions.inBitmap = mBitmap;mBitmap = mRegionDecoder.decodeRegion(mRect,mOptions);mMatrix.setScale(mCurrentScale,mCurrentScale);canvas.drawBitmap(mBitmap,mMatrix,null);}


绘制也很简单,通过区域解码器解码一个矩形的区域,返回一个 Bitmap 对象,然后通过 canvas 绘制 Bitmap。需要注意mOptions.inBitmap = mBitmap;这个配置可以复用内存,保证内存的使用一直只是矩形的这块区域。


到这里运行就能绘制出一部分图片了,想要看全部的图片,需要手指拖动来看,这就需要处理各种事件了。

第五步,分发事件

@Overridepublic boolean onTouchEvent(MotionEvent event) {mGestureDetector.onTouchEvent(event);


mScaleGestureDetector.onTouchEvent(event);return true;}


onTouchEvent中很简单,事件都交给两个手势检测器自己去处理。

第六步,处理GestureDetector中的事件

@Overridepublic boolean onDown(MotionEvent e) {//如果正在滑动,先停止 if(!mScroller.isFinished()){mScroller.forceFinished(true);}return true;}


当手指按下的时候,如果图片正在飞速滑动,那么停止


@Overridepublic boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {//滑动的时候,改变 mRect 显示区域的位置 mRect.offset((int)distanceX,(int)distanceY);//处理上下左右的边界 if(mRect.left<0){mRect.left = 0;mRect.right = (int) (mViewWidth/mCurrentScale);}if(mRect.right>mImageWidth){mRect.right = (int) mImageWidth;mRect.left = (int) (mImageWidth-mViewWidth/mCurrentScale);}if(mRect.top<0){mRect.top = 0;mRect.bottom = (int) (mViewHeight/mCurrentScale);}if(mRect.bottom>mImageHeight){mRect.bottom = (int) mImageHeight;mRect.top = (int) (mImageHeight-mViewHeight/mCurrentScale);}invalidate();return false;}


onScroll中处理滑,根据手指移动的参数,来移动矩形绘制区域,这里需要处理各个边界点,比如左边最小就为 0,右边最大为图片的宽度,不能超出边界否则就报错了。


@Overridepublic boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {mScroller.fling(mRect.left,mRect.top,-(int)velocityX,-(int)velocityY,0,(int)mImageWidth,0,(int)mImageHeight);return false;}


@Overridepublic void computeScroll() {super.computeScroll();if(!mScroller.isFinished()&&mScroller.computeScrollOffset()){if(mRect.top+mViewHeight/mCurrentScale<mImageHeight){mRect.top = mScroller.getCurrY();mRect.bottom = (int) (mRect.top + mViewHeight/mCurrentScale);}if(mRect.bottom>mImageHeight) {mRect.top = (int) (mImageHeight - mViewHeight/mCurrentScale);mRect.bottom = (int) mImageHeight;}invalidate();}}


onFling方法中调用滑动器Scroller的 fling 方法来处理手指离开之后惯性滑动。惯性移动的距离在 View 的computeScroll()方法中计算,也需要注意边界问题,不要滑出边界。

第七步,处理双击事件

@Overridepublic boolean onDoubleTap(MotionEvent e) {//处理双击事件 if (mCurrentScale>mScale){mCurrentScale = mScale;} else {mCurrentScale = mScale*mMultiple;}mRect.right = mRect.left+(int)(mViewWidth/mCurrentScale);mRect.bottom = mRect.top+(int)(mViewHeight/mCurrentScale);//处理边界 if(mRect.left<0){mRect.left = 0;mRect.right = (int) (mViewWidth/mCurrentScale);}if(mRect.right>mImageWidth){mRect.right = (int) mImageWidth;mRect.left = (int) (mImageWidth-mViewWidth/mCurrentScale);}if(mRect.top<0){mRect.top = 0;mRect.bottom = (int) (mViewHeight/mCurrentScale);}if(mRect.bottom>mImageHeight){mRect.bottom = (int) mImageHeight;mRect.top = (int) (mImageHeight-mViewHeight/mCurrentScale);}


invalidate();return true;}


mMultiple为双击之后放大几倍,这里设置 3 倍。第一次双击放大 3 倍,第二次双击返回原状。缩放完成之后,需要根据当前的缩放比重新设置绘制区域的边界。最后也需要重新定位一下边界,因为如果使用两个手指放大之后,这时候双击返回原状,如果不处理边界,位置会出错。处理边界的代码可以抽取出来。

第八步,处理手指缩放事件

@Override

用户头像

Android架构

关注

还未添加个人签名 2021.10.31 加入

还未添加个人简介

评论

发布
暂无评论
如何加载100M的图片却不撑爆内存,-撑爆了怎么处理?100M-的大图,如何预防-OOM