From 23a6f76c37724595d3774fcc39f88065e2520b3e Mon Sep 17 00:00:00 2001 From: NoodleMage Date: Tue, 26 Jan 2016 13:26:41 +0100 Subject: [PATCH] Code optimization. Added javadoc. Removed setSize for it is not used Fixed some mistakes. Code optimization. Added comments. Few comment mistake fixes Few comments Added classes because of renaming Fixed refactor mistakes :(. typo + removed todo empty class Changed o to 0. Some renaming. Checked for nullability on string.isEmpty() function to prevent crashes Removed redundant null check Update ChapterCache.java Another o to 0 change. Damn this .o! :) --- .../tachiyomi/data/cache/ChapterCache.java | 121 ++++++++++++-- .../tachiyomi/data/cache/CoverCache.java | 148 +++++++++++++++--- .../data/cache/CoverGlideModule.java | 10 +- .../tachiyomi/ui/library/LibraryHolder.java | 2 +- .../ui/manga/info/MangaInfoFragment.java | 2 +- .../ui/manga/info/MangaInfoPresenter.java | 19 +-- .../ui/setting/SettingsAdvancedFragment.java | 2 +- 7 files changed, 256 insertions(+), 48 deletions(-) diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/cache/ChapterCache.java b/app/src/main/java/eu/kanade/tachiyomi/data/cache/ChapterCache.java index 9571c6020..3a4e8c150 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/cache/ChapterCache.java +++ b/app/src/main/java/eu/kanade/tachiyomi/data/cache/ChapterCache.java @@ -21,22 +21,46 @@ import okio.BufferedSink; import okio.Okio; import rx.Observable; +/** + * Class used to create chapter cache + * For each image in a chapter a file is created + * For each chapter a Json list is created and converted to a file. + * The files are in format *md5key*.0 + */ public class ChapterCache { + /** Name of cache directory. */ private static final String PARAMETER_CACHE_DIRECTORY = "chapter_disk_cache"; + + /** Application cache version. */ private static final int PARAMETER_APP_VERSION = 1; + + /** The number of values per cache entry. Must be positive. */ private static final int PARAMETER_VALUE_COUNT = 1; + + /** The maximum number of bytes this cache should use to store. */ private static final int PARAMETER_CACHE_SIZE = 75 * 1024 * 1024; - private Context context; - private Gson gson; + /** Interface to global information about an application environment. */ + private final Context context; + /** Google Json class used for parsing json files. */ + private final Gson gson; + + /** Cache class used for cache management. */ private DiskLruCache diskCache; + /** + * Constructor of ChapterCache. + * @param context application environment interface. + */ public ChapterCache(Context context) { this.context = context; + + // Initialize Json handler. gson = new Gson(); + // Try to open cache in default cache directory. try { diskCache = DiskLruCache.open( new File(context.getCacheDir(), PARAMETER_CACHE_DIRECTORY), @@ -45,43 +69,67 @@ public class ChapterCache { PARAMETER_CACHE_SIZE ); } catch (IOException e) { - // Do Nothing. + // Do Nothing. TODO error handling. } } - public boolean remove(String file) { + /** + * Remove file from cache. + * @param file name of chapter file md5.0. + * @return false if file is journal or error else returns status of deletion. + */ + public boolean removeFileFromCache(String file) { + // Make sure we don't delete the journal file (keeps track of cache). if (file.equals("journal") || file.startsWith("journal.")) return false; try { + // Take dot(.) substring to get filename without the .0 at the end. String key = file.substring(0, file.lastIndexOf(".")); + // Remove file from cache. return diskCache.remove(key); } catch (IOException e) { return false; } } + /** + * Returns directory of cache. + * @return directory of cache. + */ public File getCacheDir() { return diskCache.getDirectory(); } - public long getRealSize() { + /** + * Returns real size of directory. + * @return real size of directory. + */ + private long getRealSize() { return DiskUtils.getDirectorySize(getCacheDir()); } + /** + * Returns real size of directory in human readable format. + * @return real size of directory. + */ public String getReadableSize() { return Formatter.formatFileSize(context, getRealSize()); } - public void setSize(int value) { - diskCache.setMaxSize(value * 1024 * 1024); - } - + /** + * Get page objects from cache. + * @param chapterUrl the url of the chapter. + * @return list of chapter pages. + */ public Observable> getPageUrlsFromDiskCache(final String chapterUrl) { return Observable.create(subscriber -> { try { + // Get list of pages from chapterUrl. List pages = getPageUrlsFromDiskCacheImpl(chapterUrl); + // Provides the Observer with a new item to observe. subscriber.onNext(pages); + // Notify the Observer that finished sending push-based notifications. subscriber.onCompleted(); } catch (Throwable e) { subscriber.onError(e); @@ -89,18 +137,31 @@ public class ChapterCache { }); } - private List getPageUrlsFromDiskCacheImpl(String chapterUrl) throws IOException { + /** + * Implementation of the getPageUrlsFromDiskCache() function + * @param chapterUrl the url of the chapter + * @return returns list of chapter pages + * @throws IOException does nothing atm + */ + private List getPageUrlsFromDiskCacheImpl(String chapterUrl) throws IOException /*TODO IOException never thrown*/ { + // Initialize snapshot (a snapshot of the values for an entry). DiskLruCache.Snapshot snapshot = null; + + // Initialize list of pages. List pages = null; try { + // Create md5 key and retrieve snapshot. String key = DiskUtils.hashKeyForDisk(chapterUrl); snapshot = diskCache.get(key); + + // Convert JSON string to list of objects. Type collectionType = new TypeToken>() {}.getType(); pages = gson.fromJson(snapshot.getString(0), collectionType); + } catch (IOException e) { - // Do Nothing. + // Do Nothing. //TODO error handling? } finally { if (snapshot != null) { snapshot.close(); @@ -109,18 +170,30 @@ public class ChapterCache { return pages; } + /** + * Add page urls to disk cache. + * @param chapterUrl the url of the chapter. + * @param pages list of chapter pages. + */ public void putPageUrlsToDiskCache(final String chapterUrl, final List pages) { + // Convert list of pages to json string. String cachedValue = gson.toJson(pages); + // Initialize the editor (edits the values for an entry). DiskLruCache.Editor editor = null; + + // Initialize OutputStream. OutputStream outputStream = null; + try { + // Get editor from md5 key. String key = DiskUtils.hashKeyForDisk(chapterUrl); editor = diskCache.edit(key); if (editor == null) { return; } + // Write chapter urls to cache. outputStream = new BufferedOutputStream(editor.newOutputStream(0)); outputStream.write(cachedValue.getBytes()); outputStream.flush(); @@ -128,7 +201,7 @@ public class ChapterCache { diskCache.flush(); editor.commit(); } catch (Exception e) { - // Do Nothing. + // Do Nothing. TODO error handling? } finally { if (editor != null) { editor.abortUnlessCommitted(); @@ -137,12 +210,17 @@ public class ChapterCache { try { outputStream.close(); } catch (IOException ignore) { - // Do Nothing. + // Do Nothing. TODO error handling? } } } } + /** + * Check if image is in cache. + * @param imageUrl url of image. + * @return true if in cache otherwise false. + */ public boolean isImageInCache(final String imageUrl) { try { return diskCache.get(DiskUtils.hashKeyForDisk(imageUrl)) != null; @@ -152,8 +230,14 @@ public class ChapterCache { return false; } + /** + * Get image path from url. + * @param imageUrl url of image. + * @return path of image. + */ public String getImagePath(final String imageUrl) { try { + // Get file from md5 key. String imageName = DiskUtils.hashKeyForDisk(imageUrl) + ".0"; File file = new File(diskCache.getDirectory(), imageName); return file.getCanonicalPath(); @@ -163,17 +247,28 @@ public class ChapterCache { return null; } + /** + * Add image to cache + * @param imageUrl url of image. + * @param response http response from page. + * @throws IOException image error. + */ public void putImageToDiskCache(final String imageUrl, final Response response) throws IOException { + // Initialize editor (edits the values for an entry). DiskLruCache.Editor editor = null; + + // Initialize BufferedSink (used for small writes). BufferedSink sink = null; try { + // Get editor from md5 key. String key = DiskUtils.hashKeyForDisk(imageUrl); editor = diskCache.edit(key); if (editor == null) { throw new IOException("Unable to edit key"); } + // Initialize OutputStream and write image. OutputStream outputStream = new BufferedOutputStream(editor.newOutputStream(0)); sink = Okio.buffer(Okio.sink(outputStream)); sink.writeAll(response.body().source()); diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/cache/CoverCache.java b/app/src/main/java/eu/kanade/tachiyomi/data/cache/CoverCache.java index 7f2697a37..e76bcf34d 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/cache/CoverCache.java +++ b/app/src/main/java/eu/kanade/tachiyomi/data/cache/CoverCache.java @@ -20,33 +20,78 @@ import java.io.OutputStream; import eu.kanade.tachiyomi.util.DiskUtils; +/** + * Class used to create cover cache + * Makes use of Glide(which can avoid repeating requests) for saving the file. + * It is not necessary to load the images to the cache. + * Names of files are created with the md5 of the thumbnailURL + */ public class CoverCache { + /** + * Name of cache directory. + */ private static final String PARAMETER_CACHE_DIRECTORY = "cover_disk_cache"; - private Context context; - private File cacheDir; + /** + * Interface to global information about an application environment. + */ + private final Context context; + /** + * Cache class used for cache management. + */ + private final File cacheDir; + + /** + * Constructor of CoverCache. + * + * @param context application environment interface. + */ public CoverCache(Context context) { this.context = context; + + // Get cache directory from parameter. cacheDir = new File(context.getCacheDir(), PARAMETER_CACHE_DIRECTORY); + + // Create cache directory. createCacheDir(); } + /** + * Check if cache dir exist if not create directory. + * + * @return true if cache dir does exist and is created. + */ private boolean createCacheDir() { return !cacheDir.exists() && cacheDir.mkdirs(); } + /** + * Download the cover with Glide (it can avoid repeating requests) and save the file. + * + * @param thumbnailUrl url of thumbnail. + * @param headers headers included in Glide request. + */ public void save(String thumbnailUrl, LazyHeaders headers) { save(thumbnailUrl, headers, null); } - // Download the cover with Glide (it can avoid repeating requests) and save the file on this cache - // Optionally, load the image in the given image view when the resource is ready, if not null - public void save(String thumbnailUrl, LazyHeaders headers, ImageView imageView) { + /** + * Download the cover with Glide (it can avoid repeating requests) and save the file. + * + * @param thumbnailUrl url of thumbnail. + * @param headers headers included in Glide request. + * @param imageView imageView where picture should be displayed. + */ + private void save(String thumbnailUrl, LazyHeaders headers, ImageView imageView) { + + // Check if url is empty. if (TextUtils.isEmpty(thumbnailUrl)) + // Do not try and create the string. Instead... only try to realize the truth. There is no string. return; + // Download the cover with Glide and save the file. GlideUrl url = new GlideUrl(thumbnailUrl, headers); Glide.with(context) .load(url) @@ -54,7 +99,10 @@ public class CoverCache { @Override public void onResourceReady(File resource, GlideAnimation anim) { try { - add(thumbnailUrl, resource); + // Copy the cover from Glide's cache to local cache. + copyToLocalCache(thumbnailUrl, resource); + + // Check if imageView isn't null and show picture in imageView. if (imageView != null) { loadFromCache(imageView, resource); } @@ -65,18 +113,32 @@ public class CoverCache { }); } - // Copy the cover from Glide's cache to this cache - public void add(String thumbnailUrl, File source) throws IOException { + + /** + * Copy the cover from Glide's cache to local cache. + * + * @param thumbnailUrl url of thumbnail. + * @param source the cover image. + * @throws IOException TODO not returned atm? + */ + private void copyToLocalCache(String thumbnailUrl, File source) throws IOException { + // Create cache directory and check if directory exist createCacheDir(); + + // Create destination file. File dest = new File(cacheDir, DiskUtils.hashKeyForDisk(thumbnailUrl)); + + + // Check if file already exists, if true delete it. if (dest.exists()) dest.delete(); + // Write thumbnail image to file. InputStream in = new FileInputStream(source); try { OutputStream out = new FileOutputStream(dest); try { - // Transfer bytes from in to out + // Transfer bytes from in to out. byte[] buf = new byte[1024]; int len; while ((len = in.read(buf)) > 0) { @@ -90,23 +152,43 @@ public class CoverCache { } } - // Get the cover from cache - public File get(String thumbnailUrl) { + + /** + * Returns the cover from cache. + * + * @param thumbnailUrl the thumbnail url. + * @return cover image. + */ + private File getCoverFromCache(String thumbnailUrl) { return new File(cacheDir, DiskUtils.hashKeyForDisk(thumbnailUrl)); } - // Delete the cover from cache - public boolean delete(String thumbnailUrl) { + /** + * Delete the cover file from the cache. + * + * @param thumbnailUrl the thumbnail url. + * @return status of deletion. + */ + public boolean deleteCoverFromCache(String thumbnailUrl) { + // Check if url is empty. if (TextUtils.isEmpty(thumbnailUrl)) return false; + // Remove file. File file = new File(cacheDir, DiskUtils.hashKeyForDisk(thumbnailUrl)); return file.exists() && file.delete(); } - // Save and load the image from cache - public void saveAndLoadFromCache(ImageView imageView, String thumbnailUrl, LazyHeaders headers) { - File localCover = get(thumbnailUrl); + /** + * Save or load the image from cache + * + * @param imageView imageView where picture should be displayed. + * @param thumbnailUrl the thumbnail url. + * @param headers headers included in Glide request. + */ + public void saveOrLoadFromCache(ImageView imageView, String thumbnailUrl, LazyHeaders headers) { + // If file exist load it otherwise save it. + File localCover = getCoverFromCache(thumbnailUrl); if (localCover.exists()) { loadFromCache(imageView, localCover); } else { @@ -114,9 +196,17 @@ public class CoverCache { } } - // If the image is already in our cache, use it. If not, load it with glide + /** + * If the image is already in our cache, use it. If not, load it with glide. + * TODO not used atm. + * + * @param imageView imageView where picture should be displayed. + * @param thumbnailUrl url of thumbnail. + * @param headers headers included in Glide request. + */ public void loadFromCacheOrNetwork(ImageView imageView, String thumbnailUrl, LazyHeaders headers) { - File localCover = get(thumbnailUrl); + // If localCover exist load it from cache otherwise load it from network. + File localCover = getCoverFromCache(thumbnailUrl); if (localCover.exists()) { loadFromCache(imageView, localCover); } else { @@ -124,8 +214,12 @@ public class CoverCache { } } - // Helper method to load the cover from the cache directory into the specified image view - // The file must exist + /** + * Helper method to load the cover from the cache directory into the specified image view. + * + * @param imageView imageView where picture should be displayed. + * @param file file to load. Must exist!. + */ private void loadFromCache(ImageView imageView, File file) { Glide.with(context) .load(file) @@ -134,9 +228,19 @@ public class CoverCache { .into(imageView); } - // Helper method to load the cover from network into the specified image view. - // It does NOT save the image in cache + /** + * Helper method to load the cover from network into the specified image view. + * It does NOT save the image in cache! + * + * @param imageView imageView where picture should be displayed. + * @param thumbnailUrl url of thumbnail. + * @param headers headers included in Glide request. + */ public void loadFromNetwork(ImageView imageView, String thumbnailUrl, LazyHeaders headers) { + // Check if url is empty. + if (TextUtils.isEmpty(thumbnailUrl)) + return; + GlideUrl url = new GlideUrl(thumbnailUrl, headers); Glide.with(context) .load(url) diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/cache/CoverGlideModule.java b/app/src/main/java/eu/kanade/tachiyomi/data/cache/CoverGlideModule.java index c94397bcd..e3613ed56 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/cache/CoverGlideModule.java +++ b/app/src/main/java/eu/kanade/tachiyomi/data/cache/CoverGlideModule.java @@ -7,8 +7,16 @@ import com.bumptech.glide.GlideBuilder; import com.bumptech.glide.load.DecodeFormat; import com.bumptech.glide.module.GlideModule; +/** + * Class used to update Glide module settings + */ public class CoverGlideModule implements GlideModule { + + /** + * Bitmaps decoded from most image formats (other than GIFs with hidden configs), will be decoded with the + * ARGB_8888 config. + */ @Override public void applyOptions(Context context, GlideBuilder builder) { builder.setDecodeFormat(DecodeFormat.PREFER_ARGB_8888); @@ -16,6 +24,6 @@ public class CoverGlideModule implements GlideModule { @Override public void registerComponents(Context context, Glide glide) { - + // Nothing to see here! } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryHolder.java b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryHolder.java index 525c176a3..d115758ee 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryHolder.java +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryHolder.java @@ -44,7 +44,7 @@ public class LibraryHolder extends FlexibleViewHolder { private void loadCover(Manga manga, Source source, CoverCache coverCache) { if (manga.thumbnail_url != null) { - coverCache.saveAndLoadFromCache(thumbnail, manga.thumbnail_url, source.getGlideHeaders()); + coverCache.saveOrLoadFromCache(thumbnail, manga.thumbnail_url, source.getGlideHeaders()); } else { thumbnail.setImageResource(android.R.color.transparent); } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/MangaInfoFragment.java b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/MangaInfoFragment.java index bee8651f4..033e8e7ce 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/MangaInfoFragment.java +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/MangaInfoFragment.java @@ -88,7 +88,7 @@ public class MangaInfoFragment extends BaseRxFragment { LazyHeaders headers = getPresenter().source.getGlideHeaders(); if (manga.thumbnail_url != null && cover.getDrawable() == null) { if (manga.favorite) { - coverCache.saveAndLoadFromCache(cover, manga.thumbnail_url, headers); + coverCache.saveOrLoadFromCache(cover, manga.thumbnail_url, headers); } else { coverCache.loadFromNetwork(cover, manga.thumbnail_url, headers); } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/MangaInfoPresenter.java b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/MangaInfoPresenter.java index ea69a76fc..bfeb251be 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/MangaInfoPresenter.java +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/MangaInfoPresenter.java @@ -19,17 +19,18 @@ import rx.schedulers.Schedulers; public class MangaInfoPresenter extends BasePresenter { - @Inject DatabaseHelper db; - @Inject SourceManager sourceManager; - @Inject CoverCache coverCache; - - private Manga manga; - protected Source source; - private int count = -1; - private static final int GET_MANGA = 1; private static final int GET_CHAPTER_COUNT = 2; private static final int FETCH_MANGA_INFO = 3; + protected Source source; + @Inject + DatabaseHelper db; + @Inject + SourceManager sourceManager; + @Inject + CoverCache coverCache; + private Manga manga; + private int count = -1; @Override protected void onCreate(Bundle savedState) { @@ -111,7 +112,7 @@ public class MangaInfoPresenter extends BasePresenter { if (isFavorite) { coverCache.save(manga.thumbnail_url, source.getGlideHeaders()); } else { - coverCache.delete(manga.thumbnail_url); + coverCache.deleteCoverFromCache(manga.thumbnail_url); } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsAdvancedFragment.java b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsAdvancedFragment.java index eb9318820..6feccd55b 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsAdvancedFragment.java +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsAdvancedFragment.java @@ -71,7 +71,7 @@ public class SettingsAdvancedFragment extends SettingsNestedFragment { subscriptions.add(Observable.defer(() -> Observable.from(files)) .concatMap(file -> { - if (chapterCache.remove(file.getName())) { + if (chapterCache.removeFileFromCache(file.getName())) { deletedFiles.incrementAndGet(); } return Observable.just(file);