SliceLiveData should remove observers.

As positions of items will be changed, new sliceViews will be created.
SliceLiveData has been set to observe a certain old sliceView. When the
page is re-launched, we cannot garantee we always get the same
sliceView, which means the sliceLiveData may be still observing a sliveView that
is no longer applicable. This will lead to broken slices.
Hence, we need to remove observers first then make it observes a new sliceView.

Bug: 117922624
Test: robotests, visual
Change-Id: I59368a6ce5fa84487c9a4788b970fdc074a0c2a9
This commit is contained in:
Emily Chuang
2018-10-18 21:01:25 +08:00
parent 4ae062b7c8
commit 8b680a988d
2 changed files with 25 additions and 7 deletions

View File

@@ -91,13 +91,15 @@ public class SliceContextualCardRenderer implements ContextualCardRenderer,
if (sliceLiveData == null) { if (sliceLiveData == null) {
sliceLiveData = SliceLiveData.fromUri(mContext, uri); sliceLiveData = SliceLiveData.fromUri(mContext, uri);
mSliceLiveDataMap.put(uri.toString(), sliceLiveData); mSliceLiveDataMap.put(uri.toString(), sliceLiveData);
}
sliceLiveData.removeObservers(mLifecycleOwner);
sliceLiveData.observe(mLifecycleOwner, slice -> { sliceLiveData.observe(mLifecycleOwner, slice -> {
if (slice == null) { if (slice == null) {
Log.w(TAG, "Slice is null"); Log.w(TAG, "Slice is null");
} }
cardHolder.sliceView.setSlice(slice); cardHolder.sliceView.setSlice(slice);
}); });
}
// Set this listener so we can log the interaction users make on the slice // Set this listener so we can log the interaction users make on the slice
cardHolder.sliceView.setOnSliceActionListener(this); cardHolder.sliceView.setOnSliceActionListener(this);

View File

@@ -18,7 +18,7 @@ package com.android.settings.homepage.slices;
import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify;
import android.content.Context; import android.content.Context;
import android.net.Uri; import android.net.Uri;
@@ -26,8 +26,10 @@ import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import androidx.lifecycle.LifecycleOwner; import androidx.lifecycle.LifecycleOwner;
import androidx.lifecycle.LiveData;
import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.RecyclerView;
import androidx.slice.Slice;
import com.android.settings.homepage.ContextualCard; import com.android.settings.homepage.ContextualCard;
import com.android.settings.homepage.PersonalSettingsFragment; import com.android.settings.homepage.PersonalSettingsFragment;
@@ -36,12 +38,16 @@ import com.android.settings.testutils.SettingsRobolectricTestRunner;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations; import org.mockito.MockitoAnnotations;
import org.robolectric.RuntimeEnvironment; import org.robolectric.RuntimeEnvironment;
@RunWith(SettingsRobolectricTestRunner.class) @RunWith(SettingsRobolectricTestRunner.class)
public class SliceContextualCardRendererTest { public class SliceContextualCardRendererTest {
@Mock
private LiveData<Slice> mSliceLiveData;
private Context mContext; private Context mContext;
private SliceContextualCardRenderer mRenderer; private SliceContextualCardRenderer mRenderer;
private LifecycleOwner mLifecycleOwner; private LifecycleOwner mLifecycleOwner;
@@ -96,6 +102,16 @@ public class SliceContextualCardRendererTest {
assertThat(mRenderer.mSliceLiveDataMap.get(sliceUri).hasObservers()).isTrue(); assertThat(mRenderer.mSliceLiveDataMap.get(sliceUri).hasObservers()).isTrue();
} }
@Test
public void bindview_sliceLiveDataShouldRemoveObservers() {
final String sliceUri = "content://com.android.settings.slices/action/flashlight";
mRenderer.mSliceLiveDataMap.put(sliceUri, mSliceLiveData);
mRenderer.bindView(getSliceViewHolder(), buildContextualCard(sliceUri));
verify(mSliceLiveData).removeObservers(mLifecycleOwner);
}
private RecyclerView.ViewHolder getSliceViewHolder() { private RecyclerView.ViewHolder getSliceViewHolder() {
final int viewType = mRenderer.getViewType(); final int viewType = mRenderer.getViewType();
final RecyclerView recyclerView = new RecyclerView(mContext); final RecyclerView recyclerView = new RecyclerView(mContext);