Android启动相册+显示图片+内存优化

Android启动相册+显示图片+内存优化

今天说下调用系统系统相册选一张照片并且显示所选择的照片。本文针对基础薄弱的朋友,如果您有什么七八年开发经验,那你可以忽略本文,哈哈哈哈哈不开玩笑了,进入正文。

先写一个按钮(用于启动相册/绑定事件)和图片组件(用于显示相册中选择的图片)。一般启动活动,调用系统的什么的,都要用到Intent(有人称为意图)。首先我们也要构建一个Intent,让它去调用启动相册。

意图构建

这个Intent也是傻乎乎的,你构建它之后它也是一脸懵逼,不知道要干嘛。我们应该要指定Intent任务(属性)也就是告诉Intent它要干嘛,进行改造。

设置意图属性


定义一个请求码

首先看方法中第一行"new Intent(Intent.ACTION_PICK)"  构造函数中的参数Intent.ACTION_PICK指定这个意图的Action(可以理解为具体动作)是PICK(挑选)。也就相当于告诉我们的Intent:“我要挑选个东西”。具体挑选什么东西呢?我们也来告诉Intent。

看intent.setType()这个方法,这个就是告诉Intent挑选什么东西了。中间的参数image/*就告诉Intent挑选的是图片。当然你也可以让Intent挑选其他东西。video/*告诉Intent我要选择一个视频,audio/*就是告诉Intent我要选择一个音频。

然后最后一行"startActivityForResult()"这个方法可以理解为对着Intent大声喊:"去吧,皮卡丘"哦不,是Intent。然后这个Intent就去根据我们刚刚上面指定的动作去干活了(调用相册选择一张图片)。这个方法中间有两个参数,第一个参数类型是Intent类型,放一个Intent。代表叫哪个Intent去干活。第二个参数就代表emmmmm,比如我们构造了很多个Intent,他们带着我们想要的东西回来了,我们怎么分辨他们呢?我们怎么知道这个Intent是从相册挑选一张照片的Intent还是打开相机拍张照片的Intent呢?你们都叫Intent啊。所以,如果你想启动一个带返回值(不同于java方法中的返回值,可以理解为带回来的东西,本文带回来的就是图片)的Intent,就要指定一个标志(学术界称为请求码)。请求码是一个Int类型的值,主要用于分辨Intent。我使用0x01(0x开头表示16进制的数字,0x01也就等于1)纯属装逼用,你们也可以直接在最后一行的方法的第二个参数写个1。然后你们在要启动相册的地方掉用这个openAlbum()这个方法就好了。比如按钮的单击事件中。

想必各位已经可以跳转到相册然后选择一张照片了。接下来我们就来获取所选择的照片。

结果返回回调方法

当我们选择了一张照片,就会回调到这个方法,有Intent结果返回都会回调到这个方法。这个方法有三个参数,第一个是请求码,就是我上面介绍的。第二个是结果码,暂时不讲解。第三个就是Intent,我们要判断这个Intent是不是我们刚刚派遣的Intent,如果是的,这个Intent里面有我们想要的东西,可以通过方法来获取。通过requestCode来判断,如果这个请求码与我们startActivityForReustl()中第二个参数指定的请求码相等,则就代表这个Intent是我们请求相册的Intent。根据我的理解这个Intent已经不再是我们之前所创建的Intent了,其实我也不敢肯定,等我再学几年Android,对Android内核有所理解了再来告诉你们。但是这个Intent里面有我们想要的东西。

首先对requestCode(请求码)进行判断,看是不是我们刚刚启动这个Intent指定的请求码。如果是的,那么我们就处理这个Intent。下面是处理的方法。

相册返回结果处理

是不是很简单?这个Intent的getData方法会返回一个Uri类型的属性,这个Uri中包含了被选中图片的地址。然后我们的ImageView有个setImageURI的方法,mPortrait是一个ImageView,大家不要怕。然后ImageView就会显示我们在相册中所选择的图片。我之前看了郭神的《第一行代码》第二版,上面也有调用相册的方法,但是我这个方法比那个简单。


你们以为这就完了???笑话,Android会这么简单的事情?下面是内存使用情况。

内存使用情况

我们选择了一张图片并显示之后,看看内存情况。震惊,多选几张岂不是直接OOM(out of memory,学术界称成内存溢出)。作为一个有情怀,有梦想的程序猿,怎么能容忍这种事情的发生???所以我们要再次改造。看内存情况可以点击AndroidStudio底部的Android Profiler进入。

Android Profiler在AndroidStudio中的位置

我们通过另外一种方式来显示图片。以bitmap(位图,如果不理解暂时可以理解成一种特殊的图片)的形式来显示图片,可以为bitmap设置属性,比如设置显示的宽高,是否只加载宽高,质量,抗锯齿等等,从而降低bitmap的质量。以下部分不能理解的朋友要多看几遍。

以bitmap来显示图片

首先还是获取Intent中的uri,进行判断,是空的下面就不需要执行了,也没办法执行了。看104行,BitmapFactory是一个加载Bitmap的工厂方法,可以从很多格式数据中获取一个bitmap,此处就是从一个流中获取bitmap,decodeStream的第一个参数就是从url中获取的流,第二个参数我不知道,第三个参数我们要获取的bitmap的属性,是个BitmapFactory.Options类型的数据。可以为这个bitmap指定宽高,质量等属性。传入的BitmapFactory.Options是怎么样的,返回的Bitmap就是怎么样的。null就代表使用默认的。

如果大家104行后面部分的代码看不懂暂时可以理解为通过uri来获取一个bitmap。然后ImageView有个ImageBitmap的方法,可以通过设置一个Bitmap来显示图片。不出意外的话手机显示结果跟刚刚的设置uri方法显示是一样的。

看不懂没关系,先这样理解,我们首先获得了一个Intent,这个Intent中有个uri,这个uri可以解析出一个bitmap,我们对这个bitmap处理(降低质量),然后再调用ImageView.setImageBitmap方法可以显示这个bitmap就可以了,当然这个bitmap显示的是我们从相册中选择图片。

接下来就是处理这个Bitmap,比如我们显示的是一张小的图片,肯定要对bitmap压缩一下,而且肉眼也看不出效果。也就是处理这个bitmap的属性,比如降低bitmap的显示质量,缩小宽度高度等等,这样bitmap占用内存就小些了。bitmap的属性用BitmapFactory.Options这个类设置。


最终处理

还有一个dealOptions方法等下再贴出来。我们一行一行来讲解。上面对uri判断没啥讲的。103行大家看好,新建一个BitmapFactory.Options,大家可以当成bitmap的属性方法,bitmap加载成啥样都由这个东西决定。104,设置只加载宽高,因为我们要根据原图宽高,和要显示的宽高来压缩原图。比如,原图是1000*1000的大小,而我们要显示的ImageView却是100*100的,那么原图可以压缩成100*100大小。而且肉眼还看不出来,但是运行内存确实少了。我们要在用户肉眼看不出的情况下尽可能压缩图片,程序运行起来也更加流畅。

105行还是之前使用过的方法,但是第三个参数不是null,是我们设置只加载宽高的options,运行105行之后,options里面就包含了原图的宽高。因为设置的是只加载宽高,所以105行方法返回的bitmap为空,所以我就没有接收了。107行:dealOptions这个方法是我自己写的,方法中有三个参数,第一个参数是options,这个options中包含了原图的宽高,第二个参数是要显示ImageView的宽,第三个是ImageView的高。dealOptions方法就根据要需要显示的宽高,来处理options。返回一个处理过后的options。

109行,依然是那个方法,第三个参数是我们处理过后的options,所以返回的Bitmap也是经过处理的。然后110行显示。

dealOptions方法

还是一行一行讲解,125新建一个options。127和128分别获取原图的宽高,原图的宽高有了,所需显示的宽高也有了,那就来压缩呗。130首先定义缩放比为1。131-138就是根据宽高来设置压缩比,具体为什么这样我也说不清,大家先按这样的判断来压缩。大家知道可以告诉我。然后139设置这个新建的options的inSampleSize(压缩比)为上面几行计算出来的simpleSize。140再设置inJustDecodeBounds=false,不然有只加载宽高,内容却不加载。141设置图片的质量为RGB_565,原本是8888。142返回这个处理过后的options。

都写完了之后,我们再来看内存使用情况。

处理之后的内存情况

我刚刚从相册选择了一张图片,显示之后的情况。你看只是高了一点点。相比之前的是一个天上,一个地下。

如果大家没看懂,可以多看几遍,也可以直接问我,一开始了解这些东西肯定难以理解,我开始学的时候也是接近放弃,但是每当我想放弃的时候,心中总有一句话回响起来"如果你想修成佛,那你就要学安卓"。我知道的话也会回答。我也是新手,如果您看出我的某些地方错了,希望您能指正,大家一起成长。此文原创。转载请标明出处。祝大家学习Android愉快。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,732评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,496评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,264评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,807评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,806评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,675评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,029评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,683评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,704评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,666评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,773评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,413评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,016评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,204评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,083评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,503评论 2 343

推荐阅读更多精彩内容