├── faster_animation.jar ├── libs └── android-support-v4.jar ├── res ├── drawable-xhdpi │ ├── anim_1.jpg │ ├── anim_2.jpg │ ├── anim_3.jpg │ ├── anim_4.jpg │ ├── anim_5.jpg │ ├── anim_6.jpg │ ├── anim_7.jpg │ ├── anim_8.jpg │ └── ic_launcher.png ├── values │ ├── strings.xml │ └── styles.xml ├── drawable-hdpi │ └── ic_launcher.png ├── drawable-mdpi │ └── ic_launcher.png ├── values-v11 │ └── styles.xml ├── values-v14 │ └── styles.xml └── layout │ └── activity_example.xml ├── project.properties ├── proguard-project.txt ├── AndroidManifest.xml ├── src └── com │ └── tigerlee │ └── libs │ ├── activity │ └── ExampleActivity.java │ └── FasterAnimationsContainer.java └── README.md /faster_animation.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tigerjj/FasterAnimationsContainer/HEAD/faster_animation.jar -------------------------------------------------------------------------------- /libs/android-support-v4.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tigerjj/FasterAnimationsContainer/HEAD/libs/android-support-v4.jar -------------------------------------------------------------------------------- /res/drawable-xhdpi/anim_1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tigerjj/FasterAnimationsContainer/HEAD/res/drawable-xhdpi/anim_1.jpg -------------------------------------------------------------------------------- /res/drawable-xhdpi/anim_2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tigerjj/FasterAnimationsContainer/HEAD/res/drawable-xhdpi/anim_2.jpg -------------------------------------------------------------------------------- /res/drawable-xhdpi/anim_3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tigerjj/FasterAnimationsContainer/HEAD/res/drawable-xhdpi/anim_3.jpg -------------------------------------------------------------------------------- /res/drawable-xhdpi/anim_4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tigerjj/FasterAnimationsContainer/HEAD/res/drawable-xhdpi/anim_4.jpg -------------------------------------------------------------------------------- /res/drawable-xhdpi/anim_5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tigerjj/FasterAnimationsContainer/HEAD/res/drawable-xhdpi/anim_5.jpg -------------------------------------------------------------------------------- /res/drawable-xhdpi/anim_6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tigerjj/FasterAnimationsContainer/HEAD/res/drawable-xhdpi/anim_6.jpg -------------------------------------------------------------------------------- /res/drawable-xhdpi/anim_7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tigerjj/FasterAnimationsContainer/HEAD/res/drawable-xhdpi/anim_7.jpg -------------------------------------------------------------------------------- /res/drawable-xhdpi/anim_8.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tigerjj/FasterAnimationsContainer/HEAD/res/drawable-xhdpi/anim_8.jpg -------------------------------------------------------------------------------- /res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | FasterAnimationsContainer 4 | 5 | 6 | -------------------------------------------------------------------------------- /res/drawable-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tigerjj/FasterAnimationsContainer/HEAD/res/drawable-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /res/drawable-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tigerjj/FasterAnimationsContainer/HEAD/res/drawable-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /res/drawable-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tigerjj/FasterAnimationsContainer/HEAD/res/drawable-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /res/values-v11/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /res/values-v14/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /res/layout/activity_example.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 13 | 14 | -------------------------------------------------------------------------------- /project.properties: -------------------------------------------------------------------------------- 1 | # This file is automatically generated by Android Tools. 2 | # Do not modify this file -- YOUR CHANGES WILL BE ERASED! 3 | # 4 | # This file must be checked in Version Control Systems. 5 | # 6 | # To customize properties used by the Ant build system edit 7 | # "ant.properties", and override values to adapt the script to your 8 | # project structure. 9 | # 10 | # To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home): 11 | #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt 12 | 13 | # Project target. 14 | target=android-19 15 | android.library=false 16 | -------------------------------------------------------------------------------- /res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 14 | 15 | 16 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /proguard-project.txt: -------------------------------------------------------------------------------- 1 | # To enable ProGuard in your project, edit project.properties 2 | # to define the proguard.config property as described in that file. 3 | # 4 | # Add project specific ProGuard rules here. 5 | # By default, the flags in this file are appended to flags specified 6 | # in ${sdk.dir}/tools/proguard/proguard-android.txt 7 | # You can edit the include path and order by changing the ProGuard 8 | # include property in project.properties. 9 | # 10 | # For more details, see 11 | # http://developer.android.com/guide/developing/tools/proguard.html 12 | 13 | # Add any project specific keep options here: 14 | 15 | # If your project uses WebView with JS, uncomment the following 16 | # and specify the fully qualified class name to the JavaScript interface 17 | # class: 18 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 19 | # public *; 20 | #} 21 | -------------------------------------------------------------------------------- /AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 5 | 6 | 9 | 10 | 15 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /src/com/tigerlee/libs/activity/ExampleActivity.java: -------------------------------------------------------------------------------- 1 | package com.tigerlee.libs.activity; 2 | 3 | import android.app.Activity; 4 | import android.os.Bundle; 5 | import android.widget.ImageView; 6 | 7 | import com.tigerlee.libs.FasterAnimationsContainer; 8 | import com.tigerlee.libs.R; 9 | 10 | public class ExampleActivity extends Activity { 11 | 12 | FasterAnimationsContainer mFasterAnimationsContainer; 13 | private static final int[] IMAGE_RESOURCES = { R.drawable.anim_1, 14 | R.drawable.anim_2, R.drawable.anim_3, R.drawable.anim_4, 15 | R.drawable.anim_5, R.drawable.anim_6, R.drawable.anim_7, 16 | R.drawable.anim_8 }; 17 | 18 | private static final int ANIMATION_INTERVAL = 500;// 200ms 19 | 20 | @Override 21 | protected void onCreate(Bundle savedInstanceState) { 22 | super.onCreate(savedInstanceState); 23 | setContentView(R.layout.activity_example); 24 | ImageView imageView = (ImageView) findViewById(R.id.imageview); 25 | mFasterAnimationsContainer = FasterAnimationsContainer 26 | .getInstance(imageView); 27 | mFasterAnimationsContainer.addAllFrames(IMAGE_RESOURCES, 28 | ANIMATION_INTERVAL); 29 | mFasterAnimationsContainer.start(); 30 | } 31 | 32 | @Override 33 | protected void onDestroy() { 34 | super.onDestroy(); 35 | mFasterAnimationsContainer.stop(); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | FasterAnimationsContainer 2 | ============================ 3 | FasterAnimationsContainer will help you to avoid from OutOfMemoryError. Android loads all the drawables at once, so animation with many frames causes this error. This class loads & sets and releases an image on background thread. 4 | 5 | Easy to implement 6 | ------------------- 7 | 8 | 9 | ```java 10 | public class ExampleActivity extends Activity { 11 | FasterAnimationsContainer mFasterAnimationsContainer; 12 | private static final int[] IMAGE_RESOURCES = { R.drawable.anim_1, 13 | R.drawable.anim_2, R.drawable.anim_3, R.drawable.anim_4, 14 | R.drawable.anim_5, R.drawable.anim_6, R.drawable.anim_7, 15 | R.drawable.anim_8 }; 16 | 17 | private static final int ANIMATION_INTERVAL = 500;// 500ms 18 | 19 | @Override 20 | protected void onCreate(Bundle savedInstanceState) { 21 | super.onCreate(savedInstanceState); 22 | setContentView(R.layout.activity_example); 23 | ImageView imageView = (ImageView) findViewById(R.id.imageview); 24 | mFasterAnimationsContainer = FasterAnimationsContainer 25 | .getInstance(imageView); 26 | mFasterAnimationsContainer.addAllFrames(IMAGE_RESOURCES, 27 | ANIMATION_INTERVAL); 28 | mFasterAnimationsContainer.start(); 29 | } 30 | 31 | @Override 32 | protected void onDestroy() { 33 | super.onDestroy(); 34 | mFasterAnimationsContainer.stop(); 35 | } 36 | } 37 | ``` 38 | -------------------------------------------------------------------------------- /src/com/tigerlee/libs/FasterAnimationsContainer.java: -------------------------------------------------------------------------------- 1 | package com.tigerlee.libs; 2 | 3 | 4 | import android.annotation.SuppressLint; 5 | import android.graphics.Bitmap; 6 | import android.graphics.BitmapFactory; 7 | import android.graphics.drawable.BitmapDrawable; 8 | import android.graphics.drawable.Drawable; 9 | import android.os.AsyncTask; 10 | import android.os.Build; 11 | import android.os.Handler; 12 | import android.widget.ImageView; 13 | 14 | import java.lang.ref.SoftReference; 15 | import java.util.ArrayList; 16 | 17 | 18 | public class FasterAnimationsContainer{ 19 | private class AnimationFrame{ 20 | private int mResourceId; 21 | private int mDuration; 22 | AnimationFrame(int resourceId, int duration){ 23 | mResourceId = resourceId; 24 | mDuration = duration; 25 | } 26 | public int getResourceId() { 27 | return mResourceId; 28 | } 29 | public int getDuration() { 30 | return mDuration; 31 | } 32 | } 33 | private ArrayList mAnimationFrames; // list for all frames of animation 34 | private int mIndex; // index of current frame 35 | 36 | private boolean mShouldRun; // true if the animation should continue running. Used to stop the animation 37 | private boolean mIsRunning; // true if the animation prevents starting the animation twice 38 | private SoftReference mSoftReferenceImageView; // Used to prevent holding ImageView when it should be dead. 39 | private Handler mHandler; // Handler to communication with UIThread 40 | 41 | private Bitmap mRecycleBitmap; //Bitmap can recycle by inBitmap is SDK Version >=11 42 | 43 | // Listeners 44 | private OnAnimationStoppedListener mOnAnimationStoppedListener; 45 | private OnAnimationFrameChangedListener mOnAnimationFrameChangedListener; 46 | 47 | private FasterAnimationsContainer(ImageView imageView) { 48 | init(imageView); 49 | }; 50 | 51 | // single instance procedures 52 | private static FasterAnimationsContainer sInstance; 53 | 54 | public static FasterAnimationsContainer getInstance(ImageView imageView) { 55 | if (sInstance == null) 56 | sInstance = new FasterAnimationsContainer(imageView); 57 | sInstance.mRecycleBitmap = null; 58 | return sInstance; 59 | } 60 | 61 | /** 62 | * initialize imageview and frames 63 | * @param imageView 64 | */ 65 | public void init(ImageView imageView){ 66 | mAnimationFrames = new ArrayList(); 67 | mSoftReferenceImageView = new SoftReference(imageView); 68 | 69 | mHandler = new Handler(); 70 | if(mIsRunning == true){ 71 | stop(); 72 | } 73 | 74 | mShouldRun = false; 75 | mIsRunning = false; 76 | 77 | mIndex = -1; 78 | } 79 | 80 | /** 81 | * add a frame of animation 82 | * @param index index of animation 83 | * @param resId resource id of drawable 84 | * @param interval milliseconds 85 | */ 86 | public void addFrame(int index, int resId, int interval){ 87 | mAnimationFrames.add(index, new AnimationFrame(resId, interval)); 88 | } 89 | 90 | /** 91 | * add a frame of animation 92 | * @param resId resource id of drawable 93 | * @param interval milliseconds 94 | */ 95 | public void addFrame(int resId, int interval){ 96 | mAnimationFrames.add(new AnimationFrame(resId, interval)); 97 | } 98 | 99 | /** 100 | * add all frames of animation 101 | * @param resId resource id of drawable 102 | * @param interval milliseconds 103 | */ 104 | public void addAllFrames(int[] resIds, int interval){ 105 | for(int resId : resIds){ 106 | mAnimationFrames.add(new AnimationFrame(resId, interval)); 107 | } 108 | } 109 | 110 | /** 111 | * remove a frame with index 112 | * @param index index of animation 113 | */ 114 | public void removeFrame(int index){ 115 | mAnimationFrames.remove(index); 116 | } 117 | 118 | /** 119 | * clear all frames 120 | */ 121 | public void removeAllFrames(){ 122 | mAnimationFrames.clear(); 123 | } 124 | 125 | /** 126 | * change a frame of animation 127 | * @param index index of animation 128 | * @param resId resource id of drawable 129 | * @param interval milliseconds 130 | */ 131 | public void replaceFrame(int index, int resId, int interval){ 132 | mAnimationFrames.set(index, new AnimationFrame(resId, interval)); 133 | } 134 | 135 | private AnimationFrame getNext() { 136 | mIndex++; 137 | if (mIndex >= mAnimationFrames.size()) 138 | mIndex = 0; 139 | return mAnimationFrames.get(mIndex); 140 | } 141 | 142 | /** 143 | * Listener of animation to detect stopped 144 | * 145 | */ 146 | public interface OnAnimationStoppedListener{ 147 | public void onAnimationStopped(); 148 | } 149 | 150 | /** 151 | * Listener of animation to get index 152 | * 153 | */ 154 | public interface OnAnimationFrameChangedListener{ 155 | public void onAnimationFrameChanged(int index); 156 | } 157 | 158 | 159 | /** 160 | * set a listener for OnAnimationStoppedListener 161 | * @param listener OnAnimationStoppedListener 162 | */ 163 | public void setOnAnimationStoppedListener(OnAnimationStoppedListener listener){ 164 | mOnAnimationStoppedListener = listener; 165 | } 166 | 167 | /** 168 | * set a listener for OnAnimationFrameChangedListener 169 | * @param listener OnAnimationFrameChangedListener 170 | */ 171 | public void setOnAnimationFrameChangedListener(OnAnimationFrameChangedListener listener){ 172 | mOnAnimationFrameChangedListener = listener; 173 | } 174 | 175 | /** 176 | * Starts the animation 177 | */ 178 | public synchronized void start() { 179 | mShouldRun = true; 180 | if (mIsRunning) 181 | return; 182 | mHandler.post(new FramesSequenceAnimation()); 183 | } 184 | 185 | /** 186 | * Stops the animation 187 | */ 188 | public synchronized void stop() { 189 | mShouldRun = false; 190 | } 191 | 192 | private class FramesSequenceAnimation implements Runnable{ 193 | 194 | @Override 195 | public void run() { 196 | ImageView imageView = mSoftReferenceImageView.get(); 197 | if (!mShouldRun || imageView == null) { 198 | mIsRunning = false; 199 | if (mOnAnimationStoppedListener != null) { 200 | mOnAnimationStoppedListener.onAnimationStopped(); 201 | } 202 | return; 203 | } 204 | mIsRunning = true; 205 | 206 | if (imageView.isShown()) { 207 | AnimationFrame frame = getNext(); 208 | GetImageDrawableTask task = new GetImageDrawableTask(imageView); 209 | task.execute(frame.getResourceId()); 210 | // TODO postDelayed after onPostExecute 211 | mHandler.postDelayed(this, frame.getDuration()); 212 | } 213 | } 214 | } 215 | 216 | private class GetImageDrawableTask extends AsyncTask{ 217 | 218 | private ImageView mImageView; 219 | 220 | public GetImageDrawableTask(ImageView imageView) { 221 | mImageView = imageView; 222 | } 223 | 224 | @SuppressLint("NewApi") 225 | @Override 226 | protected Drawable doInBackground(Integer... params) { 227 | if(Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB){ 228 | return mImageView.getContext().getResources().getDrawable(params[0]); 229 | } 230 | BitmapFactory.Options options = new BitmapFactory.Options(); 231 | options.inMutable = true; 232 | if (mRecycleBitmap != null) 233 | options.inBitmap = mRecycleBitmap; 234 | mRecycleBitmap = BitmapFactory.decodeResource(mImageView 235 | .getContext().getResources(), params[0], options); 236 | BitmapDrawable drawable = new BitmapDrawable(mImageView.getContext().getResources(),mRecycleBitmap); 237 | return drawable; 238 | } 239 | 240 | @Override 241 | protected void onPostExecute(Drawable result) { 242 | super.onPostExecute(result); 243 | if(result!=null) mImageView.setImageDrawable(result); 244 | if (mOnAnimationFrameChangedListener != null) 245 | mOnAnimationFrameChangedListener.onAnimationFrameChanged(mIndex); 246 | } 247 | 248 | } 249 | } 250 | --------------------------------------------------------------------------------