Search code examples
androidcanvasmvvmandroid-livedataandroid-viewmodel

Android pause an observer when view is removed


I have two custom views (canvas views) and both of them have an observer which triggers an event on the screen and draw something on canvas. I am reusing the container and rendering the canvas in the same parent layout by removing other views. Right now, no matter what my both view observer values.

I have tried an dirty hack where I am passing a boolan to both views as true being one and other being false on switch which kinda work but I don't want that. Because it is just a hack. Can anyone tell me an android way to do it?

public class FakeViewOne extends View {

    private EventViewModel eventViewModel;
    private float l = 0.0f;
    public FakeViewOne(Context context, View ParentView) {
        super(context);
        eventViewModel = new ViewModelProvider((ViewModelStoreOwner) getContext()).get(EventViewModel.class);

        eventViewModel.getTrigger().observe((LifecycleOwner) getContext(), new Observer<Float>() {
            @Override
            public void onChanged(Float val) {
                l = val;
            }
        });

    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        /*
        *  if l > 50 change background of a linearlayout
        *  draw a line on a canvas
        * */
        invalidate();
    } 
}


    public class FakeViewTwo extends View {

        private EventViewModel eventViewModel;
        private float l = 0.0f;
        public FakeViewTwo(Context context, View ParentView) {
            super(context);
            eventViewModel = new ViewModelProvider((ViewModelStoreOwner) getContext()).get(EventViewModel.class);

            eventViewModel.getTrigger().observe((LifecycleOwner) getContext(), new Observer<Float>() {
                @Override
                public void onChanged(Float val) {
                    l = val;
                }
            });

        }

        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            /*
            *  if l > 50 change background of a tile
            * 
            * */
            invalidate();
        } 
    } 

CODE Inside a Fragment where I am switch between those two FakeViews. How can I make those not observe values when they are not-rendered/inactive/removed from the view. I am using mycanvas.removeAllViews();.

final RelativeLayout mycanvas = view.findViewById(R.id.myCanvas);
        gestureViewModel.getGestureType().observe(getActivity(), new Observer<String>() {
            @Override
            public void onChanged(@Nullable String s) {
                assert s != null;
                mycanvas.removeAllViews();
                switch (s){
                    case "shake":
                        ShakeControl(view,myView,mycanvas);
                        break;
                    case "move":
                        MoveControl(view,myView,mycanvas);
                        break; 
                } 
            }
        });

Solution

  • I have solved the problem with removing the observers on window detach in each FakeView.

    @Override
        protected void onDetachedFromWindow() {
            super.onDetachedFromWindow();
            Log.d("Detached","Head");
            if (eventViewModel != null && eventViewModel.getTrigger().hasObservers()) {
                eventViewModel.getTrigger().removeObservers((LifecycleOwner) ctx);
            }
        }