您的位置:首页 > 移动开发 > Android开发

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

 

 

 

  • 点赞
  • 收藏
  • 分享
  • 文章举报
月下猫追梦 发布了24 篇原创文章 · 获赞 2 · 访问量 531 私信 关注
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐