Да, ваша реализация обязательно вызовет утечку памяти (я сам столкнулся с этим).
Проблема в том, что вы создали круговую ссылку. Вы объявили свой runnable как нестатический внутренний класс, что означает, что он будет автоматически поддерживать ссылку на действие. Сам runnable - это переменная-член вашей активности, которая замыкает круг. Сборщик мусора никогда не сможет освободить эти объекты, поскольку всегда будет живая ссылка.
Использование статического внутреннего класса со слабой ссылкой на действие - самый безопасный способ решить проблему. Здесь вы можете увидеть отличный пример кода. Если mainHandler является другим нестатическим внутренним классом, он создаст вторую циклическую ссылку по тем же причинам, поэтому вам придется проделать то же самое там.
Установка mainHandler.removeCallbacksAndMessages(null);
и thread.randomAlienFire = null;
также может работать, но вы должны быть очень осторожны при размещении этого кода. Возможно, в некоторых случаях код идет по другому пути, чем вы ожидаете, и пропускает эти вызовы? В этом сообщении блога описывается очень похожий опыт кого-то другого с этим подходом.
В моем случае я использовал runnable для последовательной анимации в ImageViews. чтобы избавиться от утечек памяти, я создал статический исполняемый класс, чтобы избежать циклической ссылки. Одного этого для меня было недостаточно, я также обнаружил, что drawable все еще сохраняет ссылку на мой фрагмент. вызов myImageView.removeCallbacksAndMessages(arrowAnimationRunnable);
в onDestroy () в моем фрагменте окончательно устранил утечку. вот мое решение:
public class MyFragment extends SherlockFragment {
public static class SafeRunnable implements Runnable {
private final WeakReference<MyFragment> parentReference;
public SafeRunnable(MyFragment parent) {
parentReference = new WeakReference<MyFragment>(parent);
}
@Override
public void run() {
if (parentReference != null) {
final MyFragment parent = parentReference.get();
if (parent != null) {
runWithParent(parent);
}
}
}
public void runWithParent(MyFragment parent) {
}
}
// This anonymous instance of the new runnable class does not retain a
reference to the fragment
private Runnable arrowAnimationRunnable = new SafeRunnable(this) {
@Override
public void runWithParent(MyFragment parent) {
// ... animation code
// repeat the animation in 1 second
parent.myImageView.postDelayed(this, 1000);
}
};
private ImageView myImageView;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.my_layout, container, false);
// find the image view and kick off the animation after 1 second
myImageView = (ImageView) view.findViewById(R.id.iv_arrow);
myImageView.postDelayed(arrowAnimationRunnable, 1000);
return view;
}
@Override
public void onDestroyView() {
super.onDestroyView();
// It's necessary to remove the callbacks here, otherwise a message will
// be sitting in the queue and will outlive the fragment. Because a
// reference in that message will still be pointing to the fragment, the
// fragment (and everything else) will not be garbage collected
myImageView.removeCallbacks(arrowAnimationRunnable);
}
}
person
jzn
schedule
07.11.2013