android - Will Looping a Runnable Cause a Memory Leak -
hi have large memory leak in app , think it's being caused runnables. here example of skeleton of runnables use:
private runnable randomalienfire = new runnable() { public void run() { /*a bunch of computations */ mainhandler.removecallbacks(randomalienfire); mainhandler.postdelayed(randomalienfire, number ); } when switch activities call mainhandler.removecallbacksandmessages(null); , thread.randomalienfire = null; yet still leaking entire activity. question is, there in basic skeleton causing memory leak? fact handler calling itself?
yes, implementation cause memory leak (i ran myself).
the problem have created circular reference. have declared runnable non-static inner class, means automatically maintain reference activity. runnable member variable of activity, closes circle. garbage collector never able free these objects since there living reference.
using static inner class weak reference activity safest way fix problem. you can see great code example here. if mainhandler non-static inner class, create second circular reference same reasons have same thing there.
setting mainhandler.removecallbacksandmessages(null); , thread.randomalienfire = null; work, have careful put code. perhaps code taking different path expect in cases , missing calls? this blog post describes else's similar experience approach.
in case, using runnable sequence animations on imageviews. rid of memory leaks, created static runnable class avoid circular reference. alone not enough me, found drawable still retaining reference fragment. calling myimageview.removecallbacksandmessages(arrowanimationrunnable); in ondestroy() in fragment solved leak. here solution:
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) { } } // anonymous instance of new runnable class not retain reference fragment private runnable arrowanimationrunnable = new saferunnable(this) { @override public void runwithparent(myfragment parent) { // ... animation code // repeat 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 image view , kick off 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 remove callbacks here, otherwise message // sitting in queue , outlive fragment. because // reference in message still pointing fragment, // fragment (and else) not garbage collected myimageview.removecallbacks(arrowanimationrunnable); } }
Comments
Post a Comment