• Android内存优化————加载长图


    项目中总会遇到加载长图的需求,图片的长度可能是手机长度的很多倍,也就是需要通过滑动来查看图片。比较简单的实现方式就是使用ScrollView来加载长图,但是这样做有一个很严重的问题,就是内存消耗严重。我这里有一张长图,宽高为440*10260,大小为477KB,使用ScrollView加载的话,总内存消耗为97M,是相当恐怖的。而使用优化后的自定View加载长图,内存消耗为46M,极大的减少了内存的优化,效果非常明显。我简单说一下实现的过程

    1.创建自定义View——BigImageView
    对BigImageView的构造器进行简单的修改,并且初始化相关的属性
     

    public class BigImageView extends View implements
    View.OnTouchListener, GestureDetector.OnGestureListener{
    private Rect mRect;//长图中要加载的区域
    private BitmapFactory.Options mOptions;
    private GestureDetector mGestureDetector;//手势的检测器
    private Scroller mScroller;//滚动的帮助类

    public BigImageView(Context context) {
    this(context,null);
    }

    public BigImageView(Context context, @Nullable AttributeSet attrs) {
    this(context, attrs,-1);
    }

    public BigImageView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
    mRect = new Rect();//指定加载的区域
    mOptions = new BitmapFactory.Options();
    mGestureDetector = new GestureDetector(context, this);
    setOnTouchListener(this);//设置监听
    mScroller = new Scroller(context);
    }

    @Override
    public boolean onTouch(View v, MotionEvent event) {
    //交给手势处理
    return mGestureDetector.onTouchEvent(event);
    }

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

    @Override
    public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
    return false;
    }

    @Override
    public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
    return false;
    }

    @Override
    public void onShowPress(MotionEvent e) {}
    @Override
    public void onLongPress(MotionEvent e) {}
    @Override
    public boolean onSingleTapUp(MotionEvent e) { return false; }
    }
    虽然实现的方法比较多,但是有很多都方法都用不到,比如onShowPress,onSingleTapUp,onLongPress。

    上面的代码基本上都很好理解,而mRect这个属性我简单画图说明一下。

    mRect就是图中蓝色框的部分。mRect和手机的尺寸(黑色框)比例是一样;mRect的宽度和长图的宽度是一样的。展示的时候,需要把mRect区域根据缩放比例,展示到手机的屏幕既可以。

    2.设置输入图片的入口
    创建了一个属性mDecoder,用来进行图片的解码

    /**
    * 输入一张图片
    */
    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();
    }
    3.覆写onMeasure方法
    获取了BigImageView的宽高,可以和上一步获取的图片的宽高算出缩放比例。并且设置mRect的上下左右值,用来展示长图的哪部分

    /**
    * 在测量的时候把我们需要的内存区域获取到 存入到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);
    }
    4.覆写onScroll方法
    主要是两个功能:(1)每次滑动,mRect展示的区域都会改变(2)滑动到顶点和底部的处理

    /**
    *
    * @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;
    }
    5.覆写onDraw
    在画布上画出展示的图片

    /**
    * 画出内容
    */
    @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);
    }
    6.惯性滑动处理
    onFling方法里的内容主要就是计算惯性滑动的值

    computeScroll主要就是惯性滑动行为

    需要注意的是mScroller.fling中的第四的参数,是负值

    /**
    * 处理惯性问题
    * @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();
    }
    }
    7.手机按下停止滑动处理
    /**
    * 手按下的回调
    * @param e
    * @return
    */
    @Override
    public boolean onDown(MotionEvent e) {
    //如果移动还没有停止,强制停止
    if(!mScroller.isFinished()){
    mScroller.forceFinished(true);//强制停止
    }
    //继续接收后续事件
    return true;
    }
    8.调用
    BigImageView1 bigView=findViewById(R.id.bigView);
    InputStream is=null;
    try{
    //加载图片
    is=getAssets(http://www.my516.com).open("big.png");
    bigView.setImage(is);
    }catch(Exception e){
    e.printStackTrace();
    }finally {
    if(is!=null){
    try {
    is.close();
    } catch (IOException e) {
    e.printStackTrace();
    }
    }
    }
    长图加载的内容主要就是这些,注意细节处理,其实很容易理解。我这里也只是介绍了简单的长图加载,关于横向长图,双指缩放等功能可以自己完善~
    --------------------- 

  • 相关阅读:
    ARCDesktop 学习笔记(一) 添加地图图层
    ARCGIS 开发常用技巧参考
    关于引用动软代码 找不到dll命名空间问题
    银行转账手续费
    Silverlight 笔记
    地图API
    (转)使用ImageBrush替换PictureMarkerSymbol以加强graphic显示性能
    WPF 网摘
    ArcCatalog添加GISserverIP问题
    ARCGIS 10 中文版 3D Analyst Tools等未授权问题
  • 原文地址:https://www.cnblogs.com/ly570/p/10995916.html
Copyright © 2020-2023  润新知