安卓实现内存复用加载长图

现在长图越来越多 例如微博上就有很多长图 这篇文章就是实现加载长图时能最少的占用内存
首先要自定义一个View代码如下
public class BigView extends View implements GestureDetector.OnGestureListener,View.OnTouchListener{
private final Rect mRect;
private final BitmapFactory.Options mOptions;
private final Scroller mScroller;
private final GestureDetector mGestureDetetor;
private int mImageWidth;
private int mImageHieght;
private BitmapRegionDecoder mDecoder;
private int mViewWidth;
private int mViewHeight;
private float mScale;
private Bitmap mBitmap;

public BigView(Context context) {
    this(context,null);
}
public BigView(Context context, @Nullable AttributeSet attrs) {
    this(context, attrs,0);
}
public BigView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
//第一步设置bigview需要的成员变量
    mRect=new Rect();
    mOptions =new BitmapFactory.Options();//内存复用
    mGestureDetetor =new GestureDetector(context,this);//手势识别
    mScroller =new Scroller(context);//滚动类
    setOnTouchListener(this);
}
//第二步 ,设置图片,并且得到图片信息
public void setImage(InputStream is){
    //获取图片宽和高,注意:不能将整个图片加载进内存
    mOptions.inJustDecodeBounds=true;
    BitmapFactory.decodeStream(is,null,mOptions);
    mImageWidth=mOptions.outWidth;//获取图片的宽
    mImageHieght=mOptions.outHeight;//获取图片的高
    mOptions.inMutable=true;//开启复用
    mOptions.inPreferredConfig= Bitmap.Config.RGB_565;   //设置图片格式为rgb_565
    mOptions.inJustDecodeBounds=false;
    //区域解码器
    try {
        mDecoder= BitmapRegionDecoder.newInstance(is,false);
    } catch (IOException e) {
        e.printStackTrace();
    }
    requestLayout();
}
//第三步,开始测量,得到view的宽高,测量加载的图片到底缩放成什么样
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    mViewWidth=getMeasuredWidth();//获取view的宽
    mViewHeight=getMeasuredHeight();//获取view的高
    //确定加载图片的区域
    mRect.left=0;
    mRect.top=0;
    mRect.right=mImageWidth;
    //计算缩放因子
    mScale=mViewWidth/(float)mImageWidth;
    mRect.bottom= (int) (mViewHeight/mScale);
}
//第4步 画出具体的内容
@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    //判断解码器是不是为空,如果解码器为空,表示没有设置过图片
    if (mDecoder==null){
        return;
    }
    //真正内存复用 //f复用的bitmap 必须跟即将解码的bitmap尺寸一样
    mOptions.inBitmap=mBitmap;
    mBitmap=mDecoder.decodeRegion(mRect,mOptions);//指定解码区域
    //得到一个矩阵进行缩放,相当于的到view的大小
    Matrix matrix=new Matrix();
    matrix.setScale(mScale,mScale);
    canvas.drawBitmap(mBitmap,matrix,null);
}
//第5步,处理点击事件
@Override
public boolean onTouch(View v, MotionEvent event) {
    //直接将事件交给手势事件处理
    return mGestureDetetor.onTouchEvent(event);
}
//第6步 手按下去
@Override
public boolean onDown(MotionEvent e) {
    //如果移动没有停止,就强行将它停止
    if (!mScroller.isFinished()){
        mScroller.forceFinished(true);
    }
    //继续接收后续事件
    return true;
}

//第7 步 处理滑动事件
//e1:开始事件,手指按下去,开始获取坐标
//e2:获取当前事件坐标
//xy:xy轴移动的距离
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
//手上下移动的时候,mRect需要改变显示的区域
mRect.offset(0, (int) distanceY);
//移动时处理到达顶部和底部的情况
if (mRect.bottom>mImageHieght){
mRect.bottom=mImageHieght;
mRect.top= (int) (mImageHieght-(mViewHeight/mScale));
}
if (mRect.top<0){
mRect.top=0;
mRect.bottom= (int) (mViewHeight/mScale);
}
invalidate();//重绘
return false;
}

//第8 步 处理惯性问题
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
mScroller.fling(0,mRect.top,0,(int)-velocityY,0,0,0,mImageHieght-(int)(mViewHeight/mScale));
return false;
}

//第9步 处理计算结果
@Override
public void computeScroll() {
if (mScroller.isFinished()){//滚动结束
return;
}
if (mScroller.computeScrollOffset()){//滚动未结束
mRect.top=mScroller.getCurrY();
mRect.bottom=mRect.top+(int)(mViewHeight/mScale);
invalidate();
}
super.computeScroll();
}
@Override
public void onShowPress(MotionEvent e) {
}
@Override
public boolean onSingleTapUp(MotionEvent e) {
return false;
}
@Override
public void onLongPress(MotionEvent e) {
}
}

然后接下来就是来使用自己写的View来加载图片 代码如下
public class MainActivity extends AppCompatActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    BigView bigView= (BigView) findViewById(R.id.bigview);
    try {
        InputStream is=getAssets().open("c.png");
        bigView.setImage(is);
    } catch (IOException e) {
        e.printStackTrace();
    }
}

}

布局代码如下:
<com.example.ttest.BigView
android:id="@+id/bigview"
android:layout_width=“wrap_content”
android:layout_height=“wrap_content”
/>

至此使用内存复用加载长图就已经实现完成

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

S1om

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值