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();
}
}
}
长图加载的内容主要就是这些,注意细节处理,其实很容易理解。我这里也只是介绍了简单的长图加载,关于横向长图,双指缩放等功能可以自己完善~
---------------------
Android内存优化————加载长图的更多相关文章
- Android 高清加载巨图方案 拒绝压缩图片
Android 高清加载巨图方案 拒绝压缩图片 转载请标明出处: http://blog.csdn.net/lmj623565791/article/details/49300989: 本文出自:[张 ...
- SurfaceView加载长图
1:SurfaceView加载长图,移到.可以充当背景 效果截图 2:View (淡入淡出动画没实现:记录下) package com.guoxw.surfaceviewimage; import a ...
- Android 高清加载巨图方案, 拒绝压缩图片
源地址:http://blog.csdn.net/lmj623565791/article/details/49300989 一.概述 距离上一篇博客有段时间没更新了,主要是最近有些私事导致的,那么就 ...
- ImageView加载长图(适用不需要缩放的情况)
此案例适用于加载网络长图且图片的宽和高已知的情况.由于ImageView加载图片有一个4096*4096的限制,所以对于巨长图的加载比较麻烦,需要我们自己去手动处理. 有两种解决方案:第一种就是比较l ...
- React-Native 之 GD (二十)removeClippedSubviews / modal放置的顺序 / Android 加载git图\动图 / 去除 Android 中输入框的下划线 / navigationBar
1.removeClippedSubviews 用于提升大列表的滚动性能.需要给行容器添加样式overflow:’hidden’.(Android已默认添加此样式)此属性默认开启 这个属性是因为在早期 ...
- 大礼包!ANDROID内存优化(大汇总)
写在最前: 本文的思路主要借鉴了2014年AnDevCon开发者大会的一个演讲PPT,加上把网上搜集的各种内存零散知识点进行汇总.挑选.简化后整理而成. 所以我将本文定义为一个工具类的文章,如果你在A ...
- ANDROID内存优化——大汇总(转)
原文作者博客:转载请注明本文出自大苞米的博客(http://blog.csdn.net/a396901990),谢谢支持! ANDROID内存优化(大汇总——上) 写在最前: 本文的思路主要借鉴了20 ...
- 【腾讯Bugly干货分享】Android内存优化总结&实践
本文来自于腾讯Bugly公众号(weixinBugly),未经作者同意,请勿转载,原文地址:https://mp.weixin.qq.com/s/2MsEAR9pQfMr1Sfs7cPdWQ 导语 智 ...
- ANDROID内存优化(大汇总——全)
写在最前: 本文的思路主要借鉴了2014年AnDevCon开发者大会的一个演讲PPT,加上把网上搜集的各种内存零散知识点进行汇总.挑选.简化后整理而成. 所以我将本文定义为一个工具类的文章,如果你在A ...
随机推荐
- 一个手机图表(echarts)折线图的封装
//定义一组颜色值,按顺序取出 var colorGroup = ["#6ca3c4","#76bfa3","#ea8f7a"," ...
- [bzoj3192][JLOI2013]删除物品_树状数组_栈
删除物品 bzoj-3192 JLOI-2013 题目大意:给你n个物品,分成2堆.所有的物品有不同的优先级.我只可以将一堆中的堆顶移动到另一个堆的堆顶.而如果当前物品是全局所有物品中优先级最高的,我 ...
- bootstrap-table与Spring项目集成实例收集
bootstrap-table项目官网:https://github.com/wenzhixin/bootstrap-table bootstrap-table各版本下载:https://github ...
- [转]十五天精通WCF——第六天 你必须要了解的3种通信模式
wcf已经说到第六天了,居然还没有说到这玩意有几种通信模式,惭愧惭愧,不过很简单啦,单向,请求-响应,双工模式,其中的第二种“请求-响应“ 模式,这个大家不用动脑子都清楚,这一篇我大概来分析下. 一: ...
- VB.NET机房收费 & 抽象工厂模式
学习设计模式的时候,提到了一个专门訪问数据库的模式-抽象工厂模式,记得当时举样例理解的时候并未设计到数据库,仅仅是大概了了解了一下,如今对于机房收费系统涉及到了数据库的管理,借此机会好好学习一下.用常 ...
- 多个结果显示成一个group_concat函数
需求:获取班级.课程中文名.老师 扩展:一个班级一门课程,老师可能多个,想把多个教师显示成在一个结果里 解决方案:加个group by 参考资料:https://www.cnblogs.com/zhu ...
- CSS3 网格布局(grid layout)基础知识 - 隐式网格自己主动布局(grid-auto-rows/grid-auto-columns/grid-auto-flow)
网格模板(grid-template)属性及其普通写法(longhands)定义了一个固定数量的轨道.构成显式网格. 当网格项目定位在这些界限之外.网格容器通过添加隐式网格线生成隐式网格轨道. 这些隐 ...
- Android实战简易教程-第二十四枪(基于Baas的用户表查询功能实现!)
接着上一篇,我们注冊了几个用户,用户表例如以下: 以下我们用ListView将表中数据显示出来吧. 首先看一下main.xml: <RelativeLayout xmlns:android=&q ...
- bin/sh^M:损坏的解释器: 没有那个文件或目录
脚本文件保存时使用了DOS格式,用DOS2UNIX转为UNIX格式,也可以用vim打开,用:set ff=unix转换.不要在 Windows下编辑脚本文件,否则经常会遇到这种问题. 代码:sed - ...
- Spring:延迟初始化
ApplicationContext实现的默认行为就是在启动时将所有singleton bean提前进行实例化.提前实例化意味着作为初始化过程的一部分,ApplicationContext实例会创建并 ...