Giter VIP home page Giter VIP logo

imageframe's People

Contributors

mr-chengwangyong avatar mr-wangyong avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

imageframe's Issues

另外一种实现方式

用Kotlin实现的另外一种方式的思路。看一下是否有参考价值

用法:

protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_anim);

        View imageView = findViewById(R.id.imageView);
        List<Integer> resources = new ArrayList<>(32);
        Resources res = getResources();
        final String packageName = getPackageName();
        for (int i=1; i<=210; i++){
                String resName = "gift_" + i;
                int imageResId = res.getIdentifier(resName, "drawable", packageName);
                resources.add(imageResId);
        }
        controller = FrameAnim.Companion.create()
                .target(imageView)    //target支持任意View
                .resources(resources)
                .duration(16)
                .controller();
        controller.start();

        imageView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (controller == null) {
                    return;
                }
                if (controller.isPaused()) {
                    controller.resume();
                } else {
                    controller.pause();
                }
            }
        });
}

主要功能类如下:

import android.graphics.drawable.BitmapDrawable
import android.os.Handler
import android.os.HandlerThread
import android.os.Looper
import android.support.v4.view.ViewCompat
import android.util.Log
import android.view.View
import com.mrwang.imageframe.BitmapLoadUtils
import com.mrwang.imageframe.ImageCache
import java.lang.ref.SoftReference

/**
 * Created by young on 2018/2/8.
 */


class FrameAnim {

    companion object {
        fun create(): FrameAnim {
            return FrameAnim()
        }
    }

    interface AnimEndCallBack{
        fun onAnimEnd()
    }

    interface AnimLoopedCallBack{
        fun onAnimLooped(loopedCount:Int)
    }

    /**
     * 遥控器
     */
    interface Controller {
        fun start()
        fun isPaused(): Boolean
        fun pause()
        fun resume()
        fun destroy()
    }

    private inner class ControllerImpl(val ext: FrameAnim) : Controller {
        override fun start() {
            ext.start()
        }

        override fun destroy() {
            ext.destroy()
        }

        override fun isPaused(): Boolean {
            return ext.paused
        }

        override fun pause() {
            ext.pause()
        }

        override fun resume() {
            ext.resume()
        }
    }

    private val TAG = javaClass.simpleName

    private var target: View? = null
    private var list: List<Int>? = null
    private var duration: Long = 300
    private var index = 0
    private val decodeThread = DecodeThread()
    private var decodeHandler: Handler? = null
    private val uiHandler = Handler(Looper.getMainLooper())
    private var bitmapDrawable: BitmapDrawable? = null
    private var isInitLoad = true
    private var loop = true
    private var loopedCount = 0
    private var paused = false
    private var destroyed = false
    private val controller: Controller = ControllerImpl(this)
    private var animEndCallBack:AnimEndCallBack? = null
    private var animLoopedCallBack:AnimLoopedCallBack? = null

    private val autoDestroy:IAutoDestroy = object : IAutoDestroy {
        override fun autoDestroy() {
            destroy()
        }
    }

    fun target(target: View): FrameAnim {
        this.target = target
        return this
    }

    fun resources(list: List<Int>): FrameAnim {
        this.list = list
        return this
    }

    fun duration(duration: Long): FrameAnim {
        this.duration = duration
        return this
    }

    fun loop(lp: Boolean): FrameAnim {
        this.loop = lp
        return this
    }

    fun callBackForAnimEnd(endCallBack: AnimEndCallBack): FrameAnim {
        this.animEndCallBack = endCallBack
        return this
    }

    fun callBackForAnimLooped(loopedCallBack: AnimLoopedCallBack): FrameAnim {
        this.animLoopedCallBack = loopedCallBack
        return this
    }

    fun controller():Controller{
        return controller
    }

    fun start(): Controller {
        if (target == null) {
            Log.w(TAG, "The target is Null")
            throw IllegalArgumentException("The target must not be Null")
        }
        if (list == null || list!!.isEmpty()) {
            Log.w(TAG, "The resources is Empty")
            throw IllegalArgumentException("The resources must not be Null or Empty")
        }
        val ctx = target!!.context
        ctx.registerAutoDestroy(autoDestroy)
        if (decodeHandler!=null){
            Log.e(TAG, "Task already started")
            return controller
        }
        if (paused) {
            Log.e(TAG, "Task is paused, Please use resume() to continue")
            return controller
        }
        decodeThread.start()
        if (decodeHandler == null) {
            decodeHandler = Handler(decodeThread.looper)
        }
        load()
        return controller
    }

    private fun pause() {
        if (decodeHandler == null) {
            throw IllegalStateException("Have u forgot to invoke the ``fun start()``")
        }
        paused = true
        decodeHandler!!.removeCallbacksAndMessages(null)
        uiHandler.removeCallbacksAndMessages(null)
    }

    private fun resume() {
        if (decodeHandler == null) {
            throw IllegalStateException("Have u forgot to invoke the ``fun start()``")
        }
        paused = false
        load()
    }

    fun destroy() {
        if (destroyed){
            return
        }
        destroyed = true
        decodeThread.quit()
        uiHandler.removeCallbacks(uiCallBack)
        println("Component has destroyed")
    }

    private var uiCallBack: Runnable? = null
    private val imageCache = ImageCache()
    private fun load() {
        val resources = list!!
        if (index >= resources.size && loop) {
            index = 0
            loopedCount++
            animLoopedCallBack?.onAnimLooped(loopedCount)
        } else if (index >= resources.size && !loop) {
            Log.d(TAG, "The End")
            println("The End")
            animEndCallBack?.onAnimEnd()
            return
        }

        if (bitmapDrawable != null) {
            imageCache.mReusableBitmaps.add(SoftReference(bitmapDrawable!!.bitmap))
        }
        val resId = resources[index]
        decodeHandler!!.post {
            val start = System.currentTimeMillis()
            val resource = target!!.resources
            bitmapDrawable = BitmapLoadUtils.decodeSampledBitmapFromRes(resource, resId, 0,
                    0,
                    imageCache, true)
            val end = System.currentTimeMillis()
            val decodeConsuming = end - start
            val delay = duration - decodeConsuming
            val actDelay = if (delay > 0) delay else 0
            val finalDelay = if (isInitLoad) 0 else actDelay
            isInitLoad = false
            uiCallBack = Runnable {
                ViewCompat.setBackground(target, bitmapDrawable)
                index++
                load()
            }
            uiHandler.postDelayed(uiCallBack, finalDelay)
        }
    }

    inner class DecodeThread : HandlerThread("DecodeThread")

}

自动处理生命周期:

interface IAutoDestroy {
    fun autoDestroy()
}

class LifeFragment : Fragment() {
    private val set: MutableSet<IAutoDestroy> = mutableSetOf()

    fun register(autoDestroy: IAutoDestroy) {
        set.add(autoDestroy)
    }

    override fun onDestroy() {
        super.onDestroy()
        for (autoDestroy in set) {
            autoDestroy.autoDestroy()
        }
    }
}

fun Context.registerAutoDestroy(autoDestroy: IAutoDestroy) {
    if (this is FragmentActivity) {
        var exist = supportFragmentManager.findFragmentByTag("Hello")
        if (exist == null) {
            exist = LifeFragment()
            supportFragmentManager.beginTransaction().add(exist, "Hello").commit()
        }
        if (exist is LifeFragment) {
            exist.register(autoDestroy)
        }
    }else {
        Log.e("registerAutoDestroy", "The context type do not support fragment")
    }
}

快速切换界面,调用stop方法会crash

用Monkey测试出现
java.util.ConcurrentModificationException
at java.util.ArrayList$ArrayListIterator.next(ArrayList.java:573)
at com.gubei.tool.imageframe.WorkHandler$1.handleMessage(WorkHandler.java:28)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:179)
at android.os.HandlerThread.run(HandlerThread.java:61)

public void removeMessageProxy(WorkMessageProxy proxy) {
initMessageProxyList();
messageProxyList.remove(proxy);
}好像是List移除时出错 不能确定

java.util.ConcurrentModificationException

#1944 java.util.ConcurrentModificationException
com.example.imageframelibs.ImageFrame.WorkHandler$1.void handleMessage(android.os.Message)(SourceFile:34)

解决方案
该异常表示迭代器迭代过程中,迭代的对象发生了改变,如数据项增加或删除。
[解决方案]:由于迭代对象不是线程安全,在迭代的过程中,会检查modCount是否和初始modCount即expectedModCount一致,如果不一致,则认为数据有变化,迭代终止并抛出异常。常出现的场景是,两个线程同时对集合进行操作,线程1对集合进行遍历,而线程2对集合进行增加、删除操作,此时将会发生ConcurrentModificationException异常。
具体方法:多线程访问时要增加同步锁,或者建议使用线程安全的集合:

  1. 使用ConcurrentHashMap替换HashMap,CopyOnWriteArrayList替换ArrayList;
  2. 或者使用使用Vector替换ArrayList,Vector是线程安全的。Vector的缺点:大量数据操作时,由于线程安全,性能比ArrayList低.

点击按钮播放过快崩溃

错误信息如下:
E/AndroidRuntime: FATAL EXCEPTION: WorkHandler
Process: com.example.administrator.liveanimation, PID: 32047
java.util.ConcurrentModificationException
at java.util.ArrayList$ArrayListIterator.next(ArrayList.java:578)
at com.mrwang.imageframe.WorkHandler$1.handleMessage(WorkHandler.java:34)
at android.os.Handler.dispatchMessage(Handler.java:111)
at android.os.Looper.loop(Looper.java:207)
at android.os.HandlerThread.run(HandlerThread.java:61)

频繁播放、停止,出现空指针异常

java.lang.NullPointerException: Attempt to invoke virtual method 'java.io.InputStream android.content.res.Resources.openRawResource(int)' on a null object reference
at com.mrwang.imageframe.BitmapLoadUtils.decodeSampledBitmapFromRes(BitmapLoadUtils.java:69)

图片1为什么播放不出来呢?

图片1为什么播放不出来呢?设置从第N帧开始播放为什么不起作用呢?是在初始化的时候,设置一次,还是每次播放都要设置呢?

重新加载动画就加载不出来的问题

我是点击一个开始按钮,然后加载帧动画。加载完成后,再次点击就会加载不出来,会一直走onPlayFinish这个回调。能不能看下修复一下啊?

如何实现stop后再次开始动画

再下拉刷新中使用需要实现,每次下拉动画都从第一张图开始,现在使用pause() 动画会停住然后调用start()继续开始
使用stop()之后直接停住,能否实现stop()之后动画从第一张图重新开始

加载文件图片不会轮播

如题, 加载手机sdcard的图片文件,执行一次帧动画, 然后就不会再执行,loadInThreadFromFile(File[] files)方法是一直在反复执行的。。。

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.