首先我要说的是,我有一个非常不寻常的图像来源。我正在获取需要从mp3文件上的ID3标签加载的位图。
每当我加载封面并将其保存到SD存储空间时,我都会得到lagg。奇怪的是,所有加载和保存都发生在后台线程上,所以它不应该影响UI线程。 +我一次只运行一个操作,但仍然滞后。
一旦我将所有图像保存到磁盘,我构建了一个包含所保存文件的所有路径名的数组,它像黄油一样滚动,所有图像加载没有任何延迟。所以问题显然是对SD的缓存,这在UI线程上没有发生。 (我可能错了,所以这就是你们进来的地方)从文件加载的图像是使用Universal Image Loader btw完成的,但这不会导致任何问题:)
以下是我的代码片段,用于存储封面图片:
public ExecutorService executor = Executors.newFixedThreadPool(1);
//this is where I schedule tasks for all mp3 files to be executed using the threadpool,
//it is interrupted as soon as the user interacts with the listview (which should not be
//nessecary as it is not running any code on the UI thread)
public void preloadImages(){
for(int i = 0; i < items.length; i++){
if(scrolling){
return;
}
if(items[i].type.equalsIgnoreCase("music") && imagePathArray[i] == null){
ImageRunnable imgr = new ImageRunnable(items[i].pathname, null, i);
executor.execute(imgr);
}
if(scrolling){
return;
}
}
}
自定义runnable
//the custom runnable used to call the getCover method on separate thread
private class ImageRunnable implements Runnable {
private String url;
private final WeakReference<ImageView> imageViewReference;
private boolean running = true;
private int position;
public ImageRunnable(String path, ImageView img, int pos) {
url = path;
imageViewReference = new WeakReference<ImageView>(img);
position = pos;
}
public void terminate() {
running = false;
}
@Override
public void run() {
android.os.Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
final String coverPath = getCover(url, position);
}
}
getcover方法
private String getCover(String filepath, boolean refresh, int pos){
Log.d(LOG_TAG, "BEGIN function");
File file = new File(filepath);
Log.d(LOG_TAG, "File read");
MusicMetadataSet meta = null;
try {
meta = new MyID3().read(file);
Log.d(LOG_TAG, "id3 read");
} catch (IOException e) {
Log.d(LOG_TAG, "error reading id3 tag of file");
return null;
}
if(meta != null) {
try {
MusicMetadata metasimple = (MusicMetadata) meta.getSimplified();
Log.d(LOG_TAG, "simplified");
int length = filepath.length();
String albumname = filepath.substring(length-15, length-5).replaceAll("[^a-zA-Z0-9.-]", "_");
String path = Environment.getExternalStorageDirectory().toString();
OutputStream fOut = null;
Log.d(LOG_TAG, "album string");
File fileo = new File(path, "id3tag/"+albumname+"_icon.jpg");
Log.d(LOG_TAG, "file created");
File dir = new File(path, "id3tag/");
if(!dir.isDirectory()){
dir.mkdirs();
}
if(!fileo.exists() || refresh){
try {
fileo.createNewFile();
fOut = new FileOutputStream(fileo);
Vector<ImageData> fileList = metasimple.getPictureList();
Log.d(LOG_TAG, "got pic list");
ImageData data = fileList.lastElement();
if(fileList.size() == 0){
imagePathArray[pos] = "error";
return imagePathArray[pos];
}
byte[] rawimage = data.imageData;
Log.d(LOG_TAG, "got raw");
Bitmap bitmap = BitmapFactory.decodeByteArray(rawimage, 0, rawimage.length);
Log.d(LOG_TAG, "decoded bmp");
bitmap = bitmap.createScaledBitmap(bitmap, 64, 64, false);
Log.d(LOG_TAG, "scaled bmp");
bitmap.compress(Bitmap.CompressFormat.PNG, 100, fOut);
Log.d(LOG_TAG, "compr bmp");
fOut.flush();
fOut.close();
bitmap.recycle();
Log.d(LOG_TAG, "recycled");
meta = null;
rawimage = null;
fileList = null;
options = null;
metasimple = null;
bitmap = null;
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
imagePathArray[pos] = Uri.decode(fileo.toURI().toString().replace("file:/", "file:///"));
return imagePathArray[pos];
}catch (NoSuchElementException e){
return null;
}
}
return null;
}
答案 0 :(得分:0)
我目前正在处理同样的问题。
对我来说,它似乎是多个GC调用,它会暂停所有线程,包括UI线程,以便找到可以释放的资源!
检查您的LogCat消息以确认,查找标记为dalvikm
答案 1 :(得分:0)
尽量减少新位图的分配。首先,您可以制作一个64x64的位图并在其中绘制而不是使用creatScaledBitmap。
其次,你可以通过BitmapFactory.Options将它传递给decodeByteArray来重用位图进行解码
答案 2 :(得分:0)
好的我发现了这个问题,但还没有解决方法。谢谢大家帮助到目前为止!瓶颈似乎是对ID3对象的读操作。为什么以及如何阻止主线程我不知道,但我会尝试最小化该对象的使用情况,看看它在哪里引导我:)
执行此操作后,它只会落后于每个文件只发生一次的初始缓存,所以没什么大不了的。