SkImageDecoder Factory在Downloaded映像上返回null

时间:2015-01-21 12:59:54

标签: java android

我正在使用自制的LruDiskCache构建应用程序以减少加载时间。 LruDiskCache下载文件(如果该文件尚不存在)并通过回调返回。我有一个非常奇怪的问题,第一张图像没有正确加载。这仅在活动第一次启动时发生。如果您打开相同的活动,则可以正确加载图像。

调试后我发现我收到以下调试信息:--- SkImageDecoder Factory returned null。我已经阅读了有关此问题的多个问题,但都涉及通过输入流下载图像,而我首先将图像下载到持久存储。

我的缓存类:

public class LruDiskCache {

private static final String LOGTAG = "LruDiskCache";

//Cache size
private final long cacheMaxSize;
private volatile long currentCacheSize;
public static final int DEFAULT_CACHE_SIZE_KB = 1024;
public static final int MINIMUM_CACHE_SIZE_KB = 128;

//Preferences
private final String cachePreferencesName;
private final String chachePreferencesSize = "cacheSize";
private final SharedPreferences cachePreferences;

//Lock
private final Object mDiskCacheLock = new Object();

//Cache Path
private final File cachePath;

//Initialisation
private boolean openingCache;

//Static variables
private static final long BYTES_IN_KB = 1024;


public LruDiskCache (Context c, String cacheName, int cacheMaxSizeKB){
    //Preferences
    cachePreferencesName = cacheName + "CachePreferences";
    cachePreferences = c.getSharedPreferences(cachePreferencesName, Context.MODE_PRIVATE);

    //Paths
    cachePath = new File(c.getFilesDir().getPath()+"/"+cacheName);

    //Cache size
    if(cacheMaxSizeKB < MINIMUM_CACHE_SIZE_KB){
        throw new IllegalArgumentException
                ("Invalid cache size, size must be bigger than "
                        + MINIMUM_CACHE_SIZE_KB + "kb.");
    }
    cacheMaxSize = cacheMaxSizeKB * BYTES_IN_KB;

    //Initialize
    openingCache = true;
    new InitializeCache().execute();
}

//PUBLIC METHODS

public synchronized void getRemoteFile(URL remoteFile, Callback c){
    if(openingCache){
        try {
            mDiskCacheLock.wait(1000);
        } catch (InterruptedException e) {
            c.onRequestedFileRetrieved(null, false);
        }
    }
    String path = createFilePath(remoteFile);
    File f = new File(path);
    if(f.exists() && f.isFile()){
        f.setLastModified(System.currentTimeMillis());
        c.onRequestedFileRetrieved(f, true);
    } else {
        new RemoteFileDownloadTask(remoteFile, f, c).execute();
    }
}

//PRIVATE METHODS

private String createFilePath(URL key){
    return cachePath + "/" + key.getHost() + key.getPath();
}

private synchronized void cleanUpCache(){
    long cacheSize = getDirSize(cachePath);
    int failedToDeleteCounter = 0;
    while(cacheSize > cacheMaxSize){
        File toDelete = getFirstRequestedFile(cachePath);
        Log.w("LruDiskCache", "File to be deleted: " + toDelete.getName() + ".");
        long toDeleteSize = toDelete.length();
        if(!toDelete.delete()){
            failedToDeleteCounter++;
        } else {
            Log.w("LruDiskCache", "Deleted file to clean cache.");
            cacheSize -= toDeleteSize;
        }
        if(failedToDeleteCounter > 100){
            Log.w("LruDiskCache", "Failed to clean cache, could not delete files.");
            break;
        }
    }
}

private File getFirstRequestedFile(File directory){
    File first = null;
    for(File f : directory.listFiles()){
        if(f.isFile()){
            if(first == null){
                first = f;
            } else {
                if(f.lastModified() < first.lastModified()){
                    first = f;
                }
            }
        } else if (f.isDirectory()) {
            File firstReqInDir = getFirstRequestedFile(f);
            if(first == null){
                first = firstReqInDir;
            } else if (firstReqInDir.lastModified() < first.lastModified()){
                first = firstReqInDir;
            }
        }
    }
    return first;
}

private long getDirSize(File dir) {
    long bytes = 0;
    for (File f : dir.listFiles()) {
        if (f.isDirectory()) {
            bytes += getDirSize(f);
        } else {
            bytes += f.length();
        }
    }
    return bytes;
}

//ASYNC TASKS

private class InitializeCache implements Runnable{

    public void execute(){
        new Thread(this).start();
    }

    @Override
    public void run() {
        synchronized (mDiskCacheLock) {
            Log.d("Initialize cache", "Starting init...");
            if (!cachePath.exists()) {
                if (!cachePath.mkdirs()) {
                    mDiskCacheLock.notifyAll();
                    openingCache = false;
                }
            }
            currentCacheSize = getDirSize(cachePath);
            Log.d("LruDiskCache", "Cache size: " + currentCacheSize / BYTES_IN_KB + "kb.");
            if(currentCacheSize > cacheMaxSize){
                cleanUpCache();
            }
            Log.d("Initialize cache", "Did init...");
            mDiskCacheLock.notifyAll();
            openingCache = false;
        }
    }
}

private class RemoteFileDownloadTask extends AsyncTask<Void, Void, File> {
    private final Callback c;
    private URL remoteFile;
    private File localFile;

    protected RemoteFileDownloadTask(URL remoteFile, File localFile, Callback c){
        this.c = c;
        this.remoteFile = remoteFile;
        this.localFile = localFile;
    }

    @Override
    protected File doInBackground(Void... params) {
        if(retrieveRemoteFile(remoteFile, localFile)){
            return localFile;
        } else {
            return null;
        }
    }

    @Override
    protected void onPostExecute(File file) {
        super.onPostExecute(file);
        currentCacheSize += file.length();
        if(currentCacheSize > cacheMaxSize){
            cleanUpCache();
        }
        c.onRequestedFileRetrieved(file, true);
    }

    public boolean retrieveRemoteFile(URL remote, File filePath) {
        try {
            if (filePath.exists() && filePath.isFile()) {
                return true;
            } else {
                if (!filePath.getParentFile().exists()) {
                    if (!filePath.getParentFile().mkdirs()) {
                        return false;
                    }
                }
            }
        } catch (Exception e){
            return false;
        }

        Log.w("LruDiskCache", "Created empty file: " + filePath.getPath());
        Log.w("LruDiskCache", "Downloading source from: " + remote.toString());


        try {
            FileOutputStream fos;
            InputStream is;
            BufferedInputStream bis;
            fos = new FileOutputStream(filePath);
            HttpURLConnection con = (HttpURLConnection) remote.openConnection();
            if(con.getResponseCode() != HttpURLConnection.HTTP_OK){
                Log.e("Receiver", "HTTP Response code is not OK");
                return false;
            }
            is = con.getInputStream();
            bis = new BufferedInputStream(is);
            while(bis.available() > 0){
                fos.write(bis.read());
            }
            bis.close();
            is.close();
            fos.close();
        } catch (Exception e) {
            return false;
        }
        Log.d("LruDiskCacheReceiver", filePath.getPath() + " received, " + filePath.length() + " bytes.");
        return true;
    }
}

//CALLBACK INTERFACE

public interface Callback{
    public abstract void onRequestedFileRetrieved(File f, boolean success);
}

}

这里的实现如下:

    URL emblemURL = new URL(data[position].getEmblemUrl());
    cache.getRemoteFile(emblemURL, new LruDiskCache.Callback() {
        @Override
        public void onRequestedFileRetrieved(File f, boolean success) {
            if (success && f.exists()) {
                Drawable bitmap = Drawable.createFromPath(f.getAbsolutePath());
                emblem.setImageDrawable(bitmap);
            }
        }
    });

感谢任何帮助。

0 个答案:

没有答案