RecyclerView утечки в FragmentPagerAdapter
Я выяснил, что в определенных обстоятельствах RecyclerView приводит к утечке памяти. Чтобы заархивировать такой эффект, я создал FragmentPagerAdapter, который содержит фрагмент с RecyclerView в качестве дочернего. В случае перехода приложения в фоновый режим или завершения, утечка канарейки выдает предупреждение об утечке памяти Вот мой класс деятельности
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
ViewPager mViewPager = (ViewPager) findViewById(R.id.view_pager);
List<Fragment> fragments = new LinkedList<>();
for (int i = 0; i < 10; i++) {
fragments.add(CustomFragment.newInstance(i));
}
mViewPager.setAdapter(new CustomPagerAdapter(getFragmentManager(), fragments));
mViewPager.setCurrentItem(0, false);
}
public class CustomPagerAdapter extends FragmentPagerAdapter {
private List<Fragment> fragments;
public CustomPagerAdapter(FragmentManager fragmentManager, List<Fragment> fragments) {
super(fragmentManager);
this.fragments = fragments;
}
@Override
public Fragment getItem(int position) {
return fragments.get(position);
}
@Override
public int getCount() {
return fragments.size();
}
}
}
Чтобы получить утечку, RecyclerView даже не нужно инициализировать. Если я прокомментирую это в XML-файле, утечка не будет запущена
public class CustomFragment extends Fragment {
public static final String POSITION = "position";
public static CustomFragment newInstance(int position) {
Bundle b = new Bundle();
b.putInt(POSITION, position);
CustomFragment fragment = new CustomFragment();
fragment.setArguments(b);
return fragment;
}
private int position;
private RecyclerView recyclerView;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
position = getArguments().getInt(POSITION);
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_custom, container, false);
TextView textView = (TextView) v.findViewById(R.id.text);
textView.setText("Position: "+position);
recyclerView = (RecyclerView) v.findViewById(R.id.pulse_recyclerview);
return v;
}
@Override
public void onDestroy() {
super.onDestroy();
RefWatcher refWatcher = CustomApplication.getRefWatcher(getActivity());
refWatcher.watch(this);
}
}
Вот след утечки. RecyclerView версия 23.1.1
In com.example.gabin.sampleapplication:1.0:1.
* LEAK CAN BE IGNORED.
* com.example.gabin.sampleapplication.MainActivity has leaked:
* GC ROOT static android.view.inputmethod.InputMethodManager.sInstance
* references android.view.inputmethod.InputMethodManager.mCurRootView
* references com.android.internal.policy.impl.PhoneWindow$DecorView.mContext
* leaks com.example.gabin.sampleapplication.MainActivity instance
* Retaining: 3,9 КБ.
* Reference Key: 67c5e9f4-464e-40c3-b21d-d802fe64a84b
* Device: LGE google Nexus 4 occam
* Android Version: 5.1.1 API: 22 LeakCanary: 1.4-beta1 02804f3
* Durations: watch=5035ms, gc=190ms, heap dump=5948ms, analysis=46384ms
Может ли это быть ошибка Android? Пожалуйста, дайте какие-либо идеи, как устранить утечку, или помогите мне выяснить причину ее возникновения при утечке.
1 ответ
Ваша трассировка стека показывает как минимум две вещи:
- Это не RecyclerView, кто пропускает активность. Это ImputMethodManager.
- УТЕЧКА МОЖЕТ БЫТЬ ИГНОРИРОВАНА. Согласно Leak Canary Docs, это известная проблема SDK. Но я не думаю, что это действительно утечка активности. Если вы проверите свой дамп памяти, вы не увидите несколько экземпляров активности. Код выглядит довольно безопасно в настоящее время.