6

After searching lots of other SO questions and reading articles I'm still stuck as to why my implementation does not seem to perform as other examples.

I've read that it's recommended to use getViewLifecycleOwner() when registering any LiveData observers inside of a fragment to handle the lifecycle of the fragment correctly.

However, inside my fragment OnActivityCreated method (which gets called twice when the fragment is shown on the screen) I seem to get different LifecycleOwner objects from the call to getViewLifecycleOwner() which I beleive is the reason I'm getting multiple observers registered to my LiveData object.

How do I prevent this from happening / what am I doing wrong?

I've added lots of logging to the code as below:

MainActivity

   public class MainActivity extends AppCompatActivity {

        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);

            getSupportFragmentManager().beginTransaction()
                    .replace(R.id.fragment, new LiveDataTestFragment())
                    .commit();

            Log.d("debugger2", "Activity: " + this.hashCode());
        }
    }

LiveDataTestFragment

public class LiveDataTestFragment extends Fragment {

    private LiveDataViewModel viewModel;

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        return inflater.inflate(R.layout.fragment_live_data_test, container, false);
    }

    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);

        viewModel = ViewModelProviders.of(getActivity()).get(LiveDataViewModel.class);

        Log.d("debugger2", "ViewModel: " + viewModel.hashCode());

        LiveData<String> liveData = viewModel.getLiveData();
        Log.d("debugger2", "LiveData: " + liveData.hashCode());

        LifecycleOwner lifecycleOwner = getViewLifecycleOwner();
        Log.d("debugger2", "LifeCycleOwner: " + lifecycleOwner.hashCode());

        liveData.observe(lifecycleOwner, new Observer<String>() {
            @Override
            public void onChanged(String s) {
                Log.d("debugger2", "observer hash: " + this.hashCode());
            }
        });
    }
}

Logcat:

D: Activity: 242098714
D: ViewModel: 149122972
D: LiveData: 58736037
D: LifeCycleOwner: 50378106
D: ViewModel: 149122972
D: LiveData: 58736037
D: LifeCycleOwner: 245135826
D: observer hash: 204470220
D: observer hash: 226765595
Alex Newton
  • 163
  • 3
  • 17
  • It's creating **multiple observers** because, you're providing multiple observers using `new Observer` inside `observe()` method. Create **global variable** for observer and add it your observe method. *Also make sure you remove observer when fragment destroyed.* – Jeel Vankhede Sep 21 '19 at 12:37
  • That's not how it's set up in google samples: [link](https://google-developer-training.github.io/android-developer-advanced-course-practicals/unit-6-working-with-architecture-components/lesson-14-room,-livedata,-viewmodel/14-1-a-room-livedata-viewmodel/14-1-a-room-livedata-viewmodel.html#task11intro) or [link](https://github.com/googlesamples/android-architecture-components/blob/master/BasicSample/app/src/main/java/com/example/android/persistence/ui/ProductListFragment.java) for example – Alex Newton Sep 21 '19 at 13:29

3 Answers3

1
new Observer<String>() {
            @Override
            public void onChanged(String s) {
                Log.d("debugger2", "observer hash: " + this.hashCode());
            }
        }

May be this portion of your observer is responsible to create multiple hashCode() You can create this observer just for a single time and call it multiple times if you need using the following code:

private Observer<String> singleObserver = Observer<String>() {
                @Override
                public void onChanged(String s) {
                    Log.d("debugger2", "observer hash: " + this.hashCode());
                }
}

and use it like:

// your previous code
LiveData<String> liveData = viewModel.getLiveData();
liveData.observe(lifecycleOwner, singleObserver);
// rest of your code

Hope it will work.

A S M Sayem
  • 2,010
  • 2
  • 21
  • 28
  • That's not how it's set up in google samples: [link](https://google-developer-training.github.io/android-developer-advanced-course-practicals/unit-6-working-with-architecture-components/lesson-14-room,-livedata,-viewmodel/14-1-a-room-livedata-viewmodel/14-1-a-room-livedata-viewmodel.html#task11intro) or [link](https://github.com/googlesamples/android-architecture-components/blob/master/BasicSample/app/src/main/java/com/example/android/persistence/ui/ProductListFragment.java) for example – Alex Newton Sep 21 '19 at 13:24
  • Please read the document again carefully. I am sharing a code snippet from LiveData and Observer into the edited version of my answer. check this link for documentation [https://developer.android.com/topic/libraries/architecture/livedata ] – A S M Sayem Sep 21 '19 at 13:29
0

I've figured out the issue. Thanks for the answers regardless!

I'll put the issue here even though it's unlikely anyone else will do what I did!

My activity_main.xml contained

<fragment
    android:name="com.test.livedatatestapp.LiveDataTestFragment"
    android:id="@+id/fragment"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

which was creating an instance of the Fragment class, which I was then immediately replacing inside MainActivity by replacing the Fragment, hence the duplicates...

Alex Newton
  • 163
  • 3
  • 17
0

You need to remove the observer before making an observer.

David K. Lee
  • 131
  • 1
  • 4