Android播放图片类 效果跟帧动画类似 优化内容 防止多图片使用帧动画OOM异常
2020-02-06 03:59
1021 查看
首先,把代码放上来
[code]package imageframe; import android.annotation.Nullable; import android.annotation.TargetApi; import android.content.Context; import android.graphics.drawable.BitmapDrawable; import android.os.Build; //import android.support.annotation.Nullable; //import android.support.v4.view.ViewCompat; import android.util.AttributeSet; import android.view.View; /** * 序列帧解析分离,需要的时候只需要传入一个解析器即可 */ public class ImageFrameCustomView extends View { private ImageFrameHandler imageFrameHandler; public ImageFrameCustomView(Context context) { super(context); } public ImageFrameCustomView(Context context, @Nullable AttributeSet attrs) { super(context, attrs); } public ImageFrameCustomView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } @TargetApi(Build.VERSION_CODES.LOLLIPOP) public ImageFrameCustomView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); } @Override protected void onDetachedFromWindow() { if (imageFrameHandler != null) { imageFrameHandler.stop(); } super.onDetachedFromWindow(); } public void startImageFrame(final ImageFrameHandler imageFrameHandler) { if (this.imageFrameHandler == null) { this.imageFrameHandler = imageFrameHandler; } else { this.imageFrameHandler.stop(); this.imageFrameHandler = imageFrameHandler; } imageFrameHandler .setOnImageLoaderListener(new ImageFrameHandler.OnImageLoadListener() { @Override public void onImageLoad(BitmapDrawable drawable) { ImageFrameCustomView.this .setBackgroundDrawable(drawable); } @Override public void onPlayFinish() { } }); post(new Runnable() { @Override public void run() { imageFrameHandler.start(); } }); } @Nullable public ImageFrameHandler getImageFrameHandler() { return imageFrameHandler; } }
上面是控件类,在你所需的布局使用
[code]package imageframe; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.RawRes; import android.content.res.Resources; import android.graphics.drawable.BitmapDrawable; import android.os.Handler; import android.os.Looper; import android.os.Message; import android.os.SystemClock; import android.text.TextUtils; import java.io.File; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.ref.SoftReference; /** * 直接内置序列帧解析的View */ public class ImageFrameHandler implements WorkHandler.WorkMessageProxy { private Resources resources; private int[] resArray; private int width; private int height; private boolean isRunning; private final WorkHandler workHandler; private File[] files; private static final int FILE = 0; private static final int RES = 1; private int type; private boolean isOpenCache; @Retention(RetentionPolicy.SOURCE) @IntDef({FILE, RES}) public @interface Operation { } ImageFrameHandler(@Operation int type) { this.type = type; imageCache = new ImageCache(); workHandler = new WorkHandler(); } @Deprecated public ImageFrameHandler() { imageCache = new ImageCache(); workHandler = new WorkHandler(); } private ImageCache imageCache; private Handler handler = new Handler(Looper.getMainLooper()) { @Override public void handleMessage(Message msg) { if (onImageLoadListener != null) { onImageLoadListener.onImageLoad(bitmapDrawable); } switch (msg.what) { case RES: load((int[]) msg.obj); break; case FILE: load((File[]) msg.obj); break; } } }; private volatile float frameTime; private volatile int index = 0; private volatile BitmapDrawable bitmapDrawable; private OnImageLoadListener onImageLoadListener; private boolean loop; /** * load frame form file directory; * * @param width request width * @param height request height * @param fileDir file directory * @param fps The number of broadcast images per second * @param onPlayFinish finish callback */ @Deprecated public void loadImage(final String fileDir, int width, int height, int fps, OnImageLoadListener onPlayFinish) { if (!isRunning) { isRunning = true; this.width = width; this.height = height; loadImage(fileDir, fps, onPlayFinish); } } /** * load frame form file directory; * * @param fileDir file directory * @param fps The number of broadcast images per second * @param onPlayFinish finish callback */ @Deprecated public void loadImage(final String fileDir, int fps, OnImageLoadListener onPlayFinish) { if (!isRunning && !TextUtils.isEmpty(fileDir) && fps > 0) { isRunning = true; File dir = new File(fileDir); if (dir.exists() && dir.isDirectory()) { File[] files = dir.listFiles(); loadImage(files, width, height, fps, onPlayFinish); } } } /** * load frame form file files Array; * * @param width request width * @param height request height * @param files files Array * @param fps The number of broadcast images per second * @param onPlayFinish finish callback */ @Deprecated public void loadImage(final File[] files, int width, int height, int fps, OnImageLoadListener onPlayFinish) { if (!isRunning) { setImageFrame(files, width, height, fps, onPlayFinish); load(files); } } /** * load frame form file files Array; * * @param files files Array * @param fps The number of broadcast images per second * @param onPlayFinish finish callback */ @Deprecated public void loadImage(final File[] files, int fps, OnImageLoadListener onPlayFinish) { loadImage(files, width, height, fps, onPlayFinish); } private void setImageFrame(final File[] files, int width, int height, int fps, OnImageLoadListener onPlayFinish) { this.width = width; this.height = height; if (imageCache == null) { imageCache = new ImageCache(); } this.onImageLoadListener = onPlayFinish; frameTime = 1000f / fps + 0.5f; workHandler.addMessageProxy(this); this.files = files; } /** * load frame form file resources Array; * * @param resArray resources Array * @param width request width * @param height request height * @param fps The number of broadcast images per second * @param onPlayFinish finish callback */ @Deprecated public void loadImage(Resources resources, @RawRes int[] resArray, int width, int height, int fps, OnImageLoadListener onPlayFinish) { loadImage(resources, resArray, width, height, fps, onPlayFinish); } private void setImageFrame(Resources resources, @RawRes int[] resArray, int width, int height, int fps, OnImageLoadListener onPlayFinish) { this.width = width; this.height = height; this.resources = resources; if (imageCache == null) { imageCache = new ImageCache(); } this.onImageLoadListener = onPlayFinish; frameTime = 1000f / fps + 0.5f; workHandler.addMessageProxy(this); this.resArray = resArray; } /** * load frame form file resources Array; * * @param resArray resources Array * @param fps The number of broadcast images per second * @param onPlayFinish finish callback */ @Deprecated public void loadImage(Resources resources, @RawRes int[] resArray, int fps, OnImageLoadListener onPlayFinish) { if (!isRunning) { setImageFrame(resources, resArray, width, height, fps, onPlayFinish); load(resArray); } } /** * loop play frame * * @param loop true is loop */ public ImageFrameHandler setLoop(boolean loop) { if (!isRunning) { this.loop = loop; } return this; } /** * stop play frame */ public void stop() { workHandler.getHandler().removeCallbacksAndMessages(null); workHandler.removeMessageProxy(this); handler.removeCallbacksAndMessages(null); resources = null; isRunning = false; } /** * 鏂板鏂规硶 * 鏆傚仠 * stop play frame */ public void pause() { isRunning = false; workHandler.getHandler().removeCallbacksAndMessages(null); // workHandler.removeMessageProxy(this); handler.removeCallbacksAndMessages(null); } public void start() { if (!isRunning) { isRunning = true; switch (type) { case FILE: load(files); break; case RES: load(resArray); break; } } } private void load(final File[] files) { Message message = Message.obtain(); message.obj = files; message.what = FILE; workHandler.getHandler().sendMessage(message); } private void load(@RawRes int[] res) { Message message = Message.obtain(); message.obj = res; message.what = RES; workHandler.getHandler().sendMessage(message); } private void loadInThreadFromFile(final File[] files) { if (index < files.length) { File file = files[index]; if (file.isFile() && isPicture(file)) { if (bitmapDrawable != null) { imageCache.mReusableBitmaps.add(new SoftReference<>(bitmapDrawable.getBitmap())); } long start = System.currentTimeMillis(); bitmapDrawable = FrameBuild.BitmapLoadUtils.decodeSampledBitmapFromFile(file.getAbsolutePath(), width, height, imageCache, isOpenCache); long end = System.currentTimeMillis(); float updateTime = (frameTime - (end - start)) > 0 ? (frameTime - (end - start)) : 0; Message message = Message.obtain(); message.what = FILE; message.obj = files; handler.sendMessageAtTime(message, index == 0 ? 0 : (int) (SystemClock.uptimeMillis() + updateTime)); index++; } else { index++; loadInThreadFromFile(files); } } else { if (loop) { index = 0; loadInThreadFromFile(files); } else { index++; bitmapDrawable = null; frameTime = 0; if (onImageLoadListener != null) { onImageLoadListener.onPlayFinish(); } isRunning = false; onImageLoadListener = null; } } } private void loadInThreadFromRes(final int[] resIds) { if (index < resIds.length) { int resId = resIds[index]; if (bitmapDrawable != null) { imageCache.mReusableBitmaps.add(new SoftReference<>(bitmapDrawable.getBitmap())); } long start = System.currentTimeMillis(); bitmapDrawable = FrameBuild.BitmapLoadUtils.decodeSampledBitmapFromRes(resources, resId, width, height, imageCache, isOpenCache); long end = System.currentTimeMillis(); float updateTime = (frameTime - (end - start)) > 0 ? (frameTime - (end - start)) : 0; Message message = Message.obtain(); message.what = RES; message.obj = resIds; handler.sendMessageAtTime(message, index == 0 ? 0 : (int) (SystemClock.uptimeMillis() + updateTime)); index++; } else { if (loop) { index = 0; loadInThreadFromRes(resIds); } else { index++; bitmapDrawable = null; frameTime = 0; if (onImageLoadListener != null) { onImageLoadListener.onPlayFinish(); } isRunning = false; onImageLoadListener = null; } } } private boolean isPicture(File file) { return file.getName().endsWith("png") || file.getName().endsWith("jpg"); } @Override public void handleMessage(Message msg) { switch (msg.what) { case RES: loadInThreadFromRes((int[]) msg.obj); break; case FILE: loadInThreadFromFile((File[]) msg.obj); break; } } public void setFps(int fps) { frameTime = 1000f / fps + 0.5f; } public void setOnImageLoaderListener(OnImageLoadListener onPlayFinish) { this.onImageLoadListener = onPlayFinish; } public interface OnImageLoadListener { void onImageLoad(BitmapDrawable drawable); void onPlayFinish(); } /** * 改造成build构建者模式 * <p> * 两种 一种是file * 一种是Resource */ public static class FileHandlerBuilder implements FrameBuild { private int width; private int height; private int fps = 30; private File[] files; private OnImageLoadListener onPlayFinish; private ImageFrameHandler imageFrameHandler; private int startIndex; private int endIndex; public FileHandlerBuilder(@NonNull File[] files) { if (files.length == 0) { throw new IllegalArgumentException("fileDir is not empty"); } this.files = files; createHandler(); } public FileHandlerBuilder(@NonNull String fileDir) { if (TextUtils.isEmpty(fileDir)) { throw new IllegalArgumentException("fileDir is not empty"); } File dir = new File(fileDir); if (dir.exists() && dir.isDirectory()) { files = dir.listFiles(); } createHandler(); } @Override public FrameBuild setLoop(boolean loop) { imageFrameHandler.setLoop(loop); return this; } @Override public FrameBuild stop() { imageFrameHandler.stop(); return this; } // 只需要改变数组长度即可 @Override public FrameBuild setStartIndex(int startIndex) { if (startIndex >= files.length) { throw new IllegalArgumentException("startIndex is not big to files length"); } this.startIndex = startIndex; return this; } @Override public FrameBuild setEndIndex(int endIndex) { if (endIndex > files.length) { throw new IllegalArgumentException("endIndex is not big to files length"); } if (endIndex <= startIndex) { throw new IllegalArgumentException("endIndex is not to small startIndex"); } this.endIndex = endIndex; return this; } @Override public FrameBuild setWidth(int width) { this.width = width; return this; } @Override public FrameBuild setHeight(int height) { this.height = height; return this; } @Override public FrameBuild setFps(int fps) { this.fps = fps; imageFrameHandler.setFps(fps); return this; } @Override public FrameBuild setOnImageLoaderListener(OnImageLoadListener onPlayFinish) { this.onPlayFinish = onPlayFinish; return this; } @Override public FrameBuild openLruCache(boolean isOpenCache) { imageFrameHandler.openLruCache(isOpenCache); return this; } @Override public ImageFrameHandler build() { if (!imageFrameHandler.isRunning) { clip(); imageFrameHandler.setImageFrame(files, width, height, fps, onPlayFinish); } return imageFrameHandler; } private void createHandler() { if (imageFrameHandler == null) { imageFrameHandler = new ImageFrameHandler(FILE); } } @Override public FrameBuild clip() { if (startIndex >= 0 && endIndex > 0 && startIndex < endIndex) { files = split(files, startIndex, endIndex); } return this; } File[] split(File[] resArray, int start, int end) { File[] ints = new File[end - start]; int index = 0; for (int i = start; i < end; i++) { ints[index] = resArray[i]; index++; } return ints; } } private void openLruCache(boolean isOpenCache) { this.isOpenCache = isOpenCache; } /** * 改造成build构建者模式 * <p> * 两种 一种是file * 一种是Resource */ public static class ResourceHandlerBuilder implements FrameBuild { @NonNull private final Resources resources; private int width; private int height; private int fps = 30; private int[] resArray; private OnImageLoadListener onPlayFinish; private ImageFrameHandler imageFrameHandler; private int startIndex; private int endIndex; public ResourceHandlerBuilder(@NonNull Resources resources, @NonNull @RawRes int[] resArray) { if (resArray.length == 0) { throw new IllegalArgumentException("resArray is not empty"); } this.resources = resources; this.resArray = resArray; createHandler(); } @Override public FrameBuild setLoop(boolean loop) { imageFrameHandler.setLoop(loop); return this; } @Override public FrameBuild stop() { imageFrameHandler.stop(); return this; } @Override public FrameBuild setStartIndex(int startIndex) { if (startIndex >= resArray.length) { throw new IllegalArgumentException("startIndex is not to big resArray length"); } this.startIndex = startIndex; return this; } @Override public FrameBuild setEndIndex(int endIndex) { if (endIndex > resArray.length) { throw new IllegalArgumentException("endIndex is not big to resArray length"); } if (endIndex <= startIndex) { throw new IllegalArgumentException("endIndex is not to small startIndex"); } this.endIndex = endIndex; return this; } @Override public FrameBuild clip() { if (startIndex >= 0 && endIndex > 0 && startIndex < endIndex) { resArray = split(resArray, startIndex, endIndex); } return this; } @Override public FrameBuild setWidth(int width) { this.width = width; return this; } @Override public FrameBuild setHeight(int height) { this.height = height; return this; } @Override public FrameBuild setFps(int fps) { this.fps = fps; imageFrameHandler.setFps(fps);// 这里有一个重复计算 后期想个更好的办法支持动态换 return this; } @Override public FrameBuild openLruCache(boolean isOpenCache) { imageFrameHandler.openLruCache(isOpenCache); return this; } @Override public FrameBuild setOnImageLoaderListener(OnImageLoadListener onPlayFinish) { this.onPlayFinish = onPlayFinish; return this; } @Override public ImageFrameHandler build() { if (!imageFrameHandler.isRunning) { clip(); imageFrameHandler.setImageFrame(resources, resArray, width, height, fps, onPlayFinish); } return imageFrameHandler; } private void createHandler() { if (imageFrameHandler == null) { imageFrameHandler = new ImageFrameHandler(RES); } } int[] split(int[] resArray, int start, int end) { int[] ints = new int[end - start]; int index = 0; for (int i = start; i < end; i++) { ints[index] = resArray[i]; index++; } return ints; } } }
[code]package imageframe; import android.annotation.NonNull; import android.annotation.RawRes; import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.drawable.BitmapDrawable; import static android.graphics.BitmapFactory.decodeFile; import static android.graphics.BitmapFactory.decodeStream; /** */ public interface FrameBuild { public FrameBuild setLoop(boolean loop); public FrameBuild stop(); public FrameBuild clip(); public FrameBuild setStartIndex(int startIndex); public FrameBuild setEndIndex(int endIndex); public FrameBuild setWidth(int width); public FrameBuild setHeight(int height); public FrameBuild setFps(int fps); public FrameBuild openLruCache(boolean isOpenCache); public FrameBuild setOnImageLoaderListener( ImageFrameHandler.OnImageLoadListener onPlayFinish); ImageFrameHandler build(); class BitmapLoadUtils { public static BitmapDrawable decodeSampledBitmapFromFile( String filename, int reqWidth, int reqHeight, ImageCache cache, boolean isOpenLruCache) { final BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; decodeFile(filename, options); options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight); BitmapDrawable bitmapFromCache; if (isOpenLruCache) { bitmapFromCache = cache.getBitmapFromCache(filename); if (bitmapFromCache == null) { // if (Utils.hasHoneycomb()) { bitmapFromCache = readBitmapFromFile(filename, cache, options); cache.addBitmap(filename, bitmapFromCache); } } else { bitmapFromCache = readBitmapFromFile(filename, cache, options); } return bitmapFromCache; } @NonNull private static BitmapDrawable readBitmapFromFile(String filename, ImageCache cache, BitmapFactory.Options options) { BitmapDrawable bitmapFromCache; addInBitmapOptions(options, cache); // } // If we're running on Honeycomb or newer, try to use inBitmap. options.inJustDecodeBounds = false; bitmapFromCache = new BitmapDrawable(BitmapFactory.decodeFile( filename, options)); return bitmapFromCache; } static BitmapDrawable decodeSampledBitmapFromRes(Resources resources, @RawRes int resId, int reqWidth, int reqHeight, ImageCache cache, boolean isOpenLruCache) { final BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; decodeStream(resources.openRawResource(resId), null, options); options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight); // String resourceName = resources.getResourceName(resId); // if (Utils.hasHoneycomb()) { BitmapDrawable bitmapFromCache; if (isOpenLruCache) { String resourceName = resources.getResourceName(resId); bitmapFromCache = cache.getBitmapFromCache(resourceName); if (bitmapFromCache == null) { // if (Utils.hasHoneycomb()) { bitmapFromCache = readBitmapFromRes(resources, resId, cache, options); cache.addBitmap(resourceName, bitmapFromCache); } } else { bitmapFromCache = readBitmapFromRes(resources, resId, cache, options); } return bitmapFromCache; } @NonNull private static BitmapDrawable readBitmapFromRes(Resources resources, @RawRes int resId, ImageCache cache, BitmapFactory.Options options) { addInBitmapOptions(options, cache); // } // If we're running on Honeycomb or newer, try to use inBitmap. options.inJustDecodeBounds = false; return new BitmapDrawable(resources, decodeStream( resources.openRawResource(resId), null, options)); } private static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) { if (reqHeight == 0 || reqWidth == 0) { return 1; } final int height = options.outHeight; final int width = options.outWidth; int inSampleSize = 1; if (height > reqHeight || width > reqWidth) { final int halfHeight = height / 2; final int halfWidth = width / 2; // The maximum value of the inSampleSize can be obtained on the // premise of ensuring that the // width and height of the bitmap are larger than the target // size while ((halfHeight / inSampleSize) > reqHeight && (halfWidth / inSampleSize) > reqWidth) { inSampleSize *= 2; } } return inSampleSize; } private static void addInBitmapOptions(BitmapFactory.Options options, ImageCache cache) { // inBitmap only works with mutable bitmaps, so force the decoder to // return mutable bitmaps. options.inMutable = true; if (cache != null) { // Try to find a bitmap to use for inBitmap. Bitmap inBitmap = cache.getBitmapFromReusableSet(options); if (inBitmap != null) { // If a suitable bitmap has been found, set it as the value // of // inBitmap. options.inBitmap = inBitmap; } } } } }
[code]package imageframe; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.drawable.BitmapDrawable; import android.os.Build; import android.util.LruCache; import java.lang.ref.SoftReference; import java.util.Collections; import java.util.HashSet; import java.util.Iterator; import java.util.Set; /** */ public class ImageCache { final Set<SoftReference<Bitmap>> mReusableBitmaps; private LruCache<String, BitmapDrawable> mMemoryCache; public ImageCache() { mReusableBitmaps = Collections .synchronizedSet(new HashSet<SoftReference<Bitmap>>()); long memCacheSize = Runtime.getRuntime().freeMemory() / 8; if (memCacheSize <= 0) { memCacheSize = 1; } // If you're running on Honeycomb or newer, create a // synchronized HashSet of references to reusable bitmaps. mMemoryCache = new LruCache<String, BitmapDrawable>((int) memCacheSize) { // // Notify the removed entry that is no longer being cached. // @Override // protected void entryRemoved(boolean evicted, String key, // BitmapDrawable oldValue, BitmapDrawable newValue) { // //Log.i("TAG","mReusableBitmaps add2"); // //mReusableBitmaps.add(new // SoftReference<>(oldValue.getBitmap())); // } @Override protected int sizeOf(String key, BitmapDrawable value) { return value.getBitmap().getByteCount(); } }; } // This method iterates through the reusable bitmaps, looking for one // to use for inBitmap: Bitmap getBitmapFromReusableSet(BitmapFactory.Options options) { Bitmap bitmap = null; if (mReusableBitmaps != null && !mReusableBitmaps.isEmpty()) { synchronized (mReusableBitmaps) { final Iterator<SoftReference<Bitmap>> iterator = mReusableBitmaps .iterator(); Bitmap item; while (iterator.hasNext()) { item = iterator.next().get(); if (null != item && item.isMutable()) { // Check to see it the item can be used for inBitmap. if (canUseForInBitmap(item, options)) { bitmap = item; // Remove from reusable set so it can't be used // again. iterator.remove(); break; } } else { // Remove from the set if the reference has been // cleared. iterator.remove(); } } } } return bitmap; } private static boolean canUseForInBitmap(Bitmap candidate, BitmapFactory.Options targetOptions) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { // From Android 4.4 (KitKat) onward we can re-use if the byte size // of // the new bitmap is smaller than the reusable bitmap candidate // allocation byte count. int width = targetOptions.outWidth / targetOptions.inSampleSize; int height = targetOptions.outHeight / targetOptions.inSampleSize; int byteCount = width * height * getBytesPerPixel(candidate.getConfig()); return byteCount <= candidate.getAllocationByteCount(); } // On earlier versions, the dimensions must match exactly and the // inSampleSize must be 1 return candidate.getWidth() == targetOptions.outWidth && candidate.getHeight() == targetOptions.outHeight && targetOptions.inSampleSize == 1; } /** * A helper function to return the byte usage per pixel of a bitmap based on * its configuration. */ static int getBytesPerPixel(Bitmap.Config config) { if (config == Bitmap.Config.ARGB_8888) { return 4; } else if (config == Bitmap.Config.RGB_565) { return 2; } else if (config == Bitmap.Config.ARGB_4444) { return 2; } else if (config == Bitmap.Config.ALPHA_8) { return 1; } return 1; } public BitmapDrawable getBitmapFromCache(String filename) { return mMemoryCache.get(filename); } public void addBitmap(String filename, BitmapDrawable bitmapFromCache) { mMemoryCache.put(filename, bitmapFromCache); } }
[code]package imageframe; import android.os.Handler; import android.os.Message; import android.os.Process; import java.util.ArrayList; import java.util.List; public class WorkHandler extends android.os.HandlerThread { private Handler workHandler = null; private volatile List<WorkMessageProxy> messageProxyList; public WorkHandler() { super("WorkHandler", Process.THREAD_PRIORITY_BACKGROUND); start(); workHandler = new Handler(getLooper()) { @Override public void handleMessage(Message msg) { if (messageProxyList != null) { for (WorkMessageProxy workMessageProxy : messageProxyList) { workMessageProxy.handleMessage(msg); } } } }; } public void post(Runnable run) { workHandler.post(run); } public void postAtFrontOfQueue(Runnable runnable) { workHandler.postAtFrontOfQueue(runnable); } public void postDelayed(Runnable runnable, long delay) { workHandler.postDelayed(runnable, delay); } public void postAtTime(Runnable runnable, long time) { workHandler.postAtTime(runnable, time); } public void addMessageProxy(WorkMessageProxy proxy) { initMessageProxyList(); messageProxyList.add(proxy); } public void removeMessageProxy(WorkMessageProxy proxy) { initMessageProxyList(); messageProxyList.remove(proxy); } private void initMessageProxyList() { if (messageProxyList == null) { messageProxyList = new ArrayList<>(); } } public Handler getHandler() { return workHandler; } public interface WorkMessageProxy { void handleMessage(Message msg); } }
接下来的一个ImageLoading,是做主要功能实现:
[code]package imageframe; import imageframe.ImageFrameCustomView; import imageframe.ImageFrameHandler; import android.content.Context; import android.content.res.Resources; /** * Created by sunchip on 2018/7/10. * 播放图片类 效果跟帧动画类似 优化内容 防止多图片使用帧动画OOM异常 YML */ public class ImageLoading { private static ImageFrameHandler Build; private static String TAG = "ImageLoading"; // static final int[] resIdsE = {R.drawable.dihn_001,R.drawable.dihn_002,R.drawable.dihn_003,R.drawable.dihn_004,R.drawable.dihn_005}; public static void loadRes(Context context, final ImageFrameCustomView imageFrame, int count, String title, int fps, boolean loop) { final int[] resIds = new int[count]; Resources res = context.getResources(); final String packageName = context.getPackageName(); for (int i = 0; i < resIds.length; i++) { String resName = title + (i + 1); int imageResId = res.getIdentifier(resName, "drawable", packageName); resIds[i] = imageResId; } ImageFrameHandler build = new ImageFrameHandler.ResourceHandlerBuilder(context.getResources(), resIds) .setFps(fps) .setLoop(loop) .build(); imageFrame.startImageFrame(build); Build = build; } //暂停 public static void Pause() { if (Build != null) Build.pause(); } //停止 public static void Stop() { if (Build != null) Build.stop(); } public static void start() { if (Build != null) Build.start(); } }
以上就是自定义的所有使用类,接下来我们开始使用它;
1.首先,写布局:
[code] <imageframe.ImageFrameCustomView android:layout_width="414px" android:layout_height="414px" android:layout_marginTop="104px" android:visibility="gone" android:background="@drawable/blanfive_000012" android:id="@+id/FramrSix_im2"/>
内容就不做过多解释了,需要注意的就是类名别弄错了.
2.代码中使用:
[code] private ImageFrameCustomView mImageView2; mImageView2 = (ImageFrameCustomView) findViewById(R.id.FramrSix_im2); ImageLoading.loadRes(getActivity(), mImageView2, 12, "blanfive_0000", AppApplication.Fps, true);
前面两句我就不解释了,重点在第三句代码:这个类就是主要的操作类,需要传参上下文对象,控件,帧动画总数,帧动画前置名(等会来说这个),秒帧数,是否循环播放帧. 这里我们说一下帧动画所有动画的名字:我在方法中使用getIdentifier获取图片对象,名字都是blanfive_0000开头,如果有两张图片,名字就是blanfive_00001与blanfive_00002.其实看ImageLoading类就大概能看出来
具体请看https://github.com/Mr-wangyong/ImageFrame
- 点赞
- 收藏
- 分享
- 文章举报
相关文章推荐
- Android 图片压缩展示 防止使用MediaStore.Images.Media.getBitmap造成的OOM异常
- Android实现眼睛一闪一闪的效果,使用layerdrawable,类似GIF图片效果
- Android的ExpandableListView的动画展开效果和使用traceview的性能优化
- Android播放多张图片形成一个动画效果
- Android 中加载几百张图片做帧动画防止 OOM 的解决方案
- Android Bitmap大量使用不产生OOM之“加载大图片资源优化”
- 【转】Android 使用ViewPager实现类似gallery画廊的效果(画廊效果之ViewPager显示多个图片)
- Android中如何使用rotate实现图片不停旋转的效果与动画的停止
- Android 使用ViewPager实现类似gallery画廊的效果(画廊效果之ViewPager显示多个图片)
- Android使用SurfaceView代替AnimationDrawable播放多图帧动画,避免OOM和卡顿
- Android 使用Bitmap将自身保存为文件,BitmapFactory从File中解析图片并防止OOM
- Android使用PowerImageView实现播放强大的ImageView动画效果
- Android 使用动画效果后的控件位置处理 类似系统通知栏下拉动画!!
- Android 使用动画效果后的控件位置处理 类似系统通知栏下拉动画
- 使用CSS制作文字环绕图片效果(文字内容包含<li>标签)
- Android 加载大图片造成OOM异常解决方法
- android matrix camera处理图片绕X轴Y轴翻转(类似3D效果)
- 剖析Android动画(图片闪烁、左右摇摆、上下晃动等效果)
- Android多抽屉效果 (类似最早QQ使用的效果)
- Android使用WebView加载图片防止OutOfMemoryError