微信相册图片java会不会内存泄露占手机内存?

[1回答]我的微信一直显示储存卡剩余空间不足可能会影响微信图片,语音及视频功能.
这是怎么回事?我的手机内存还有1.5GB
SD卡还有3.5GB__内存_SD卡_程序搬家 _手机问题_刷机专家(卓大师)
我的微信一直显示储存卡剩余空间不足可能会影响微信图片,语音及视频功能.
这是怎么回事?我的手机内存还有1.5GB
SD卡还有3.5GB
网友(8285415)问于
o 系统(2.2.1
) o Root权限(已获取)
答案1:内存小/少
手机内存在手机出厂的时候就已经固定了,其总量无法调整,不能像电脑一样加内存条。所以想提升可用内存,除了经常清理系统,或者把不是必须的应用移到SD卡,然后使用其他应用时停掉其他的占内存的应用。不过默认系统会自动处理。
答案2:实际内存比标识的小
手机的内存显示往往会比官方说明要少一些,这是正常的,因为硬件驱动、系统以及其他一些核心功能会占用一些内存(而且是不能释放的),手机上显示出来的空间只包含您实际可以用的。还有就是计算的标准不一样。厂家计算的标准是1000(比如1MB=1000KB)并且是从字节开始计算的,而系统是以1024进行计算的。
答案3:如何释放内存RAM
手机RAM相当于电脑的内存条。当程序开启时程序的运行数据就存储在RAM中;由于安卓系统的特性,当程序结束运行时,其内存仍然驻留在RAM中,这是为了下次启动很快。需要注意的是这些不运行的程序驻留在RAM是不影响速度的,因为当RAM不够用的时候,系统会自动释放不运行软件的内存。也可以选择结束掉正在运行的程序来强行释放内存。
是以前查找附近的人太多了,在百度里边搜索下微信文件夹储存在什么位置,然后把那个打开,里边全是图片,你都删除了就可以了。我刚搞定
qzone_何赛回答于
0个赞同 o 0个反对
专家简介:原卓大师,专注刷机领域,业内元老级应用。
专家宣言:让您一键轻松解决刷机烦恼!
版本:5.3.1大小:16.8MB
版本:2.7.0大小:2.84MB
大师简介:业内最强ROOT软件,轻松ROOT。
大师宣言:让您一键轻松解决ROOT烦恼!
版本:2.7.1大小:11.57MB
版本:3.3.0大小:5.5MB
大师简介:免ROOT直接安装字体,个性化定制手机。
大师宣言:万千字体,想换就换!
版本:3.9.0大小:5.2MB
相关解决问题列表
(C) 2007 - 2015
北京耘升天下科技有限公司
帮助与支持
关注卓大师官方微信
获取最新潮刷机资讯
还没有卓大师的账号?
或使用其他帐号登录:微信现在是童鞋们日常生活中必不可少的一款聊天工具了,但有很多时候,会被好友拉到自己并不感兴趣的微信群里,那么该如何退出微信群聊呢?接下来,就给大家演示一下该如何退出微信群,有遇到这问题可以跟着一起往下看看。可能很多朋友都不知道手机微信如何退出群聊吧,下面以图文的方式给大家具体介绍快速退出群聊的具体方法,有需要的机友可参考。 1.你先点进要退的群,以下是小编要退的群聊消息框。 2.在你群聊的界面单击“聊天主界面右上角的按钮”,即可进入到“群管理界面”,如下图所示: 3.然后拉到最下面就可以看见【删
我们先要下载安装好我们的360手机安全卫士!我们就用安卓市场软件来把360手机安全卫士下载到我们的手机吧!点击进入搜索界面,在搜索栏上输入“360”然后点击搜索按钮!在新的页面下,我们要找到360手机安全卫士软件,并点击它;然后在新界面里点击最右下角的下载!这样我们就正确地下载了一个360手机安全卫士安卓手机软件! 软件下载:360保险箱 v5.0.0.1050 官方正式版(支持Win7) 我们把360手机安全卫士下载到我们的手机了,我们要把它安装到我们的手机才能使用的!我们在管理下的下载任务里
手机qq怎么禁言?小编将在下文演示手机qq禁言个人教程,如果我们不想让一个人在群里说话的话该怎么进行设置呢?能不能将其禁言?当然是可以的,步骤如下,一起来看吧。 第一步、打开手机QQ后点击【联系人】--【群组】。 第二步、点击一个【我管理的群】,点击群里想要禁言成员的头像。 第三步、接着点击【右上角的图标】,最后点击【禁言】就完成了。 手机qq禁言的方法就是这么简单,快去试试吧。
还在用手机版微信?还在为手机没电玩微信而烦恼?现在网页版微信发起群功能有啦。 微信网页版如何发起群聊天?小编今天来为大家介绍一下使用教程。 第一步:打开网页 第二步:成功扫描之后,点击我确认登录微信网页版 第三步:成功扫描之后,点击我确认登录微信网页版,发起聊天。 第四步:扫描之后,成功登录微信网页版,找到群主 第五步,开始聊天了。等待群里的童鞋回复吧。 注意事项: 1、微信网页版与手机微信是同步更新的,所以不要以为使用微信网页版就不会产生流量了。他是同样需要流
如果你也是个手机软件狂人,喜欢尝试各种各样新奇有趣的软件,面对越来越少的手机内存空间,不得不对已经安装的软件痛下杀手。你是否还在安装与卸载之间纠结?Follow Me!我们一起来给Android系统扩扩容,让“机器人”也可以“大肚能容”,免去存储空间不足的后顾之忧。 复制代码 代码如下: Tips:存储器分为随机存储器(RAM)和只读存储器(ROM)两种。手机ROM相当于PC上的硬盘,用于存储手机操作系统和软件,也叫FLASH ROM,决定手机存储空间的大小。手机RAM相当于PC的内存,其大小决
微信是腾讯公司于日推出的一款通过网络快速发送语音短信、视频、图片和文字,支持多人群聊的手机聊天软件。随着微信的使用率越来越高,微信群的使用率也越来越广泛。但有很多时候,微信群也是一种困扰(如会议、约会时)。其实,很多朋友不知道,微信群是可以设置为静音的,今天,笔者就给大家讲解下,微信群该如何设置为静音状态呢? 1)首先进入微信,进入微信群。 2)进入微信群后,点击微信群右上角的“设置”(如下图) 3)进入微信群设置后点击“详细设置” 4)勾选“关闭音量震动提醒”即可。 注:iP
第一步:打开网页 第二步:成功扫描之后,点击我确认登录微信网页版 第三步:成功扫描之后,点击我确认登录微信网页版,发起聊天。 第四步:扫描之后,成功登录微信网页版,找到群主 第五步,开始聊天了。等待群里的童鞋回复吧。 注意事项: 1、微信网页版与手机微信是同步更新的,所以不要以为使用微信网页版就不会产生流量了。他是同样需要流量的。所以在使用微信网页版的时候,尽量保证手机连接WiFi。 2、微信网页版没有朋友圈。 3、手机退出微信端,微信网页版会自动退出!
最近有网友问笔者这样一个问题:微信群能踢人吗?对于此问题,笔者也没有尝试过,不过之前笔者建立过一个微信群,因此之后也去研究了一下,发现微信群与QQ群类似,也支持踢人功能,只是操作上有所不同。可能大家对于微信群踢人方面还不是很了解,以下脚本之家小编为大家详细介绍下。 一、微信群能踢人吗? 与腾讯QQ群类似,微信群也是可以踢人的,不过与QQ群有所不同的是,QQ群只要是管理就可以踢人,而微信群只要群创建者才可以踢人。 二、微信群如何踢人? 微信群踢人也比较简单,只是没有QQ群踢人那么方便,具体微信群踢
智能手机越来越多,多样的应用也不断地丰富着收集的功能,但是,如果某次安装应用的时候,提示手机内存不足了怎么办? 添置内存卡,扩大存储空间: 主流的智能机一般支持16G内存卡,购置一块内存卡安装在手机扩展槽里,即可正常使用: 使用豌豆荚应用程序进行手机应用管理: 手机连接到电脑上后,依次单击豌豆荚主界面右上角的“设置,手机管理,安装应用设置”: 选择“优先安装到SD卡(推荐)”或者“强制安装到SD卡”后,单击“确定”: 在主机面上依次单击“应用和游戏,安装新应用”: 单击“添加文件”: 找到文件后
在PP助手上看见好多喜欢的壁纸或者在网上下载了好多图片,该怎么放到手机里面呢?如果使用iTunes导入,过程非常复杂,而且会覆盖掉手机之前的图片,其实只要通过PP助手,我们就可以方便快捷的进行图片的导入了。 一、导入PP助手的壁纸 将设备连接PP助手,点击:网络资源---选择墙纸,然后在适用设备对应选择好适配机型,找到喜欢的壁纸单击,在弹出壁纸的右下角选择导入设备即可。 二、导入电脑里的图片 ①.将设备和PP助手连接后,点击设备--照片。 ②.点击右边面板的”导入“按钮,在弹
不知道微信群聊怎么找?如果遇到微信群聊找不到了有什么解决方法呢?很多机友表示不知怎么的之前加入的群聊都消失了,下面就来看一看该如何解决并且找回微信群聊吧~ 微信下载: 微信安卓版 微信iPhone版 微信电脑版 如果你感觉这个微信群还不错,建议在“详细设置”里点击“保存到通讯录”,这样以后哪怕你清空这个微信群的聊天记录,仍然可以在通讯录里找到这个群。 微信群与QQ群并不一样,因为QQ群有固定的号码,而微信群却没有。如果你没有在通讯录中保存,就关闭或退出这个群,那么很遗憾,现在是找不到
微信群怎么找?很多微信朋友在退出群后想再加入回去,但是不知道怎么加入。那么微信群怎么找呢?可以找得到吗?小编为你一一解答。 想干阅读:如何退出微信群聊天组 退出微信群的图文详细步骤 如果你感觉这个微信群还不错,建议在“详细设置”里点击“保存到通讯录”,这样以后哪怕你清空这个微信群的聊天记录,仍然可以在通讯录里找到这个群。 微信群与QQ群并不一样,因为QQ群有固定的号码,而微信群却没有。如果你没有在通讯录中保存,就关闭或退出这个群,那么很遗憾,现在是找不到的,只有等群里的某人又发起聊天时,你再添加
微信群怎么@所有人呢?长按群内小伙伴们的头像可以单独@他,可是,你知道怎么@群内所有人吗?下面小编将为大家讲解下微信群聊@所有人方法,希望能够帮助到大家哦! 微信群怎么@所有人? 第一步:文本编辑软件(EmEditor_v14或者Editplus) 下载文本编辑软件 第二步:登陆微信网页版(/) 第三步:随便选择一个微信群 第四步:打开微信群微信全员界面,复制微信群所有成员名字,Alt+C 或者右键复制 第五步:打开EmEditor_v14软件,粘贴刚才复制的群
手机qq群能修改昵称吗?手机qq5.0群昵称怎样修改?腾讯最近发布了手机qq5.0,这个版本有比较大的改动,不论实在界面还是在功能上,很多经常用手机登陆QQ的朋友们不知道怎样修改群名片,下面就脚本之家小编为大家详细具体修改步骤吧 方法/步骤 1、在手机上打开qq 5.0。 2、点击“群组”进入群组列表。任意进入一个群。 3、点击右上方小图标,进入群资料。 4、点击下方“我的群名片”。进入“我的群名片“下的”群昵称“选项。 5、在”群昵称“页面下,修改即可,修改完点击右上方”完成“按钮即可。 EN
微信是童鞋们必不可少的联络工具,在自己创建微信群组以后,将自己的好友或志趣相投的朋友汇集起来,但是如果想要修改微信群昵称该怎么操作呢?来为大家介绍如何操作群组。 1、打开自己想要修改群昵称的微信群,在右上角点击“聊天信息”设置,如图所示 随后在微信群设置中,往下翻,找到“我在本群的昵称”,然后修改,如图所示 最后输入在这个微信群的昵称,点击“保存”按钮就可以了,如图所示
微信多开宝是一款手机上可以安装多个微信账号的软件。有的人不止有一个微信账号,账号多了来回切换比较麻烦。微信多开宝可以帮你解决,那么微信多开宝怎样一个手机安装多个微信?下面让我们一起去简单的了解下怎么使用吧。 1、电脑百度微信多开宝,这个是分版本的,安卓的手机就下安卓版的,苹果的要下苹果版的才可以。现在以安卓版的为例。 2、下载到手机上之后直接安装就好了。安装好的微信多开宝如图所示。 3、点击多开宝右上角的云状图标,就可以下载多个微信了!不过这里说明,安装多个是要付费的,但是安装一个是
微信小视频怎么导出?360手机助手多了一个功能,就是可以轻松导出微信的小视频,大家还不知道吧。之前还要自己进入到手机内去一个一个查找,现在就方便多了,现在就让小编跟大家介绍一下360手机助手轻松导出微信小视频。一起来看看吧! 360手机助手轻松导出微信小视频教程: 1:打开链接一下到手机,这里是360助手新添加的功能,找到其他的,我的视频。就可以看到了。(小编这里手机没有视频,所以看不到,或者你有视频,看不到就点击一下刷新就好) 这就是小编跟大家介绍的360手机助手轻松导出微信小
微信的群聊,可能没有那么多人清楚了,它的存在已经延伸为点赞群了,勤俭持家神器。那么,微信群聊如何加好友,让大家同乐呢?本文,小编就将为大家分享微信群聊邀请好友教程。 腾讯QQ发展这么多年,相信很多人可以把它玩的熟的不能再熟了,连QQ群中的机器人都调戏的顺手。但是,微信的群聊,可能就不会那么多人清楚了,它的存在已经延伸为点赞群了,勤俭持家神器。那么,微信群聊如何加好友,让大家同乐呢?本文,小编就将为大家分享微信群聊邀请好友教程。 具体方法: 第一步、在“微信”应用,点击“通讯录”,选中“群聊”。
mvbox虚拟视频播放器支持任何带摄像头功能的聊天软件,如QQ、YY、呱呱等,有的朋友就问了,mvbox怎么在qq群里唱歌呢?下面请看小编给大家整理的mvbox教程 在设置用mvbo在QQ群里唱歌之前,我们需要对mvbo和QQ进行关联 现在骗子都很多,学习的人也很多,很多心术不正的人,就喜欢luo聊啥的,结果被人骗了都不知道为什么,因为mvbox和QQ视频聊天是可以对接的,弄出个虚假视频,所以你看到的不一定是真人,可能是人家在播放视频。OK接下来,我教大家如何设置mvbox和QQ视频聊天关联,怎
mvbox虚拟视频播放器支持任何带摄像头功能的聊天软件,如QQ、YY、呱呱等,有的朋友就问了,mvbox怎么在qq群里唱歌呢?下面请看小编给大家整理的mvbox教程 1、如何在聊天室关联MVBOX虚拟摄象头 1) 进入聊天室,在聊天室的右侧点击按钮,选择音视频设置,如下图: 2) 在音视频窗口中的视频设备中选择“Virtual Cam”,即可实现在聊天室关联MVBOX虚拟摄像头,可以很方便的利用画中画、调色板、滤镜和抠象、特效等功能来美化您的摄象头,如下图设置所示: 2、如何在QQ中使用虚拟摄象28310人阅读
转载请注明本文出自xiaanming的博客(),请尊重他人的辛勤劳动成果,谢谢!写这篇文章之前,先简单说几句,首先是先恭喜下自己获得了2013年的博客之星称号,很意外也很开心,自己是从2013年开始写博客,那时候也不知道怎么写,我从小就不喜欢写日记,作文什么的,所以刚开始都是贴代码,也没有人看,后面慢慢的,写的文章被推荐博客首页和CSDN首页(这里也要小小的感谢下小编MM),访问量逐渐的多了起来,有更多的人看我的文章,这也使自己有了继续写文章的动力,也希望我写的东西对大家有点帮助吧,在2014年我会继续在CSDN上面写博客,然后是感谢博客之星给我投票支持我的朋友们,谢谢你们支持我的每一票,最后就是2014春节马上就到了,提前祝福大家新年快乐,工作顺利,事事顺心!回到主题,之前群里面有朋友问我,有没有关于本地图片选择的Demo,类似微信的效果,他说网上没有这方面的Demo,问我能不能写一篇关于这个效果的Demo,于是我研究了下微信的本地图片选择的Demo,自己仿照的写了下分享给大家,希望对以后有这样子需求的朋友有一点帮助吧,主要使用的是ContentProvider扫描手机中的图片,并用GridView将图片显示出来,关于GridView和ListView显示图片的问题,一直是一个很头疼的问题,因为我们手机的内存有限,手机给每个应用程序分配的内存也有限,所以图片多的情况下很容易伴随着OOM的发生,不过现在也有很多的开源的图片显示框架,对显示很多图片进行了优化,大家有兴趣的可以去了解了解,今天我的这篇文章使用的是LruCache这个类(之前写了一篇使用LruCache加载网络图片的)以及对图片进行相对应的裁剪,这样也可以尽量的避免OOM的发生,我们先看下微信的效果吧接下来我们就来实现这些效果吧,首先我们新建一个项目,取名ImageScan首先我们先看第一个界面吧,使用将手机中的图片扫描出来,然后根据图片的所在的文件夹将其分类出来,并显示所在文件夹里面的一张图片和文件夹中图片个数,我们根据界面元素(文件夹名, 文件夹图片个数,文件夹中的一张图片)使用一个实体对象ImageBean来封装这三个属性package com.example.
* GridView的每个item的数据对象
* @author len
public class ImageBean{
* 文件夹的第一张图片路径
private String topImageP
* 文件夹名
private String folderN
* 文件夹中的图片数
private int imageC
public String getTopImagePath() {
return topImageP
public void setTopImagePath(String topImagePath) {
this.topImagePath = topImageP
public String getFolderName() {
return folderN
public void setFolderName(String folderName) {
this.folderName = folderN
public int getImageCounts() {
return imageC
public void setImageCounts(int imageCounts) {
this.imageCounts = imageC
接下来就是主界面的布局啦,上面的导航栏我没有加进去,只有下面的GridView,所以说主界面布局中只有一个GridView&RelativeLayout xmlns:android=&/apk/res/android&
xmlns:tools=&/tools&
android:layout_width=&match_parent&
android:layout_height=&match_parent& &
android:id=&@+id/main_grid&
android:layout_width=&match_parent&
android:layout_height=&match_parent&
android:listSelector=&@android:color/transparent&
android:cacheColorHint=&@android:color/transparent&
android:stretchMode=&columnWidth&
android:horizontalSpacing=&20dip&
android:gravity=&center&
android:verticalSpacing=&20dip&
android:columnWidth=&90dip&
android:numColumns=&2& &
&/GridView&
&/RelativeLayout&接下来就是GridView的Item的布局,看上面的图也行你会认为他的效果是2张图片添加的效果,其实不是,后面的叠加效果只是一张背景图片而已,代码先贴上来&?xml version=&1.0& encoding=&UTF-8&?&
&RelativeLayout xmlns:android=&/apk/res/android&
android:layout_width=&fill_parent&
android:layout_height=&wrap_content& &
&FrameLayout
android:id=&@+id/framelayout&
android:layout_width=&fill_parent&
android:layout_height=&wrap_content& &
&com.example.imagescan.MyImageView
android:id=&@+id/group_image&
android:background=&@drawable/albums_bg&
android:src=&@drawable/friends_sends_pictures_no&
android:paddingLeft=&20dip&
android:paddingRight=&20dip&
android:paddingTop=&18dip&
android:paddingBottom=&30dip&
android:scaleType=&fitXY&
android:layout_width=&fill_parent&
android:layout_height=&150dip& /&
android:id=&@+id/group_count&
android:layout_width=&wrap_content&
android:layout_height=&wrap_content&
android:background=&@drawable/albums_icon_bg&
android:gravity=&center&
android:layout_marginBottom=&10dip&
android:text=&5&
android:layout_gravity=&bottom|center_horizontal& /&
&/FrameLayout&
android:id=&@+id/group_title&
android:layout_width=&fill_parent&
android:layout_height=&wrap_content&
android:gravity=&center&
android:layout_below=&@id/framelayout&
android:layout_centerHorizontal=&true&
android:ellipsize=&end&
android:singleLine=&true&
android:text=&Camera&
android:textSize=&16sp& /&
&/RelativeLayout&看到上面的布局代码,也行你已经发现了,上面使用的是自定义的MyImageView,我先不说这个自定义MyImageView的作用,待会再给大家说,我们继续看代码第一个界面的主要代码package com.example.
import java.io.F
import java.util.ArrayL
import java.util.HashM
import java.util.I
import java.util.L
import java.util.M
import android.app.A
import android.app.ProgressD
import android.content.ContentR
import android.content.I
import android.database.C
import android.net.U
import android.os.B
import android.os.H
import android.os.M
import android.provider.MediaS
import android.view.V
import android.widget.AdapterV
import android.widget.AdapterView.OnItemClickL
import android.widget.GridV
* @blog http://blog.csdn.net/xiaanming
* @author xiaanming
public class MainActivity extends Activity {
private HashMap&String, List&String&& mGruopMap = new HashMap&String, List&String&&();
private List&ImageBean& list = new ArrayList&ImageBean&();
private final static int SCAN_OK = 1;
private ProgressDialog mProgressD
private GroupA
private GridView mGroupGridV
private Handler mHandler = new Handler(){
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case SCAN_OK:
//关闭进度条
mProgressDialog.dismiss();
adapter = new GroupAdapter(MainActivity.this, list = subGroupOfImage(mGruopMap), mGroupGridView);
mGroupGridView.setAdapter(adapter);
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mGroupGridView = (GridView) findViewById(R.id.main_grid);
getImages();
mGroupGridView.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView&?& parent, View view,
int position, long id) {
List&String& childList = mGruopMap.get(list.get(position).getFolderName());
Intent mIntent = new Intent(MainActivity.this, ShowImageActivity.class);
mIntent.putStringArrayListExtra(&data&, (ArrayList&String&)childList);
startActivity(mIntent);
* 利用ContentProvider扫描手机中的图片,此方法在运行在子线程中
private void getImages() {
//显示进度条
mProgressDialog = ProgressDialog.show(this, null, &正在加载...&);
new Thread(new Runnable() {
public void run() {
Uri mImageUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
ContentResolver mContentResolver = MainActivity.this.getContentResolver();
//只查询jpeg和png的图片
Cursor mCursor = mContentResolver.query(mImageUri, null,
MediaStore.Images.Media.MIME_TYPE + &=? or &
+ MediaStore.Images.Media.MIME_TYPE + &=?&,
new String[] { &image/jpeg&, &image/png& }, MediaStore.Images.Media.DATE_MODIFIED);
if(mCursor == null){
while (mCursor.moveToNext()) {
//获取图片的路径
String path = mCursor.getString(mCursor
.getColumnIndex(MediaStore.Images.Media.DATA));
//获取该图片的父路径名
String parentName = new File(path).getParentFile().getName();
//根据父路径名将图片放入到mGruopMap中
if (!mGruopMap.containsKey(parentName)) {
List&String& chileList = new ArrayList&String&();
chileList.add(path);
mGruopMap.put(parentName, chileList);
mGruopMap.get(parentName).add(path);
//通知Handler扫描图片完成
mHandler.sendEmptyMessage(SCAN_OK);
mCursor.close();
}).start();
* 组装分组界面GridView的数据源,因为我们扫描手机的时候将图片信息放在HashMap中
* 所以需要遍历HashMap将数据组装成List
* @param mGruopMap
private List&ImageBean& subGroupOfImage(HashMap&String, List&String&& mGruopMap){
if(mGruopMap.size() == 0){
List&ImageBean& list = new ArrayList&ImageBean&();
Iterator&Map.Entry&String, List&String&&& it = mGruopMap.entrySet().iterator();
while (it.hasNext()) {
Map.Entry&String, List&String&& entry = it.next();
ImageBean mImageBean = new ImageBean();
String key = entry.getKey();
List&String& value = entry.getValue();
mImageBean.setFolderName(key);
mImageBean.setImageCounts(value.size());
mImageBean.setTopImagePath(value.get(0));//获取该组的第一张图片
list.add(mImageBean);
首先看getImages()这个方法,该方法是使用ContentProvider将手机中的图片扫描出来,我这里只扫描了手机的外部存储中的图片,由于手机中可能存在很多的图片,扫描图片又比较耗时,所以我们在这里开启了子线程去获取图片,扫描的图片都存放在Cursor中,我们先要将图片按照文件夹进行分类,我们使用了HashMap来进行分类并将结果存储到mGruopMap(Key是文件夹名,Value是文件夹中的图片路径的List)中,分类完了关闭Cursor并利用Handler来通知主线程然后是subGroupOfImage()方法,改方法是将mGruopMap的数据组装到List中,在List中存放GridView中的每个item的数据对象ImageBean, 遍历HashMap对象,具体的逻辑看代码,之后就是给GridView设置Adapter。设置item点击事件,点击文件夹跳转到展示文件夹图片的Activity, 我们需要传递每个文件夹中的图片的路径的集合看GroupAdapter的代码之前,我们先看一个比较重要的类,本地图片加载器NativeImageLoaderpackage com.example.
import java.util.concurrent.ExecutorS
import java.util.concurrent.E
import android.graphics.B
import android.graphics.BitmapF
import android.graphics.P
import android.os.H
import android.os.M
import android.support.v4.util.LruC
* 本地图片加载器,采用的是异步解析本地图片,单例模式利用getInstance()获取NativeImageLoader实例
* 调用loadNativeImage()方法加载本地图片,此类可作为一个加载本地图片的工具类
* @blog http://blog.csdn.net/xiaanming
* @author xiaanming
public class NativeImageLoader {
private LruCache&String, Bitmap& mMemoryC
private static NativeImageLoader mInstance = new NativeImageLoader();
private ExecutorService mImageThreadPool = Executors.newFixedThreadPool(1);
private NativeImageLoader(){
//获取应用程序的最大内存
final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
//用最大内存的1/4来存储图片
final int cacheSize = maxMemory / 4;
mMemoryCache = new LruCache&String, Bitmap&(cacheSize) {
//获取每张图片的大小
protected int sizeOf(String key, Bitmap bitmap) {
return bitmap.getRowBytes() * bitmap.getHeight() / 1024;
* 通过此方法来获取NativeImageLoader的实例
public static NativeImageLoader getInstance(){
* 加载本地图片,对图片不进行裁剪
* @param path
* @param mCallBack
public Bitmap loadNativeImage(final String path, final NativeImageCallBack mCallBack){
return this.loadNativeImage(path, null, mCallBack);
* 此方法来加载本地图片,这里的mPoint是用来封装ImageView的宽和高,我们会根据ImageView控件的大小来裁剪Bitmap
* 如果你不想裁剪图片,调用loadNativeImage(final String path, final NativeImageCallBack mCallBack)来加载
* @param path
* @param mPoint
* @param mCallBack
public Bitmap loadNativeImage(final String path, final Point mPoint, final NativeImageCallBack mCallBack){
//先获取内存中的Bitmap
Bitmap bitmap = getBitmapFromMemCache(path);
final Handler mHander = new Handler(){
public void handleMessage(Message msg) {
super.handleMessage(msg);
mCallBack.onImageLoader((Bitmap)msg.obj, path);
//若该Bitmap不在内存缓存中,则启用线程去加载本地的图片,并将Bitmap加入到mMemoryCache中
if(bitmap == null){
mImageThreadPool.execute(new Runnable() {
public void run() {
//先获取图片的缩略图
Bitmap mBitmap = decodeThumbBitmapForFile(path, mPoint == null ? 0: mPoint.x, mPoint == null ? 0: mPoint.y);
Message msg = mHander.obtainMessage();
msg.obj = mB
mHander.sendMessage(msg);
//将图片加入到内存缓存
addBitmapToMemoryCache(path, mBitmap);
* 往内存缓存中添加Bitmap
* @param key
* @param bitmap
private void addBitmapToMemoryCache(String key, Bitmap bitmap) {
if (getBitmapFromMemCache(key) == null && bitmap != null) {
mMemoryCache.put(key, bitmap);
* 根据key来获取内存中的图片
* @param key
private Bitmap getBitmapFromMemCache(String key) {
return mMemoryCache.get(key);
* 根据View(主要是ImageView)的宽和高来获取图片的缩略图
* @param path
* @param viewWidth
* @param viewHeight
private Bitmap decodeThumbBitmapForFile(String path, int viewWidth, int viewHeight){
BitmapFactory.Options options = new BitmapFactory.Options();
//设置为true,表示解析Bitmap对象,该对象不占内存
options.inJustDecodeBounds =
BitmapFactory.decodeFile(path, options);
//设置缩放比例
options.inSampleSize = computeScale(options, viewWidth, viewHeight);
//设置为false,解析Bitmap对象加入到内存中
options.inJustDecodeBounds =
return BitmapFactory.decodeFile(path, options);
* 根据View(主要是ImageView)的宽和高来计算Bitmap缩放比例。默认不缩放
* @param options
* @param width
* @param height
private int computeScale(BitmapFactory.Options options, int viewWidth, int viewHeight){
int inSampleSize = 1;
if(viewWidth == 0 || viewWidth == 0){
return inSampleS
int bitmapWidth = options.outW
int bitmapHeight = options.outH
//假如Bitmap的宽度或高度大于我们设定图片的View的宽高,则计算缩放比例
if(bitmapWidth & viewWidth || bitmapHeight & viewWidth){
int widthScale = Math.round((float) bitmapWidth / (float) viewWidth);
int heightScale = Math.round((float) bitmapHeight / (float) viewWidth);
//为了保证图片不缩放变形,我们取宽高比例最小的那个
inSampleSize = widthScale & heightScale ? widthScale : heightS
return inSampleS
* 加载本地图片的回调接口
* @author xiaanming
public interface NativeImageCallBack{
* 当子线程加载完了本地的图片,将Bitmap和图片路径回调在此方法中
* @param bitmap
* @param path
public void onImageLoader(Bitmap bitmap, String path);
该类是一个单例类,提供了本地图片加载,内存缓存,裁剪等逻辑,该类在加载本地图片的时候采用的是异步加载的方式,对于大图片的加载也是比较耗时的,所以采用子线程的方式去加载,对于图片的缓存机制使用的是LruCache,使用手机分配给应用程序内存的1/4用来缓存图片,除了使用LruCache缓存图片之外,还对图片进行了裁剪,举个很简单的例子,假如我们的控件大小是100 * 100, 而我们的图片是400*400,我们加载这么大的图片需要很多的内存,所以我们采用了图片裁剪,根据控件的大小来确定图片的裁剪比例,从而减小内存的消耗,提高GridView滑动的流畅度,介绍里面几个比较重要的方法computeScale()计算图片需要裁剪的比例,根据控件的大小和图片的大小确定比例,如果图片比控件大,我们就进行裁剪,否则不需要。decodeThumbBitmapForFile()方法是根据计算好了图片裁剪的比例之后从文件中加载图片,我们先设置options.inJustDecodeBounds = true表示解析不占用内存,但是我们能获取图片的具体大小,利用computeScale()计算好比例,在将options.inJustDecodeBounds=false,再次解析Bitmap,这样子就对图片进行了裁剪。loadNativeImage(final String path, final Point mPoint, final NativeImageCallBack mCallBack)我们在客户端只需要调用该方法就能获取到Bitmap对象,里面的具体逻辑是先判断内存缓存LruCache中是否存在该Bitmap,不存在就开启子线程去读取,为了方便管理加载本地图片线程,这里使用了线程池,池中只能容纳一个线程,读取完了本地图片先将Bitmap加入到LruCache中,保存的Key为图片路径,然后再使用Handler通知主线程图片加载好了,之后将Bitmap和路径回调到方法onImageLoader(Bitmap bitmap, String path)中,该方法的mPoint是用来封装控件的宽和高的对象如果不对图片进行裁剪直接这个方法的重载方法loadNativeImage(final String path, final NativeImageCallBack mCallBack) 就行了,逻辑是一样的,只是这个方法不对图片进行裁剪接下来就是GridView的Adapter类的代码package com.example.
import java.util.L
import android.content.C
import android.graphics.B
import android.graphics.P
import android.view.LayoutI
import android.view.V
import android.view.ViewG
import android.widget.BaseA
import android.widget.GridV
import android.widget.ImageV
import android.widget.TextV
import com.example.imagescan.MyImageView.OnMeasureL
import com.example.imagescan.NativeImageLoader.NativeImageCallB
public class GroupAdapter extends BaseAdapter{
private List&ImageBean&
private Point mPoint = new Point(0, 0);//用来封装ImageView的宽和高的对象
private GridView mGridV
protected LayoutInflater mI
public int getCount() {
return list.size();
public Object getItem(int position) {
return list.get(position);
public long getItemId(int position) {
public GroupAdapter(Context context, List&ImageBean& list, GridView mGridView){
this.list =
this.mGridView = mGridV
mInflater = LayoutInflater.from(context);
public View getView(int position, View convertView, ViewGroup parent) {
final ViewHolder viewH
ImageBean mImageBean = list.get(position);
String path = mImageBean.getTopImagePath();
if(convertView == null){
viewHolder = new ViewHolder();
convertView = mInflater.inflate(R.layout.grid_group_item, null);
viewHolder.mImageView = (MyImageView) convertView.findViewById(R.id.group_image);
viewHolder.mTextViewTitle = (TextView) convertView.findViewById(R.id.group_title);
viewHolder.mTextViewCounts = (TextView) convertView.findViewById(R.id.group_count);
//用来监听ImageView的宽和高
viewHolder.mImageView.setOnMeasureListener(new OnMeasureListener() {
public void onMeasureSize(int width, int height) {
mPoint.set(width, height);
convertView.setTag(viewHolder);
viewHolder = (ViewHolder) convertView.getTag();
viewHolder.mImageView.setImageResource(R.drawable.friends_sends_pictures_no);
viewHolder.mTextViewTitle.setText(mImageBean.getFolderName());
viewHolder.mTextViewCounts.setText(Integer.toString(mImageBean.getImageCounts()));
//给ImageView设置路径Tag,这是异步加载图片的小技巧
viewHolder.mImageView.setTag(path);
//利用NativeImageLoader类加载本地图片
Bitmap bitmap = NativeImageLoader.getInstance().loadNativeImage(path, mPoint, new NativeImageCallBack() {
public void onImageLoader(Bitmap bitmap, String path) {
ImageView mImageView = (ImageView) mGridView.findViewWithTag(path);
if(bitmap != null && mImageView != null){
mImageView.setImageBitmap(bitmap);
if(bitmap != null){
viewHolder.mImageView.setImageBitmap(bitmap);
viewHolder.mImageView.setImageResource(R.drawable.friends_sends_pictures_no);
return convertV
public static class ViewHolder{
public MyImageView mImageV
public TextView mTextViewT
public TextView mTextViewC
首先我们将每个item的图片路径设置Tag到该ImageView上面,然后利用NativeImageLoader来加载本地图片,但是我们显示的图片的宽和高可能远大于GirdView item中ImageView的大小,于是为了节省内存,我们需要对图片进行裁剪,需要对图片裁剪我们利用loadNativeImage(final String path, final Point mPoint, final NativeImageCallBack mCallBack)方法,我们就必须要获取ImageView的宽和高了但是我们想在getView()中获取ImageView的宽和高存在问题,在getView()里面刚开始显示item的时候利用ImageView.getWidth() 获取的都是0,为什么刚开始获取不到宽和高呢,因为我们使用LayoutInflater来将XML布局文件Inflater()成View的时候,View并没有显示在界面上面,表明并没有对View进行onMeasure(), onLayout(), onDraw()等操作,必须等到retrue&convertView的时候,表示该item对应的View已经绘制在ListView的位置上了,&此时才对item对应的View进行onMeasure(), onLayout(), onDraw()等操作,这时候才能获取到Item的宽和高,于是我想到了自定义ImageView,在onMeasure()中利用回调的模式主动通知我ImageView测量的宽和高,但是这有一个小小的问题,就是显示GridView的第一个item的时候,获取的宽和高还是0,第二个就能正常获取了,第一个宽和高为0,表示我们不对第一张图片进行裁剪而已,在效率上也没啥问题,不知道大家有没有好的方法,可以在getView()中获取Item中某个控件的宽和高。自定义MyImageView的代码,我们只需要设置OnMeasureListener监听,当MyImageView测量完毕之后,就会将测量的宽和高回调到onMeasureSize()中,然后我们可以根据MyImageView的大小来裁剪图片package com.example.
import android.content.C
import android.util.AttributeS
import android.widget.ImageV
public class MyImageView extends ImageView {
private OnMeasureListener onMeasureL
public void setOnMeasureListener(OnMeasureListener onMeasureListener) {
this.onMeasureListener = onMeasureL
public MyImageView(Context context, AttributeSet attrs) {
super(context, attrs);
public MyImageView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
//将图片测量的大小回调到onMeasureSize()方法中
if(onMeasureListener != null){
onMeasureListener.onMeasureSize(getMeasuredWidth(), getMeasuredHeight());
public interface OnMeasureListener{
public void onMeasureSize(int width, int height);
上面这些代码就完成了第一个界面的功能了,接下来就是点击GridView的item跳转另一个界面来显示该文件夹下面的所有图片,功能跟第一个界面差不多,也是使用GridView来显示图片,第二个界面的布局代码我就不贴了,直接贴上界面的代码package com.example.
import java.util.L
import android.app.A
import android.os.B
import android.widget.GridV
import android.widget.T
public class ShowImageActivity extends Activity {
private GridView mGridV
private List&String&
private ChildA
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.show_image_activity);
mGridView = (GridView) findViewById(R.id.child_grid);
list = getIntent().getStringArrayListExtra(&data&);
adapter = new ChildAdapter(this, list, mGridView);
mGridView.setAdapter(adapter);
public void onBackPressed() {
Toast.makeText(this, &选中 & + adapter.getSelectItems().size() + & item&, Toast.LENGTH_LONG).show();
super.onBackPressed();
GridView的item上面一个我们自定义的MyImageView用来显示图片,另外还有一个CheckBox来记录我们选中情况,Adapter的代码如下package com.example.
import java.util.ArrayL
import java.util.HashM
import java.util.I
import java.util.L
import java.util.M
import android.content.C
import android.graphics.B
import android.graphics.P
import android.view.LayoutI
import android.view.V
import android.view.ViewG
import android.widget.BaseA
import android.widget.CheckB
import poundB
import android.widget.ImageV
import poundButton.OnCheckedChangeL
import android.widget.GridV
import com.example.imagescan.MyImageView.OnMeasureL
import com.example.imagescan.NativeImageLoader.NativeImageCallB
import com.nineoldandroids.animation.AnimatorS
import com.nineoldandroids.animation.ObjectA
public class ChildAdapter extends BaseAdapter {
private Point mPoint = new Point(0, 0);//用来封装ImageView的宽和高的对象
* 用来存储图片的选中情况
private HashMap&Integer, Boolean& mSelectMap = new HashMap&Integer, Boolean&();
private GridView mGridV
private List&String&
protected LayoutInflater mI
public ChildAdapter(Context context, List&String& list, GridView mGridView) {
this.list =
this.mGridView = mGridV
mInflater = LayoutInflater.from(context);
public int getCount() {
return list.size();
public Object getItem(int position) {
return list.get(position);
public long getItemId(int position) {
public View getView(final int position, View convertView, ViewGroup parent) {
final ViewHolder viewH
String path = list.get(position);
if(convertView == null){
convertView = mInflater.inflate(R.layout.grid_child_item, null);
viewHolder = new ViewHolder();
viewHolder.mImageView = (MyImageView) convertView.findViewById(R.id.child_image);
viewHolder.mCheckBox = (CheckBox) convertView.findViewById(R.id.child_checkbox);
//用来监听ImageView的宽和高
viewHolder.mImageView.setOnMeasureListener(new OnMeasureListener() {
public void onMeasureSize(int width, int height) {
mPoint.set(width, height);
convertView.setTag(viewHolder);
viewHolder = (ViewHolder) convertView.getTag();
viewHolder.mImageView.setImageResource(R.drawable.friends_sends_pictures_no);
viewHolder.mImageView.setTag(path);
viewHolder.mCheckBox.setOnCheckedChangeListener(new OnCheckedChangeListener() {
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
//如果是未选中的CheckBox,则添加动画
if(!mSelectMap.containsKey(position) || !mSelectMap.get(position)){
addAnimation(viewHolder.mCheckBox);
mSelectMap.put(position, isChecked);
viewHolder.mCheckBox.setChecked(mSelectMap.containsKey(position) ? mSelectMap.get(position) : false);
//利用NativeImageLoader类加载本地图片
Bitmap bitmap = NativeImageLoader.getInstance().loadNativeImage(path, mPoint, new NativeImageCallBack() {
public void onImageLoader(Bitmap bitmap, String path) {
ImageView mImageView = (ImageView) mGridView.findViewWithTag(path);
if(bitmap != null && mImageView != null){
mImageView.setImageBitmap(bitmap);
if(bitmap != null){
viewHolder.mImageView.setImageBitmap(bitmap);
viewHolder.mImageView.setImageResource(R.drawable.friends_sends_pictures_no);
return convertV
* 给CheckBox加点击动画,利用开源库nineoldandroids设置动画
* @param view
private void addAnimation(View view){
float [] vaules = new float[]{0.5f, 0.6f, 0.7f, 0.8f, 0.9f, 1.0f, 1.1f, 1.2f, 1.3f, 1.25f, 1.2f, 1.15f, 1.1f, 1.0f};
AnimatorSet set = new AnimatorSet();
set.playTogether(ObjectAnimator.ofFloat(view, &scaleX&, vaules),
ObjectAnimator.ofFloat(view, &scaleY&, vaules));
set.setDuration(150);
set.start();
* 获取选中的Item的position
public List&Integer& getSelectItems(){
List&Integer& list = new ArrayList&Integer&();
for(Iterator&Map.Entry&Integer, Boolean&& it = mSelectMap.entrySet().iterator(); it.hasNext();){
Map.Entry&Integer, Boolean& entry = it.next();
if(entry.getValue()){
list.add(entry.getKey());
public static class ViewHolder{
public MyImageView mImageV
public CheckBox mCheckB
第二个界面的Adapter跟第一个界面差不多,无非多了一个CheckBox用来记录图片选择情况,我们只需要对CheckBox设置setOnCheckedChangeListener监听,微信的选中之后CheckBox有一个动画效果,所以我利用nineoldandroids动画库也给CheckBox加了一个动画效果,直接调用addAnimation()方法就能添加了,getSelectItems()方法就能获取我们选中的item的position了,知道了选中的position,其他的信息就都知道了,微信有对图片进行预览的功能,我这里就不添加了,如果有这个需求可以自行添加,给大家推荐一个运行项目,效果如下看起来还不错吧,采用的是异步读取图片,对图片进行了缓存和裁剪,使得在显示本地图片方面比较流畅,GridView滑动也挺流畅的,也有效的避免OOM的产生,工程中有些东西还没有贴完全,有兴趣的朋友可以下载Demo来运行一下,好了,今天的讲解到这里结束了,感谢大家观看,有疑问的朋友可以在下面留言,我会为大家解答的!
版权声明:本文为博主原创文章,未经博主允许不得转载。
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:1792594次
积分:15934
积分:15934
排名:第285名
原创:60篇
转载:15篇
评论:3359条
Android 技术讨论群
我的联系方式
文章:16篇
阅读:324125
(3)(1)(1)(1)(1)(3)(4)(4)(2)(2)(5)(6)(10)(8)(15)(4)(2)(1)(2)}

我要回帖

更多关于 内存会不会影响fps 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信