Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

gif not animated #260

Closed
ourgit opened this issue Mar 16, 2016 · 18 comments
Closed

gif not animated #260

ourgit opened this issue Mar 16, 2016 · 18 comments
Labels

Comments

@ourgit
Copy link

ourgit commented Mar 16, 2016

I am using android-gif-drawable for animate emotion. However it only shows still frame,the gif can not animate.I am sure the gif file is correct,it can animate when using Glide.

Here is the snippet:

public static SpannableStringBuilder parseEmotion(Context context, String content, final TextView gifTextView) {
SpannableStringBuilder ssb = new SpannableStringBuilder(content);
Pattern pattern = Pattern.compile(FACE_PATTERN, Pattern.CASE_INSENSITIVE);
Log.i(TAG, "before parse:" + content);
if (null == content || content.length() < 1) return null;
Matcher matcher = pattern.matcher(content);
if (matcher.groupCount() > 0) {
gifCallback = new Drawable.Callback() {
@OverRide
public void invalidateDrawable(Drawable drawable) {
gifTextView.invalidate();
}

            @Override
            public void scheduleDrawable(Drawable who, Runnable what, long when) {
                gifTextView.postDelayed(what, when);
            }

            @Override
            public void unscheduleDrawable(Drawable who, Runnable what) {
                gifTextView.removeCallbacks(what);
            }
        };
    }

    while (matcher.find()) {
        int matchStart = matcher.start();
        int matchEnd = matcher.end();
        String group = matcher.group();
        try {
            int resourceId = context.getResources().getIdentifier(group, "drawable", "com.mypack");
            GifDrawable gifDrawable = new GifDrawable(context.getResources(), resourceId);
            gifs.add(gifDrawable);
            int width = getRecommendScaleOnBig(context);
            gifDrawable.setBounds(0, 0, width, width);
            gifDrawable.start();
            gifDrawable.setLoopCount(0);
            ssb.setSpan(new ImageSpan(gifDrawable), matchStart, matchEnd, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
            gifDrawable.setCallback(gifCallback);
        } catch (IOException e) {
            Log.e(TAG, e.getMessage());
        }
    }

    return ssb;
}

hope guys help me out.thanks in advance

@ourgit
Copy link
Author

ourgit commented Mar 16, 2016

I also log the method invalidateDrawable,and find it does not execute when listview nofitydataInvalidate. I am trying to execute drawable.invalidateSelf() to make it animate,but failed.

@koral--
Copy link
Owner

koral-- commented Mar 16, 2016

Does it animate after calling gifTextView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);?

@ourgit
Copy link
Author

ourgit commented Mar 17, 2016

Hi koral,

where should I place gifTextView.setLayerType(View.LAYER_TYPE_SOFTWARE,
null)?

I placed above "return ssb",no work;
placed here
gifDrawable.addAnimationListener(new AnimationListener() {
@OverRide https://github.com/Override
public void onAnimationCompleted(int loopNumber) {
Log.i(TAG,"reseting gif...");
gifTextView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
gifDrawable.invalidateSelf();
}
});

some item animated,some item does not, they have the same emotion.
am i doing something wrong? where is the proper place to put the method?

thanks

@ourgit
Copy link
Author

ourgit commented Mar 17, 2016

I attach the gif here,maybe it could do some help for excluding error.

On Thu, Mar 17, 2016 at 10:35 AM, justin chen [email protected] wrote:

Hi koral,

where should I place gifTextView.setLayerType(View.LAYER_TYPE_SOFTWARE,
null)?

I placed above "return ssb",no work;
placed here
gifDrawable.addAnimationListener(new AnimationListener() {
@OverRide https://github.com/Override
public void onAnimationCompleted(int loopNumber) {
Log.i(TAG,"reseting gif...");
gifTextView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
gifDrawable.invalidateSelf();
}
});

some animate,some not. only one item animated,other item does not.

where is the proper place to put the method?

thanks

On Wed, Mar 16, 2016 at 11:32 PM, Karol Wrótniak <[email protected]

wrote:

Does it animate after calling gifTextView.setLayerType(View.LAYER_TYPE_SOFTWARE,
null);?


You are receiving this because you authored the thread.
Reply to this email directly or view it on GitHub
https://github.com/koral--/android-gif-drawable/issues/260#issuecomment-197384899

@koral--
Copy link
Owner

koral-- commented Mar 17, 2016

setLayerType() should be called once, preferably somewhere at the beginning, eg. just after retrieving TextView instance by findViewById() or similar call.
There is a similar issue, but with no solution yet: https://github.com/koral--/android-gif-drawable/issues/247
Could you tell what is the device model, which Android version it is using?
BTW there is no gif attached.

@ourgit
Copy link
Author

ourgit commented Mar 18, 2016

I tested in two devices,with the same result,one is samsung S5 with android 5.0 ,the other is samsung A5 with android 4.4.4.

git does not accept rar attachment,so I mail you with gmail attachment,maybe you can find the attachment at gmail.If need further infomation,please let me know.

@ourgit
Copy link
Author

ourgit commented Mar 18, 2016

Hi @koral--
I try your advice,and it works most of the Gif emotion,but some still no animate,and sometimes the not animated gifs animate when I scroll the listView,that is really wierd! Also I find that when I scroll the listview the memory does not release,so it keep high using memory.That is really a headache,any solution for that?thanks

@koral--
Copy link
Owner

koral-- commented Mar 18, 2016

Assuming that parseEmotion() is called on each item instantiation you need to unset callback (gifDrawable.setCallback(null);) on recycled items.

@ourgit
Copy link
Author

ourgit commented Mar 18, 2016

yeah,parseEmotion() is called on each item instantiation. And every textview cached by convertview cache. I will try unset callback to release memory.Do you have any idea about "it works most of the Gif emotion,but some still no animate,and sometimes the not animated gifs animate when I scroll the listView"?

@koral--
Copy link
Owner

koral-- commented Mar 18, 2016

Without debugging I don't know yet what is the reason.

I think we have to first determine if callback methods (those from Drawable.Callback) are called for affected items when they are not animating. To check this you can eg. create (for this experiment purposes only) separate callback instances for each item. Something like that:

gifDrawable.setCallback(
new Drawable.Callback() {
@Override
public void invalidateDrawable(Drawable drawable) {
gifTextView.invalidate();
//log item index to logcat, set breakpoint with log or something similar here
}
            @Override
            public void scheduleDrawable(Drawable who, Runnable what, long when) {
                gifTextView.postDelayed(what, when);
            }

            @Override
            public void unscheduleDrawable(Drawable who, Runnable what) {
                gifTextView.removeCallbacks(what);
            }
        }
);

After we know if callbacks are called we can decide what should be next steps.

@ourgit
Copy link
Author

ourgit commented Mar 19, 2016

hi @koral--
after set and read the log, I am sure the callbacks are called. hope you can give me the further solution.
here are some key code,maybe it will do some help for solve the issue.

public SpannableStringBuilder parseEmotion2(Context context, String content, final TextView gifTextView) {
        SpannableStringBuilder ssb = new SpannableStringBuilder(content);
        Pattern pattern = Pattern.compile(FACE_PATTERN, Pattern.CASE_INSENSITIVE);
        if (null == content || content.length() < 1) return null;
        Matcher matcher = pattern.matcher(content);
        List<int[]> resourceAndIndex = new ArrayList<>();
        while (matcher.find()) {
            String group = matcher.group();
            int resourceId = context.getResources().getIdentifier(group, "drawable", "com.quji");
            int[] index = new int[]{resourceId, matcher.start(), matcher.end()};
            resourceAndIndex.add(index);
        }
        setSpan(context, resourceAndIndex, ssb, gifTextView);
        return ssb;
    }

    private void setSpan(Context context, List<int[]> resourceAndIndex, SpannableStringBuilder ssb, final TextView gifTextView) {
        if (null == resourceAndIndex || ssb == null) return;
        int matchCount = resourceAndIndex.size();
        boolean noAnimate = false;
        if (matchCount > 9) noAnimate = true;
        int width = getRecommendScaleOnBig(context);
        List<Drawable> drawables = new ArrayList<>();
        for (int[] index : resourceAndIndex) {
            int resourceId = index[0];
            int start = index[1];
            int end = index[2];
            if (noAnimate) {
                Drawable drawable = cachemap.get(resourceId);
                if (null == drawable) {
                    drawable = context.getResources().getDrawable(resourceId);
                    drawable.setBounds(0, 0, width, width);
                    drawables.add(drawable);
                    cachemap.put(resourceId, drawable);
                }
                ssb.setSpan(new ImageSpan(drawable), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
            } else {
                try {
                    final GifDrawable gifDrawable = new GifDrawable(context.getResources(), resourceId);
                    gifDrawable.setBounds(0, 0, width, width);
                    gifDrawable.setLoopCount(0);
                    drawables.add(gifDrawable);
//                    gifDrawable.addAnimationListener(new AnimationListener() {
//                        @Override
//                        public void onAnimationCompleted(int loopNumber) {
//                            Log.i(TAG, "reseting gif...");
//                            if (null != gifDrawable) gifDrawable.reset();
//                        }
//                    });
                    gifDrawable.setCallback(new GifCallback(gifTextView));
                    ssb.setSpan(new ImageSpan(gifDrawable), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
                } catch (IOException e) {
                    Log.e(TAG, e.getMessage());
                }
            }
        }
        gifTextView.setTag(R.id.img_tag,drawables);
    }
 private static class GifCallback implements Drawable.Callback {

        private final TextView tv;

        public GifCallback(TextView tv) {
            this.tv = tv;
        }

        @Override
        public void invalidateDrawable(android.graphics.drawable.Drawable who) {
            tv.invalidate();
            Log.i(TAG,"invalidateDrawable:"+tv.toString()+":drawables:"+who.toString());
        }

        @Override
        public void scheduleDrawable(android.graphics.drawable.Drawable who, Runnable what, long when) {
            tv.postDelayed(what, when);
        }

        @Override
        public void unscheduleDrawable(android.graphics.drawable.Drawable who, Runnable what) {
            tv.removeCallbacks(what);
        }
    }

@koral--
Copy link
Owner

koral-- commented Mar 19, 2016

How exactly are you using parseEmotion2() and is there any pattern which items are not animating?
There is an issue with ListView/GridView that at certain indexes are instantiated multiple times and the latest instance is not visible: https://github.com/koral--/android-gif-drawable/issues/135

@ourgit
Copy link
Author

ourgit commented Mar 21, 2016

@koral--

in listview adapter getView() method using the parseEmotion, here are the details:

SpannableStringBuilder span = EmotionParser.getInstance().parseEmotion2(instance,content, cache.tv_chatcontent_out_mul);
cache.tv_chatcontent_out_mul.setText(span);

I don't find any pattern which items not animateing, it seems like randomly happens,but can reproduce.

all the gifs by android-gif-drawable are visible except some not animate.

@koral--
Copy link
Owner

koral-- commented Mar 21, 2016

OK, I'll try to reproduce that.

@ourgit
Copy link
Author

ourgit commented Mar 22, 2016

thank you. Look forward to your solution.

On Tue, Mar 22, 2016 at 2:11 AM, Karol Wrótniak [email protected]
wrote:

OK, I'll try to reproduce that.


You are receiving this because you authored the thread.
Reply to this email directly or view it on GitHub
https://github.com/koral--/android-gif-drawable/issues/260#issuecomment-199408431

@koral-- koral-- added bug and removed question labels Mar 26, 2016
@koral--
Copy link
Owner

koral-- commented Mar 26, 2016

I've managed to reproduce that and will fix it ASAP.

@koral--
Copy link
Owner

koral-- commented Mar 26, 2016

@ourgit it seems that in your case the problem is that callback is garbage collected, because Drawable creates weak reference of it and there is no strong reference kept. You need to store reference to callback in some object which lives for the time when you need animation eg. inside item view holder.

TL;DR
Your case is not a bug in library per se however I've updated the sample project to show span inside RecyclerView: https://github.com/koral--/android-gif-drawable-sample/blob/master/sample/src/main/java/pl/droidsonroids/gif/sample/sources/GifSourcesAdapter.java#L47 and updated MultiCallback to support TextView with spans containing GifDrawables.

@ourgit
Copy link
Author

ourgit commented Mar 27, 2016

thank you. I will try your solution and see if it works.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants