0

Im adding and then animating a simple ImageView inside a RelativeLayout whenever a button is clicked. Heres my current code:

 mButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {

            ImageView imageview = new ImageView(getActivity());
            imageview.setImageDrawable(getActivity().getDrawable(R.drawable.pic));
            imageview.setLayoutParams(layoutParams);
            mRelativeLayout.addView(imageview);



            Animation anim = AnimationUtils.loadAnimation(getActivity(), R.anim.animation);
            anim.setAnimationListener(new Animation.AnimationListener() {
                @Override
                public void onAnimationStart(Animation animation) {

                }

                @Override
                public void onAnimationEnd(Animation animation) {
                    mRelativeLayout.removeView(imageview);
                }

                @Override
                public void onAnimationRepeat(Animation animation) {

                }
            });
            imageview.startAnimation(anim);
        }

This works fine for the most part, but if I rapidly click the button, the app crashes with the following NPE:

java.lang.NullPointerException: Attempt to read from field 'int android.view.View.mViewFlags' on a null object reference at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3398) at android.view.View.draw(View.java:16187) at android.view.View.updateDisplayListIfDirty(View.java:15180) at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:3593) at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:3573) at android.view.View.updateDisplayListIfDirty(View.java:15140) at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:3593) at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:3573) at android.view.View.updateDisplayListIfDirty(View.java:15140) at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:3593) at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:3573)

Any ideas as to why this is happening? Whats the fix?

Orbit
  • 2,985
  • 9
  • 49
  • 106

3 Answers3

0

Why use removeView() ?

Why not use

mRelativeLayout.setVisibility(View.GONE);

especially if you are just going to bring it back up again? Then, that way you don't have to keep recreating the View inside of the OnClick.

Currently, you are rapidly doing a MUCH more intensive operation than need be by creating and destroying a View constantly AND updating parameters that don't likely need to be reattached!

Do once, reuse.

childofthehorn
  • 697
  • 1
  • 4
  • 12
  • Im not bringing the view back, im deleting it. – Orbit Jan 22 '16 at 05:02
  • If it is in an onlcik and you are doing repeated operations, you are going to cause problems as you are asking to the system to create and destroy view items quickly with an animation and all of that running on the UI thread. Pull it out of the onClick and set the visibility in the xml to GONE first, then simply use the onClick to set the view visibility and also afterthe animation is done. Is there any possible reason why you have to destroy the view when visibility gets rid of it for you? – childofthehorn Jan 22 '16 at 05:10
  • The view fades out when the animation ends. The reason for deleting is so that it doesnt build up hundreds of invisible views if the button is spam clicked. – Orbit Jan 22 '16 at 05:37
  • Setting Visibility ensures that you DON't spin up hundreds of views. You only do it once. Then reuse it. That way, spam clicking it will have no affect. Why do you want to create a view inside, why not just set it back initialized to the 0-state? – childofthehorn Jan 22 '16 at 05:39
  • I think you're misunderstanding what im doing. – Orbit Jan 22 '16 at 05:40
  • Why not include the ImageView and your relative layout in an XML relative layout, initialize that. Then, use that overarching view to set the visibility with the default being android:visiblility="gone" ? That way, yu don't have to recreate it and reattach it at the bottom of your main RelativeLayout. – childofthehorn Jan 22 '16 at 05:45
0

It looks like the animation is not done with the view until after the onAnimationEnd is called.

You could try to set the visibility to gone and just delay the removeView call with Handler.

jab11
  • 867
  • 1
  • 8
  • 15
  • Well the image fades out so its not seen anyway, i just need a way to not build up 100+ invisible views if the user spam clicks the button. – Orbit Jan 22 '16 at 05:33
  • the .post() works because it queues the action after current tasks on the view run. so the animation has a chance to finish with the view before it's removed. it's only delayed because they call .post() on the view so it only gets to run when the view gets to update the UI. I still think postDelayed() would be better to ensure nobody is still using the view. – jab11 Jan 23 '16 at 19:52
0

Well, this seems to work: How to remove a View when animation ends?

Im not sure if theres another way or if anybody can confirm why the .post() works (it was mentioned in the comments but another confirmation would be good).

I wont mark this answered yet so that if someone has a better explanation or solution they can submit an answer.

Community
  • 1
  • 1
Orbit
  • 2,985
  • 9
  • 49
  • 106