5007
- 收藏
- 点赞
- 分享
- 举报
由OOM问题引发的分析
本帖最后由 Heguming 于 2015-8-21 18:09 编辑
最近,在做一个导览系统,主要功能是为游人提供馆内各层的导览图,方便人们参观。
项目刚开始,一切都有条不紊的进行。由于接触过几个这方面的项目,因此进行起来还算顺利。
然而,项目进行过程中,确实遇到了问题:OOM-内存溢出
有经验的工程师会立即想到BUG的源头:图片尺寸过大或加载数量过多
本项目开发过程中,多次出现该问题,具体细节及解决方法如下:
1.主界面
对于此处的OOM,我采取了一个较为规避的方法,将原定计划的ImageView+GestureDetector改为WebView。
经过修改,不仅解决了OOM问题,还使得手势操作较GestureDetector更为灵敏,流畅,毕竟是采用了WebView内置的Zoom工具,效果就是不一样。然而同样存在一个问题,即WebView加载过程中,会出现短暂的空白期,但相对于原定计划,该瑕疵可以忽略。
2.管理员界面
此处需要同时加载两张图片,若加载图片过大,会报OOM错误。即使选取图片尺寸较小,也会感到很明显的卡顿现象。这极大的影响了用户的交互体验。对于此处OOM问题,我采取的措施是加载缩略图。
加载缩略图,目前主要有两种方式:
1.通过ThumbnailUtils工具类直接创建缩略图:
newBitmap = ThumbnailUtils.extractThumbnail(oldBitmap, width, height);
2.利用Option属性压缩图片生成缩略图:
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
Bitmap bitmap = BitmapFactory.decodeFile(path, options);
options.inSampleSize = scale; //缩放倍数
options.inJustDecodeBounds = false;
bitmap = BitmapFactory.decodeFile(path, options);
ThumbnailUtils是Android 2.2版本中,新增的一个用于实现缩略图的工具类,此工具类功能强大,利用内置的常数和方法,可以轻松快捷的实现图片和视频的缩略图功能。
对于这两种方式,我都尝试了一遍。相比较而言,第二种方式加载图片缩略图更快,故此处采用第二种方式。
3.文件浏览
此处需要同时显示同一文件夹下的所有图片文件的缩略图,然后以列表的形式显示在ItemView中。对于此类需要同时加载多张图片的场合,通常采用异步方式进行。
异步加载图片缩略图可以通过AsyncLoadedImage类实现。
AsyncLoadedImage类继承AsyncTask异步加载类,通过调用publishProgress方法更新onProgressUpdate贮存缩略图信息到Adapter,通过监听Adapter Change实现异步加载缩略图。
然而,经过测试,发现通过这种方法加载图片效果效果并不理想。因此,我采取了另外一种方式。
首先,在ListView Adapter中,禁止ItemView中的ImageView控件的图片加载。如果在此Adapter中getView方法内加载图片,会导致图片的重复加载。
因为getView方法是用于获取将要显示的View,即每滑动一次,就会加载一次图片,对于已经加载过的,是无法保存的。
其次,将列表改为可上拉加载的,这样在显示刷新页面的footView时,可以进行数据的更新及图片的显示。
由于将setImage放在了Adapter外,故而此时加载的图片是可以保存的,是不随getView而实时动态重复加载的。
然而,此处调试过程中,发现了一个致命的逻辑错误。
由于我是在更新数据的同时加载ImageView的,此时父View-ListView尚未生成,即listView并未执行getView方法,故而无法通过子View-ItemView获取控件ImageView的ID。
而我想要的效果是,更新完数据后,同时加载图片,最后通过ListView显示出来。
很明显,这陷入了逻辑循环悖论之中。即若要加载A View,必须先加载B View,而若要加载B View,又必须先加载A View。
因而,该效果最后被否定。只有先获得ListView,然后通过getChildAt方法获得ItemView,最终获得ImageView的ID。
可是,又有一个问题随之而生,即何时更新ImageView。很显然,必须ListView一被显示,即执行Update方法更新ImageView。那么,问题来了,如何监听ListView显示完成?
由于开发经验不深,在我的印象中,貌似ListView并没有该listener-onCreateView。
最初设想是通过在getView中进行判断,一旦满足某个条件,即通过自定义接口,通知Activity更新ImageView。但实验证明,当该条件满足时,ListView也并未显示完成。
而后,又通过多种方法,但都以失败告终。但最后,终于让我想到了。
之所以用"想到",而非"找到",可能是我太大意了,竟然忘了listView.setOnScrollListener监听器。该监听器主要包含两个方法: onScroll和onScrollStateChanged。
前者监听滚动事件,后者监听滚动状态改变事件。
其中,onScroll中有一个visibleItemCount参数,即可以通过它判断ListView是否显示完成,即visibleItemCount>0。
初级程序员很容易犯的一个错误就是,将onScroll方法误以为监听手指拖动。
实际上,除了手指拖动,该方法还包括监听系统自动滚动。故而,可以通过监听页面的系统滚动,实现监听ListView的显示完成事件。
好了,言归正传,下一步,也是最关键的一部,建立LruCache类缓存已加载过的图片,用于图片的二次加载。
当然,除了LruCache缓存,还可以通过弱引用SoftReference的方式异步加载图片。
但是网上有言,说从 Android 2.3 开始,垃圾回收器会更倾向于回收持有软引用或弱引用的对象,这让软引用和弱引用变得不再可靠。
同时,Android 3.0 中,图片的数据会存储在本地的内存当中,因而无法用一种可预见的方式将其释放,这就有潜在的风险造成应用程序的内存溢出并崩溃。
故而,此处采用LruCache方式来缓存图片。如果即将加载的图片在LruCache中有缓存,则直接从LruCache中读取,这大大提高了图片的加载效率。
最后,通过线程,将已加载的缩略图保存成缩略图文件,方便日后再次加载。
总结一下上述加载大量图片的思路流程:
1.判断LruCache中是否有该缩略图缓存,如果有,直接加载,如果没有,进入第二步。
2.判断自创建的缩略图文件夹中是否有该缩略图文件,如果有,加载,并将缩略图(非原图)存入LruCache中缓存,如果没有,进入第三步。
3.生成缩略图文件,存入自创建的缩略图文件夹,并将缩略图(非原图)存入LruCache中缓存,结束。
需要注意的小细节是:加载图片时,尽量不要从事耗时的操作,故此将生成缩略图文件的方法,放入线程中异步执行。
好了,测试证明,通过这种方法加载的图片列表,拖动起来顺滑而流畅,没有丝毫卡顿。
大功告成!
文章结束处,附上关键代码:
LruCacheBitmap:
(实现图片压缩并缓存)
[code]package com.example.pic;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Environment;
import android.view.View;
import android.widget.ImageView;
import com.example.model.Info;
public class LruCacheBitmap {
private android.util.LruCache lruCache;
private final static String THUMBNAIL = Environment
.getExternalStorageDirectory() + "/display/thumbnail/";
private static ArrayList IMG_SUFFIX = new ArrayList();
static {
IMG_SUFFIX.add("jpg");
IMG_SUFFIX.add("JPG");
IMG_SUFFIX.add("png");
IMG_SUFFIX.add("PNG");
IMG_SUFFIX.add("bmp");
IMG_SUFFIX.add("BMP");
}
public LruCacheBitmap(android.util.LruCache lruCache) {
this.lruCache = lruCache;
}
private Bitmap getThumbnail(String path, int width, int height) {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(path, options);
options.inSampleSize = calculateInSampleSize(options, width, height);
options.inJustDecodeBounds = false;
Bitmap src = BitmapFactory.decodeFile(path, options);
Bitmap bitmap = createScaleBitmap(src, width, height);
return bitmap;
}
private static int calculateInSampleSize(BitmapFactory.Options options,
int reqWidth, int reqHeight) {
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
final int halfHeight = height / 2;
final int halfWidth = width / 2;
while ((halfHeight / inSampleSize) > reqHeight
&& (halfWidth / inSampleSize) > reqWidth) {
inSampleSize *= 2;
}
}
return inSampleSize;
}
private static Bitmap createScaleBitmap(Bitmap src, int dstWidth,
int dstHeight) {
Bitmap dst = Bitmap.createScaledBitmap(src, dstWidth, dstHeight, false);
if (src != dst) { // 如果没有缩放,那么不回收
src.recycle(); // 释放Bitmap的native像素数组
}
return dst;
}
private void addBitmapToLruCache(String path, Bitmap bitmap) {
if (getBitmapFromLruCache(path) == null) {
lruCache.put(path, bitmap);
}
}
private Bitmap getBitmapFromLruCache(String path) {
return lruCache.get(path);
}
public void setImageForImageView(String imagePath, ImageView imageView) {
Bitmap bitmap = getBitmapFromLruCache(imagePath);
if (bitmap != null) {
imageView.setImageBitmap(bitmap);
}
}
public void loadBitmaps(List infos, View view, int width, int height,
int firstVisibleItem, int visibleItemCount) {
try {
for (int i = firstVisibleItem; i < firstVisibleItem
+ visibleItemCount; i++) {
String name = infos.get(i).getName();
String path = infos.get(i).getPath();
boolean isDirectory = infos.get(i).getIsDirectory();
if ((!isDirectory)
&& (name.lastIndexOf(".") > 0)
&& (IMG_SUFFIX.contains(name.substring(name
.lastIndexOf(".") + 1)))) {
Bitmap bitmap = getBitmapFromLruCache(path);
if (bitmap == null) {
bitmap = readThumbnailFromFile(name);
if (bitmap == null) {
bitmap = getThumbnail(path, width, height);
final Bitmap copyBitmap = bitmap;
final String copyName = name;
new Thread() {
@Override
public void run() {
// TODO Auto-generated method stub
super.run();
saveThumbnailToFile(copyBitmap, copyName);
}
}.start();
}
addBitmapToLruCache(path, bitmap);
}
ImageView imageView = (ImageView) view
.findViewWithTag(path);
if (imageView != null && bitmap != null) {
imageView.setImageBitmap(bitmap);
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
private void saveThumbnailToFile(Bitmap bitmap, String name) {
File dir = new File(THUMBNAIL);
if (!dir.exists()) {
dir.mkdirs();
}
File file = new File(THUMBNAIL + name);
try {
BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(
new FileOutputStream(file));
bitmap.compress(Bitmap.CompressFormat.JPEG, 80,
bufferedOutputStream);
bufferedOutputStream.flush();
bufferedOutputStream.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private Bitmap readThumbnailFromFile(String name) {
File file = new File(THUMBNAIL + name);
// 若该文件存在
if (file.exists()) {
Bitmap bitmap = BitmapFactory.decodeFile(THUMBNAIL + name);
return bitmap;
}
return null;
}
}
[/code]
FileListViewAdapter:
(ListViewAdapter)
[code]package com.example.adapter;
import java.util.ArrayList;
import java.util.List;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import com.example.display.R;
import com.example.model.Info;
public class FileListViewAdapter extends BaseAdapter {
private List datas = new ArrayList();
private LayoutInflater layoutInflater;
private SetImage setImage;
private int[] logos = { R.drawable.unknow, R.drawable.jpg, R.drawable.png,
R.drawable.avi, R.drawable.doc, R.drawable.html, R.drawable.mp3,
R.drawable.pdf, R.drawable.ppt, R.drawable.rar, R.drawable.txt,
R.drawable.wav, R.drawable.zip };
enum Type {
FILE, DIRECTORY;
}
public FileListViewAdapter(Context context, List datas) {
super();
this.datas = datas;
setImage = (SetImage) context;
this.layoutInflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
@Override
public int getCount() {
if (datas != null && !datas.isEmpty())
return datas.size();
else
return 0;
}
@Override
public Info getItem(int position) {
return datas.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = convertView;
final ViewHolder holder;
if (convertView == null) {
view = layoutInflater.inflate(R.layout.item_list_file, null);
holder = new ViewHolder();
holder.imageViewFolder = (ImageView) view
.findViewById(R.id.imageViewFolder);
holder.textViewPathName = (TextView) view
.findViewById(R.id.textViewPathName);
holder.textViewNext = (TextView) view
.findViewById(R.id.textViewNext);
holder.imageViewThumbnail = (ImageView) view
.findViewById(R.id.imageViewThumbnail);
view.setTag(holder);
} else {
holder = (ViewHolder) view.getTag();
}
Info info = getItem(position);
String name = info.getName();
String path = info.getPath();
boolean isDirectory = info.getIsDirectory();
if (isDirectory) {
holder.imageViewFolder.setBackgroundResource(R.drawable.folder);
holder.textViewNext.setVisibility(View.VISIBLE);
holder.imageViewThumbnail.setVisibility(View.GONE);
} else {
String fileSuffix = getSuffix(name);
int index = 0;
switch (fileSuffix) {
case "jpg":
index = 1;
break;
case "png":
index = 2;
break;
case "avi":
index = 3;
break;
case "doc":
index = 4;
break;
case "html":
index = 5;
break;
case "mp3":
index = 6;
break;
case "pdf":
index = 7;
break;
case "ppt":
index = 8;
break;
case "rar":
index = 9;
break;
case "txt":
index = 10;
break;
case "wav":
index = 11;
break;
case "zip":
index = 12;
break;
default:
index = 0;
break;
}
if ((index == 1) || (index == 2)) {
holder.textViewNext.setVisibility(View.GONE);
holder.imageViewThumbnail.setVisibility(View.VISIBLE);
} else {
holder.textViewNext.setVisibility(View.INVISIBLE);
holder.imageViewThumbnail.setVisibility(View.GONE);
}
holder.imageViewFolder.setBackgroundResource(logos[index]);
}
holder.textViewPathName.setText(name);
holder.imageViewThumbnail.setTag(path);
setImage.setImage(path, holder.imageViewThumbnail);
return view;
}
private class ViewHolder {
private ImageView imageViewFolder;
private TextView textViewPathName;
private TextView textViewNext;
private ImageView imageViewThumbnail;
}
private String getSuffix(String name) {
if (name.lastIndexOf(".") < 0) // Don't have the suffix
return "";
String fileSuffix = name.substring(name.lastIndexOf(".") + 1);
return fileSuffix;
}
public interface SetImage {
public void setImage(String path, ImageView imageView);
}
}
[/code]
原创,转载请注明出处 :o
最近,在做一个导览系统,主要功能是为游人提供馆内各层的导览图,方便人们参观。
项目刚开始,一切都有条不紊的进行。由于接触过几个这方面的项目,因此进行起来还算顺利。
然而,项目进行过程中,确实遇到了问题:OOM-内存溢出
有经验的工程师会立即想到BUG的源头:图片尺寸过大或加载数量过多
本项目开发过程中,多次出现该问题,具体细节及解决方法如下:
1.主界面
对于此处的OOM,我采取了一个较为规避的方法,将原定计划的ImageView+GestureDetector改为WebView。
经过修改,不仅解决了OOM问题,还使得手势操作较GestureDetector更为灵敏,流畅,毕竟是采用了WebView内置的Zoom工具,效果就是不一样。然而同样存在一个问题,即WebView加载过程中,会出现短暂的空白期,但相对于原定计划,该瑕疵可以忽略。
2.管理员界面
此处需要同时加载两张图片,若加载图片过大,会报OOM错误。即使选取图片尺寸较小,也会感到很明显的卡顿现象。这极大的影响了用户的交互体验。对于此处OOM问题,我采取的措施是加载缩略图。
加载缩略图,目前主要有两种方式:
1.通过ThumbnailUtils工具类直接创建缩略图:
newBitmap = ThumbnailUtils.extractThumbnail(oldBitmap, width, height);
2.利用Option属性压缩图片生成缩略图:
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
Bitmap bitmap = BitmapFactory.decodeFile(path, options);
options.inSampleSize = scale; //缩放倍数
options.inJustDecodeBounds = false;
bitmap = BitmapFactory.decodeFile(path, options);
ThumbnailUtils是Android 2.2版本中,新增的一个用于实现缩略图的工具类,此工具类功能强大,利用内置的常数和方法,可以轻松快捷的实现图片和视频的缩略图功能。
对于这两种方式,我都尝试了一遍。相比较而言,第二种方式加载图片缩略图更快,故此处采用第二种方式。
3.文件浏览
此处需要同时显示同一文件夹下的所有图片文件的缩略图,然后以列表的形式显示在ItemView中。对于此类需要同时加载多张图片的场合,通常采用异步方式进行。
异步加载图片缩略图可以通过AsyncLoadedImage类实现。
AsyncLoadedImage类继承AsyncTask异步加载类,通过调用publishProgress方法更新onProgressUpdate贮存缩略图信息到Adapter,通过监听Adapter Change实现异步加载缩略图。
然而,经过测试,发现通过这种方法加载图片效果效果并不理想。因此,我采取了另外一种方式。
首先,在ListView Adapter中,禁止ItemView中的ImageView控件的图片加载。如果在此Adapter中getView方法内加载图片,会导致图片的重复加载。
因为getView方法是用于获取将要显示的View,即每滑动一次,就会加载一次图片,对于已经加载过的,是无法保存的。
其次,将列表改为可上拉加载的,这样在显示刷新页面的footView时,可以进行数据的更新及图片的显示。
由于将setImage放在了Adapter外,故而此时加载的图片是可以保存的,是不随getView而实时动态重复加载的。
然而,此处调试过程中,发现了一个致命的逻辑错误。
由于我是在更新数据的同时加载ImageView的,此时父View-ListView尚未生成,即listView并未执行getView方法,故而无法通过子View-ItemView获取控件ImageView的ID。
而我想要的效果是,更新完数据后,同时加载图片,最后通过ListView显示出来。
很明显,这陷入了逻辑循环悖论之中。即若要加载A View,必须先加载B View,而若要加载B View,又必须先加载A View。
因而,该效果最后被否定。只有先获得ListView,然后通过getChildAt方法获得ItemView,最终获得ImageView的ID。
可是,又有一个问题随之而生,即何时更新ImageView。很显然,必须ListView一被显示,即执行Update方法更新ImageView。那么,问题来了,如何监听ListView显示完成?
由于开发经验不深,在我的印象中,貌似ListView并没有该listener-onCreateView。
最初设想是通过在getView中进行判断,一旦满足某个条件,即通过自定义接口,通知Activity更新ImageView。但实验证明,当该条件满足时,ListView也并未显示完成。
而后,又通过多种方法,但都以失败告终。但最后,终于让我想到了。
之所以用"想到",而非"找到",可能是我太大意了,竟然忘了listView.setOnScrollListener监听器。该监听器主要包含两个方法: onScroll和onScrollStateChanged。
前者监听滚动事件,后者监听滚动状态改变事件。
其中,onScroll中有一个visibleItemCount参数,即可以通过它判断ListView是否显示完成,即visibleItemCount>0。
初级程序员很容易犯的一个错误就是,将onScroll方法误以为监听手指拖动。
实际上,除了手指拖动,该方法还包括监听系统自动滚动。故而,可以通过监听页面的系统滚动,实现监听ListView的显示完成事件。
好了,言归正传,下一步,也是最关键的一部,建立LruCache类缓存已加载过的图片,用于图片的二次加载。
当然,除了LruCache缓存,还可以通过弱引用SoftReference的方式异步加载图片。
但是网上有言,说从 Android 2.3 开始,垃圾回收器会更倾向于回收持有软引用或弱引用的对象,这让软引用和弱引用变得不再可靠。
同时,Android 3.0 中,图片的数据会存储在本地的内存当中,因而无法用一种可预见的方式将其释放,这就有潜在的风险造成应用程序的内存溢出并崩溃。
故而,此处采用LruCache方式来缓存图片。如果即将加载的图片在LruCache中有缓存,则直接从LruCache中读取,这大大提高了图片的加载效率。
最后,通过线程,将已加载的缩略图保存成缩略图文件,方便日后再次加载。
总结一下上述加载大量图片的思路流程:
1.判断LruCache中是否有该缩略图缓存,如果有,直接加载,如果没有,进入第二步。
2.判断自创建的缩略图文件夹中是否有该缩略图文件,如果有,加载,并将缩略图(非原图)存入LruCache中缓存,如果没有,进入第三步。
3.生成缩略图文件,存入自创建的缩略图文件夹,并将缩略图(非原图)存入LruCache中缓存,结束。
需要注意的小细节是:加载图片时,尽量不要从事耗时的操作,故此将生成缩略图文件的方法,放入线程中异步执行。
好了,测试证明,通过这种方法加载的图片列表,拖动起来顺滑而流畅,没有丝毫卡顿。
大功告成!
文章结束处,附上关键代码:
LruCacheBitmap:
(实现图片压缩并缓存)
[code]package com.example.pic;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Environment;
import android.view.View;
import android.widget.ImageView;
import com.example.model.Info;
public class LruCacheBitmap {
private android.util.LruCache
private final static String THUMBNAIL = Environment
.getExternalStorageDirectory() + "/display/thumbnail/";
private static ArrayList
static {
IMG_SUFFIX.add("jpg");
IMG_SUFFIX.add("JPG");
IMG_SUFFIX.add("png");
IMG_SUFFIX.add("PNG");
IMG_SUFFIX.add("bmp");
IMG_SUFFIX.add("BMP");
}
public LruCacheBitmap(android.util.LruCache
this.lruCache = lruCache;
}
private Bitmap getThumbnail(String path, int width, int height) {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(path, options);
options.inSampleSize = calculateInSampleSize(options, width, height);
options.inJustDecodeBounds = false;
Bitmap src = BitmapFactory.decodeFile(path, options);
Bitmap bitmap = createScaleBitmap(src, width, height);
return bitmap;
}
private static int calculateInSampleSize(BitmapFactory.Options options,
int reqWidth, int reqHeight) {
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
final int halfHeight = height / 2;
final int halfWidth = width / 2;
while ((halfHeight / inSampleSize) > reqHeight
&& (halfWidth / inSampleSize) > reqWidth) {
inSampleSize *= 2;
}
}
return inSampleSize;
}
private static Bitmap createScaleBitmap(Bitmap src, int dstWidth,
int dstHeight) {
Bitmap dst = Bitmap.createScaledBitmap(src, dstWidth, dstHeight, false);
if (src != dst) { // 如果没有缩放,那么不回收
src.recycle(); // 释放Bitmap的native像素数组
}
return dst;
}
private void addBitmapToLruCache(String path, Bitmap bitmap) {
if (getBitmapFromLruCache(path) == null) {
lruCache.put(path, bitmap);
}
}
private Bitmap getBitmapFromLruCache(String path) {
return lruCache.get(path);
}
public void setImageForImageView(String imagePath, ImageView imageView) {
Bitmap bitmap = getBitmapFromLruCache(imagePath);
if (bitmap != null) {
imageView.setImageBitmap(bitmap);
}
}
public void loadBitmaps(List
int firstVisibleItem, int visibleItemCount) {
try {
for (int i = firstVisibleItem; i < firstVisibleItem
+ visibleItemCount; i++) {
String name = infos.get(i).getName();
String path = infos.get(i).getPath();
boolean isDirectory = infos.get(i).getIsDirectory();
if ((!isDirectory)
&& (name.lastIndexOf(".") > 0)
&& (IMG_SUFFIX.contains(name.substring(name
.lastIndexOf(".") + 1)))) {
Bitmap bitmap = getBitmapFromLruCache(path);
if (bitmap == null) {
bitmap = readThumbnailFromFile(name);
if (bitmap == null) {
bitmap = getThumbnail(path, width, height);
final Bitmap copyBitmap = bitmap;
final String copyName = name;
new Thread() {
@Override
public void run() {
// TODO Auto-generated method stub
super.run();
saveThumbnailToFile(copyBitmap, copyName);
}
}.start();
}
addBitmapToLruCache(path, bitmap);
}
ImageView imageView = (ImageView) view
.findViewWithTag(path);
if (imageView != null && bitmap != null) {
imageView.setImageBitmap(bitmap);
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
private void saveThumbnailToFile(Bitmap bitmap, String name) {
File dir = new File(THUMBNAIL);
if (!dir.exists()) {
dir.mkdirs();
}
File file = new File(THUMBNAIL + name);
try {
BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(
new FileOutputStream(file));
bitmap.compress(Bitmap.CompressFormat.JPEG, 80,
bufferedOutputStream);
bufferedOutputStream.flush();
bufferedOutputStream.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private Bitmap readThumbnailFromFile(String name) {
File file = new File(THUMBNAIL + name);
// 若该文件存在
if (file.exists()) {
Bitmap bitmap = BitmapFactory.decodeFile(THUMBNAIL + name);
return bitmap;
}
return null;
}
}
[/code]
FileListViewAdapter:
(ListViewAdapter)
[code]package com.example.adapter;
import java.util.ArrayList;
import java.util.List;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import com.example.display.R;
import com.example.model.Info;
public class FileListViewAdapter extends BaseAdapter {
private List
private LayoutInflater layoutInflater;
private SetImage setImage;
private int[] logos = { R.drawable.unknow, R.drawable.jpg, R.drawable.png,
R.drawable.avi, R.drawable.doc, R.drawable.html, R.drawable.mp3,
R.drawable.pdf, R.drawable.ppt, R.drawable.rar, R.drawable.txt,
R.drawable.wav, R.drawable.zip };
enum Type {
FILE, DIRECTORY;
}
public FileListViewAdapter(Context context, List
super();
this.datas = datas;
setImage = (SetImage) context;
this.layoutInflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
@Override
public int getCount() {
if (datas != null && !datas.isEmpty())
return datas.size();
else
return 0;
}
@Override
public Info getItem(int position) {
return datas.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = convertView;
final ViewHolder holder;
if (convertView == null) {
view = layoutInflater.inflate(R.layout.item_list_file, null);
holder = new ViewHolder();
holder.imageViewFolder = (ImageView) view
.findViewById(R.id.imageViewFolder);
holder.textViewPathName = (TextView) view
.findViewById(R.id.textViewPathName);
holder.textViewNext = (TextView) view
.findViewById(R.id.textViewNext);
holder.imageViewThumbnail = (ImageView) view
.findViewById(R.id.imageViewThumbnail);
view.setTag(holder);
} else {
holder = (ViewHolder) view.getTag();
}
Info info = getItem(position);
String name = info.getName();
String path = info.getPath();
boolean isDirectory = info.getIsDirectory();
if (isDirectory) {
holder.imageViewFolder.setBackgroundResource(R.drawable.folder);
holder.textViewNext.setVisibility(View.VISIBLE);
holder.imageViewThumbnail.setVisibility(View.GONE);
} else {
String fileSuffix = getSuffix(name);
int index = 0;
switch (fileSuffix) {
case "jpg":
index = 1;
break;
case "png":
index = 2;
break;
case "avi":
index = 3;
break;
case "doc":
index = 4;
break;
case "html":
index = 5;
break;
case "mp3":
index = 6;
break;
case "pdf":
index = 7;
break;
case "ppt":
index = 8;
break;
case "rar":
index = 9;
break;
case "txt":
index = 10;
break;
case "wav":
index = 11;
break;
case "zip":
index = 12;
break;
default:
index = 0;
break;
}
if ((index == 1) || (index == 2)) {
holder.textViewNext.setVisibility(View.GONE);
holder.imageViewThumbnail.setVisibility(View.VISIBLE);
} else {
holder.textViewNext.setVisibility(View.INVISIBLE);
holder.imageViewThumbnail.setVisibility(View.GONE);
}
holder.imageViewFolder.setBackgroundResource(logos[index]);
}
holder.textViewPathName.setText(name);
holder.imageViewThumbnail.setTag(path);
setImage.setImage(path, holder.imageViewThumbnail);
return view;
}
private class ViewHolder {
private ImageView imageViewFolder;
private TextView textViewPathName;
private TextView textViewNext;
private ImageView imageViewThumbnail;
}
private String getSuffix(String name) {
if (name.lastIndexOf(".") < 0) // Don't have the suffix
return "";
String fileSuffix = name.substring(name.lastIndexOf(".") + 1);
return fileSuffix;
}
public interface SetImage {
public void setImage(String path, ImageView imageView);
}
}
[/code]
原创,转载请注明出处 :o
我来回答
回答2个
时间排序
认可量排序
认可0
认可0
或将文件直接拖到这里
悬赏:
E币
网盘
* 网盘链接:
* 提取码:
悬赏:
E币
Markdown 语法
- 加粗**内容**
- 斜体*内容*
- 删除线~~内容~~
- 引用> 引用内容
- 代码`代码`
- 代码块```编程语言↵代码```
- 链接[链接标题](url)
- 无序列表- 内容
- 有序列表1. 内容
- 缩进内容
- 图片![alt](url)
相关问答
-
2019-06-27 21:06:09
-
2019-06-27 21:06:47
-
2016-10-08 13:46:43
-
2016-11-04 14:59:53
-
2018-02-01 16:04:14
-
02020-03-16 10:52:39
-
2016-11-04 16:28:11
-
2019-12-30 10:55:38
-
2016-08-15 14:12:16
-
2019-01-10 16:05:45
-
2013-06-21 15:14:35
-
2020-07-27 14:28:15
-
2019-01-15 17:02:52
-
2017-07-22 16:55:47
-
2019-01-03 14:44:34
-
2015-08-21 13:17:25
-
2024-02-25 18:06:35
-
2018-07-10 17:27:29
-
2020-03-31 21:06:08
无更多相似问答 去提问
点击登录
-- 积分
-- E币
提问
—
收益
—
被采纳
—
我要提问
切换马甲
上一页
下一页
悬赏问答
-
50如何获取vpss chn的图像修改后发送至vo
-
5FPGA通过Bt1120传YUV422数据过来,vi接收不到数据——3516dv500
-
50SS928 运行PQtools 拼接 推到设备里有一半画面会异常
-
53536AV100的sample_vdec输出到CVBS显示
-
10海思板子mpp怎么在vi阶段改变视频数据尺寸
-
10HI3559AV100 多摄像头同步模式
-
9海思ss928单路摄像头vio中加入opencv处理并显示
-
10EB-RV1126-BC-191板子运行自己编码的程序
-
10求HI3519DV500_SDK_V2.0.1.1
-
5有偿求HI3516DV500 + OV5647驱动
举报反馈
举报类型
- 内容涉黄/赌/毒
- 内容侵权/抄袭
- 政治相关
- 涉嫌广告
- 侮辱谩骂
- 其他
详细说明
提醒
你的问题还没有最佳答案,是否结题,结题后将扣除20%的悬赏金
取消
确认
提醒
你的问题还没有最佳答案,是否结题,结题后将根据回答情况扣除相应悬赏金(1回答=1E币)
取消
确认