0

I have a problem that is driving me nuts and been searching several hours around the web but cant find a solution. I want to set an animation on the first view in my recyclerview when I add new data to the list. But I cant because the recyclerview is null.

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    orientation = getResources().getConfiguration().orientation;

    model = ViewModelProviders.of(getActivity()).get(ViewModelAdvices.class);
    model.getAdvices().observe(this, new Observer <List <Advice>>() {

        //Update recyclerview automatically when data is changed
        @Override
        public void onChanged(List <Advice> advices) {
            filtered_advices_list.clear();
            filtered_advices_list.addAll(advices);
            adapter_recycler_view.notifyDataSetChanged();

        }
    });
}

@Override
public void onResume() {
    super.onResume();
    Animation animation = AnimationUtils.loadAnimation(getContext(), R.anim.test_item);
    View v = recycler_view.getChildAt(0);
    v.startAnimation(animation);

}



@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    View view = inflater.inflate(R.layout.show_advices_fragment, container, false);

    setupLayoutDifferences(view);

    recycler_view = (RecyclerView) view.findViewById(R.id.recycler_view);
    layout_manager = new LinearLayoutManager(getContext());
    recycler_view.setLayoutManager(layout_manager);
    adapter_recycler_view = new AdapterRV(filtered_advices_list);
    recycler_view.setAdapter(adapter_recycler_view);

 spinner_1 = (Spinner) view.findViewById(R.id.spinner_1);
    adapter_spinner_1 = ArrayAdapter.createFromResource(view.getContext(), R.array.categories, android.R.layout.simple_spinner_item);
    adapter_spinner_1.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
    spinner_1.setAdapter(adapter_spinner_1);

    spinner_1.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
        @Override
        public void onItemSelected(AdapterView <?> parent, View view, int position, long id) {
            String category = spinner_1.getItemAtPosition(spinner_1.getSelectedItemPosition()).toString();
            model.setCategory(category);
        }
        @Override
        public void onNothingSelected(AdapterView <?> parent) { }
    });

    return view;
    }
} 

show_advices_fragment

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:background="@color/colorBlueGreen"
        android:paddingBottom="6dp">



    <Spinner
            android:id="@+id/spinner_1"
            android:layout_width="match_parent"
            android:layout_height="50dp"
            android:backgroundTint="@color/colorBlack" />

        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_gravity="bottom">

            <Button
                android:id="@+id/button_add_activity"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_alignParentBottom="true"
                android:layout_marginTop="6dp"
                android:layout_marginLeft="6dp"
                android:layout_marginRight="6dp"
                android:visibility="gone"
                android:text="@string/button_add_activity" />

            <androidx.recyclerview.widget.RecyclerView
                android:id="@+id/recycler_view"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:layout_above="@+id/button_add_activity"
                android:background="@color/colorLightGrey"
                android:scrollbars="vertical"
                />

        </RelativeLayout>

    </LinearLayout>

list_item_activity_main

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="4dp"
android:background="@color/colorWhite"
android:orientation="horizontal"
android:paddingBottom="5dp"
android:paddingTop="5dp"
android:paddingLeft="3dp"
android:paddingRight="3dp"
android:weightSum="3">

<TextView
    android:id="@+id/text_view_advice"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@drawable/border"
    android:textColor="@color/colorPrimary"
    android:paddingRight="4dp"
    android:layout_weight="1"
    android:text="TextView" />

<TextView
    android:id="@+id/text_view_author"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:textColor="@color/colorGrey"
    android:layout_weight="2"
    android:gravity="center"
    android:text="TextView" />

 </LinearLayout>

And test_item

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="@android:integer/config_longAnimTime">

    <translate
        android:interpolator="@android:anim/decelerate_interpolator"
        android:fromXDelta="100%p"
        android:toXDelta="0"
        />

    <alpha
        android:fromAlpha="0.5"
        android:toAlpha="1"
        android:interpolator="@android:anim/accelerate_decelerate_interpolator"
        />

</set>

In the onResume I am in the last lifecycle I suppose and the recyclerview is being build up already in onCreateView. I guess that the build-up of the recyclerview aint finished before I reach onResume, but how can I solve this? If I do the animation with a mouseclick when the fragment is already loaded it works but not when I switch fragment and the recyclerview is being built up again.

potatoman
  • 11
  • 1
  • 1
    show your layout file – Marcin Orlowski Apr 10 '19 at 23:16
  • I createt a thread for my animation and it worked if I slept over 200ms. Its probably something with my ViewModel and Livedata that causes the problem. – potatoman Apr 10 '19 at 23:41
  • its your onResume method. onResume is always called first before all of your methods. if you want to do animation from onResume method then just put all the recyclerview setup code in on resume also. otherwise move your animation code to onCreateView after recycler setup. You can put `if(recycler_view!=null)` then do animation to avoid crash. it will also tell you that you if recycler view was initialised or not if animation works. – Faisal Apr 11 '19 at 00:25

3 Answers3

0

Try this

@Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        orientation = getResources().getConfiguration().orientation;

        model = ViewModelProviders.of(getActivity()).get(ViewModelAdvices.class);
        model.getAdvices().observe(this, new Observer<List<Advice>>() {

            //Update recyclerview automatically when data is changed
            @Override
            public void onChanged(List<Advice> advices) {
                filtered_advices_list.clear();
                filtered_advices_list.addAll(advices);

            }
        });
    }

    @Override
    public void onResume() {
        super.onResume();
        Animation animation = AnimationUtils.loadAnimation(getContext(), R.anim.test_item);
        View v = recycler_view.getChildAt(0);
        v.startAnimation(animation);

    }


    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.show_advices_fragment, container, false);

        setupLayoutDifferences(view);

        recycler_view = (RecyclerView) view.findViewById(R.id.recycler_view);
        layout_manager = new LinearLayoutManager(getContext());
        recycler_view.setLayoutManager(layout_manager);
        populateAdapter();


        spinner_1 = (Spinner) view.findViewById(R.id.spinner_1);
        adapter_spinner_1 = ArrayAdapter.createFromResource(view.getContext(), R.array.categories, android.R.layout.simple_spinner_item);
        adapter_spinner_1.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
        spinner_1.setAdapter(adapter_spinner_1);

        spinner_1.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
            @Override
            public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
                String category = spinner_1.getItemAtPosition(spinner_1.getSelectedItemPosition()).toString();
                model.setCategory(category);
            }

            @Override
            public void onNothingSelected(AdapterView<?> parent) {
            }
        });

        if (adapter_recycler_view != null){
            adapter_recycler_view.notifyDataSetChanged();
        }

        return view;
    }

    private void populateAdapter() {
        adapter_recycler_view = new AdapterRV(filtered_advices_list);
        recycler_view.setAdapter(adapter_recycler_view);
    }
VIISHRUT MAVANII
  • 11,410
  • 7
  • 34
  • 49
0

You can't depends on onResume() in Fragment, because it's not 100% called after onCreateView() on some Android versions (More details at Fragment onResume() & onPause() is not called on backstack). So, there is a probability that you're fragment layout creation is not yet finished.

You can wait until the RecyclerView is finished inflating all the items with OnGlobalLayoutListener then show the animation for the first item:

recycler_view.getViewTreeObserver()
             .addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
                 @Override
                public void onGlobalLayout() {

                  // show the animation
                  Animation animation = AnimationUtils.loadAnimation(getContext(), R.anim.test_item);
                  View v = recycler_view.getChildAt(0);
                  v.startAnimation(animation);

                  // remove listener so that this won't be called multiple time.
                  recycler_view.getViewTreeObserver().removeOnGlobalLayoutListener(this);
            }
        }); 
ישו אוהב אותך
  • 28,609
  • 11
  • 78
  • 96
0

Thank you for trying to help me. Problem is that my application is probably not the best organized so everything runs before my recyclerview is done with the list it gets from ViewModel. But doing the animation on a separate thread works like a charm, then I also have full control over the animation.

if(action.equals("addData")) {

            Thread thread = new Thread() {
                @Override
                public void run() {
                    try {

                        boolean recycler_view_loading = true;

                        while(recycler_view_loading ) {
                            sleep(250);

                            if (recycler_view.getChildAt(0) != null) {

                                Animation animation = AnimationUtils.loadAnimation(getContext(), R.anim.item_animation_side);
                                View v = recycler_view.getChildAt(0);
                                v.startAnimation(animation);
                                recycler_view_loading  = false;
                            }
                        }
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            };
            thread.start();
        }
potatoman
  • 11
  • 1