This library has been deprecated. Please consider using square/picasso instead.
Extension of Android's ImageView that supports animated GIFs and includes a better density management.
Francesco Pontillo and Sebastiano Poggi
The ImageViewEx is an extension of the standard Android ImageView that fills in one of the biggest gaps in the standard ImageView: displaying animated GIFs.
The Android Framework Drawable class, in fact, only supports static GIFs. This View is able to receive a raw image in byte[] form, bypassing the standard Drawables handling and thus providing broader support.
The ImageViewEx also allows you to specify what has to be considered the default image density when loading images from raw data. Android defaults to considering mdpi as the baseline, but using setInDensity you can choose to change it to whatever value you like (we suggest to stick to standard abstracted density buckets like hdpi thou).
The following is a brief documentation of the classes, methods and views included in this library.
- Remote loading and caching of images
- Loading and Error Drawables
- Getting images from the Internet
- Handling network failures
- Maximum number of threads
- Example of use
This library requires Android API level 8 (Android 2.2) as minimum, and targets the Android API level 17.
You need to include in your destination project:
- JakeWharton/DiskLruCache library, used for caching on disk.
- foxykeep/DataDroid library, used for handling async operations.
- square/okhttp library, for a better connection management.
The Eclipse project included specifies this is a library project, although it provides two basic Activities for testing the extended ImageViews provided.
For your application, you need to include the permissions specified in the AndroidManifest of the library, which are:
android.permission.INTERNETfor getting images on the internetandroid.permission.ACCESS_NETWORK_STATEto monitor the network stateandroid.permission.WRITE_EXTERNAL_STORAGEfor making the cache access and write the SD card
The ImageViewExService service is also internally used by ImageViewNext for handling asynchronous operation. You need to declare this service in your AndroidManifest.xml:
<service android:name="net.frakbot.imageviewex.service.ImageViewExService"/>ImageViewEx is an extended ImageView that supports some additional methods for your every-day life.
The best thing about ImageViewEx is its automatic handling of animated GIF images starting from a simple byte[].
Simply call img.setSource(mGIF) and see your GIF animating. Note that there may be some issues under some conditions (see Known issues and workarounds).
What if you don't know if an image is a GIF or a regular one? No problem, simply call setSource and ImageViewEx will do the rest, displaying your image as a regular one or an animated GIF when necessary.
Accessory methods are:
void setFramesDuration(int duration)to set the duration, in milliseconds, of each frame during the GIF animation (it is the refresh period)void setFPS(float fps)to set the number of frames per second during the GIF animationboolean isPlaying()to know if your GIF is playingboolean canPlay()to know if your source set bysetSourcewas an animated GIF after allint getFramesDuration()to get the frame duration, in millisecondsfloat getFPS()to get the number of frames per second during the GIF animationvoid play()to start the GIF, if it hasn't started yet.void pause()to pause the GIF, if it has startedvoid stop()to stop playing the GIF, if it has started
As mentioned earlier, you may not want to animate some GIF under some conditions.
So we've provided you with a conditional method that gets triggered just before each animation begins, boolean canAnimate(). This method should be overridden by your custom implementation. By default, it always returns true. This method decides whether animations can be started for this instance of ImageViewEx.
If you don't want to have another class extending ImageViewEx and your canAnimate() returns the same value throughout your application, you can use the following
ImageViewNext.setCanAlwaysAnimate(false);to specify you never want to animate GIFs. If you don't set any value to setCanAlwaysAnimate, it defaults to true. The result you get by setting the value to false is that it will stop all animations, no matter what canAnimate() returns.
You can check the current behavior by calling the static boolean getCanAlwaysAnimate() method.
You can set a specific density to simulate for every instance of ImageViewEx by using the following methods:
static void setClassLevelDensity(int classLevelDensity)to set a specific density for every imagestatic void removeClassLevelDensity()to remove the class-level customizationstatic boolean isClassLevelDensitySet(), checks if a class-level density has been setstatic int getClassLevelDensity(), gets the set class-level density, or null if none has been set
You can even set a density for just one of your ImageViewExs:
void setDensity(int fixedDensity), to set the density for a particular instance ofImageViewExint getDensity(), gets the set density for a particular instance ofImageViewEx(an instance-level density has higher priority over a class-level density)void dontOverrideDensity(), restores the regular density of theImageViewEx
ImageViewEx is, after all, a regular ImageView, so you can go ahead and use its regular methods:
void setImageResource(int resId)void setImageDrawable(Drawable drawable)void setImageBitmap(Bitmap bm)- and so on.
// Disables animation, behaving like a regular ImageView,
// except you can still set byte[] as the source
ImageViewEx.setCanAlwaysAnimate(false);
// Sets a default density for all of the images in each ImageViewEx.
ImageViewEx.setClassLevelDensity(DisplayMetrics.DENSITY_MEDIUM);
// Sets a density for the img1 only.
// Changing the density after an object has been set will
// do nothing, you will have to re-set the object.
img1.setInDensity(DisplayMetrics.DENSITY_LOW);
img1.setSource(Converters.assetToByteArray(getAssets(), "image.png"));
img2.setSource(Converters.assetToByteArray(getAssets(), "animated_image.gif"));ImageViewExService is used by ImageViewNext, an extension of ImageViewEx that handles downloading, displaying and caching of images (and animated GIFs, of course).
ImageViewNext extends ImageViewEx, thus supporting all of its methods, plus some more.
ImageViewNext uses ImageViewExService and some DataDroid Operations to retrieve images from a two-level cache and the internet and set them into your ImageViewNext.
ImageViewNext takes care of instantiating the cache to some default values, which can be overridden/read by using the following static methods (pretty self-explanatory, read the JavaDoc for more information about them):
getMemCache()getDiskCache()getMemCacheSize()setMemCacheSize(int memCacheSize)getAppVersion()setAppVersion(int appVersion)getDiskCacheSize()setDiskCacheSize(int diskCacheSize)
ImageViewNext supports loading and error Drawables:
static void setClassLoadingDrawable(int classLoadingDrawableResId)sets aDrawablefor every instance ofImageViewNextfrom the resources to be displayed (and animated, if it's anAnimatedDrawable) as soon as the caching tells us there's no in-memory reference for the asked resource. If you have enabled a disk cache, thisDrawablewill be set before fetching the disk memory.void setLoadingDrawable(Drawable loadingDrawable)sets aDrawablefor the current instance ofImageViewNextfrom the resources to be displayed (and animated, if it's anAnimatedDrawable) as soon as the caching tells us there's no in-memory reference for the asked resource. If you have enabled a disk cache, thisDrawablewill be set before fetching the disk memory.static void setClassErrorDrawable(int classErrorDrawableResId)sets aDrawablefor every instance ofImageViewNextfrom the resources to be displayed (and animated, if it's anAnimatedDrawable) as soon as the RemoteLoader returns an error, not being able to retrieve the image.void setErrorDrawable(Drawable errorDrawable)sets aDrawablefor the current instance of ofImageViewNextfrom the resources to be displayed (and animated, if it's anAnimatedDrawable) as soon as the RemoteLoader returns an error, not being able to retrieve the image.Drawable getLoadingDrawable()returns theDrawableto be displayed while waiting for long-running operations.Drawable getErrorDrawable()returns theDrawableto be displayed in case of an error.
In order to get images from the Internet, simply call setUrl(String url) to start retrieving an image from the internet or the caches.
ImageViewNext can be overridden in order to do some custom operations in the following methods:
void onMemCacheHit(byte[] image)is called as soon as there's a memory cache hit for the requested URLvoid onMemCacheMiss()is called as soon as there's a memory cache miss for the requested URLvoid onDiskCacheHit(byte[] image)is called as soon as there's a disk cache hit for the requested URLvoid onDiskCacheMiss()is called as soon as there's a disk cache miss for the requested URLvoid onNetworkHit(byte[] image)is called as soon as there's a network hit for the requested URLvoid onNetworkMiss()is called as soon as there's a network miss for the requested URLvoid onMiss()is called when an error occurs or the resource can't be found anywherevoid onSuccess(byte[] image)is automatically called after the image has been retrieved
You should not worry about setting images, as this is handled by ImageViewNext itself , which by defaults sets the loading image when there's a memory miss (on onMemCacheMiss()), an error one in case of error (onMiss()) and the retrieved image in case of success (onSuccess(byte[] image)).
If you override ImageViewNext, always call the default implementation of these methods.
By default, starting from version 2.2.0, each ImageViewNext will listen to network availability changes and automatically retry and get the image from the Internet, if and only if the same instance failed to do so in the previous attempt.
If you want to override the default behavior you can use:
setClassAutoRetryFromNetwork(boolean classAutoRetryFromNetwork)to set a class-level behaviorsetAutoRetryFromNetwork(boolean autoRetryFromNetwork)to set an instance-specific behavior
To know what the current settings are in regards to auto retry, use:
isClassAutoRetryFromNetwork()to get the class-level settingisAutoRetryFromNetwork()to retrieve the instance-specific setting
Remember: the instance-specific setting has an higher priority than the class-level setting.
### Maximum number of threadsYou can set the maximum number of concurrent threads; threads are used to retrieve an image, given its URL, from the memory cache, the disk cache or the network.
Use ImageViewNext.setMaximumNumberOfThreads(THREAD_NUMBER) BEFORE any ImageViewNext object is instantiated (ideally, in your Application class), as calling this function again after an ImageViewNext has been instantiated will have no effect.
You can retrieve the maximum number of concurrent threads with ImageViewNext.getMaximumNumberOfThreads().
// Sets class-level loading/error Drawables
ImageViewNext.setClassErrorDrawable(R.drawable.error_thumb);
ImageViewNext.setClassLoadingDrawable(R.drawable.loading_spinner);
img1.setUrl("http://upload.wikimedia.org/wikipedia/commons/9/91/Cittadimatera1.jpg");
img2.setUrl("http://upload.wikimedia.org/wikipedia/commons/4/49/Basilicata_Matera1_tango7174.jpg");ImageViewExinternally uses an old Android Framework class, Movie, to parse animated GIFs. This ensures fast execution, since the Movie class internally relies on native code. Due to Movie being a legacy class, though, there are a few quirks.
Firstly, you can't have Movie working on an hardware-accelerated canvas in Honeycomb and newer versions of Android. The ImageViewEx thus automatically disables hardware acceleration by itself when it has to display a GIF image. One side effect is that hardware acceleration is "lost" forever on the View once turned off, so if you reuse the ImageViewEx and at some point you assign a GIF image to it, from that point onwards it won't be hardware accelerated anymore. That's a limitation Android itself imposes, so there's not much we can do about that. On the bright side, this only affects cases where hardware acceleration is available; even when software rendering is active, there's not a big performance hit thou.
The second issue is that Movie has serious issues on some emulator instances and some retail devices. This is most likely due to some broken code down at native (maybe in Skia) or video driver level. So not much we can do on this one either. On the bright side, we've provided a workaround, that is setting setCanAlwaysAnimate(false) on phones known to cause issues. You will lose animation support, but you don't need to get crazy trying to handle several layouts, some using ImageViews and some using ImageViewExes.
If you use this library, letting us know would make us proud. We do not ask for anything else.
## Version history- Updated
DiskLruCacheto 2.0.0.
- Enabled setting of maximum number of concurrent threads.
- Minor fixes and improvements.
- Speed improvements.
- Moved assets to the test project.
- Caching/async system completely rewritten.
- Several performance optimization.
- Few bugs fixed.
- Few bugs fixed.
- First release.
Released under the [MIT license](http://www.opensource.org/licenses/mit-license.php).
Copyright (c) 2011-2013 Francesco Pontillo and Sebastiano Poggi
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.