Zim
Zim

Reputation: 182

Android: Handler and Timer inside a RecyclerView is not working properly

In a chatting window I have a feature like self destructing message after a duration. For which I have a class which shows burning animation after the duration. While sending text the handler and timer I used in the below class is working fine for 2-3 times then some animation discrepancy is found like the fire isn't starting in exact location.

Apart from that while sending a file from file chooser fragment when it returns to the recyclerview of the chatwindow nothing happens until I touch the screen and scroll it a bit. While debugging I noticed that the first time when bindview is called after sending a file the handler and timer is not executing properly. Instead if I navigate back and enter the chatwindow again it's working perfectly. It burns the filemessage perfectly then.

The burner class:

public class Burner {
private static final TaggedLogger logger = new TaggedLogger("Burner");

public static void burnMessage(final TextMessageViewHolder holder, final BurnerListener listener) {
    final int DURATION = 3000;
    if (!holder.isBurning) {
        final Handler handler = new Handler(Looper.getMainLooper());
        final Animator.AnimatorListener animatorListener = new Animator.AnimatorListener() {

            @Override
            public void onAnimationStart(Animator animator) {
                logger.log("onAnimationStart");

            }

            @Override
            public void onAnimationEnd(Animator animator) {
                listener.onBurnFinished();
            }

            @Override
            public void onAnimationCancel(Animator animator) {

            }

            @Override
            public void onAnimationRepeat(Animator animator) {

            }
        };
        holder.isBurning = true;
        holder.fireAnimationHolder.setVisibility(View.VISIBLE);
        holder.fireAnimationHolder.measure(0, 0);
        Activity activity = (Activity) ChatProperties.getChatWindowContext();

        if (activity != null) {
            final ParticleSystem particleSystem = new ParticleSystem(activity, 48, R.drawable.fire_2, DURATION)
                    .setSpeedByComponentsRange(-0.025f, 0.0f, -0.06f, -0.08f)
                    .setAcceleration(0.00003f, 0)
                    .setInitialRotationRange(30, 45)
                    .addModifier(new AlphaModifier(255, 0, 200, 1000))
                    .addModifier(new ScaleModifier(0.5f, 2f, 0, 1000));
            holder.fireAnimationHolder.post(new Runnable() {
                @Override
                public void run() {
                    holder.fireAnimationHolder.measure(0,0);
                    int fireAnimationHolderWidth = holder.fireAnimationHolder.getWidth();
//                    logger.log("fireAnimationHolderWidth = " + fireAnimationHolderWidth);
                    particleSystem.emit(holder.fireSource, 12);
                    holder.fireSource.animate().translationXBy(fireAnimationHolderWidth).setStartDelay(500).setDuration(DURATION).setListener(animatorListener).start();
                    holder.fireSourceController.setPivotX(0);
                    holder.fireSourceController.animate().alpha(1f).scaleX(1f).setDuration(DURATION).start();
                }
            });
            new Timer().scheduleAtFixedRate(new TimerTask() {
                int elapsedTime = 0;

                @Override
                public void run() {
                    elapsedTime += 300;
                    if (elapsedTime >= DURATION) {
                        handler.post(new Runnable() {
                            @Override
                            public void run() {
                                particleSystem.cancel();
                            }
                        });

                        this.cancel();
                    } else {
                        handler.post(new Runnable() {
                            @Override
                            public void run() {
                                particleSystem.updateEmitPoint(holder.fireSource, Gravity.CENTER);
                            }
                        });
                    }
                }
            }, 100, 300);
        }
    }
}

This burnMessage method is called from the bindview of the TextMessageViewholder's bindview method and FilemessageViewHolder extends TextMessageViewHoler class.

In TextMessageViewHolder's bindview method this function is called if it's a self destructing message:

private void handleMessageBurning(final Message message) {
    if (message.imBurnTime > 0 && BurnMessageHelper.animatedBurnMessageEntryMap.containsKey(message.callerId)) {
        Log.e("BurnThread","message to be burned");
        Burner.burnMessage(this, new BurnerListener() {
            @Override
            public void onBurnFinished() {
                if (ChatProperties.isGroupChat) {
                    DataHelper.getInstance().deleteGroupMessage(Target.target, message.callerId);
                } else {
                    DataHelper.getInstance().deleteMessage(Target.target, message.callerId);
                }
                BurnMessageHelper.animatedBurnMessageEntryMap.remove(message.callerId);
                isBurning = false;
            }
        });
    } else {
        fireAnimationHolder.setVisibility(View.GONE);
    }
}

What is happening here? Does the thread of the timer can't run in main thread here due to some reason? Please help. Thanks.

N.B. I tried this in Marshmallow, Nougat and Oreo.

Upvotes: 0

Views: 385

Answers (0)

Related Questions