android - A line of code is causing memory leaks in my app -
a single line of code causing memory leaks in app. i've debugged more 200 times still cannot find reason of leak. i've compared content provider implementation other have , code same. app works well,except when rotate device app leakcanary detects leak. loaders seems constructed also. highly appreciated.
this line of code causing memory leak:(if comment out line of code memory leaks disapperas, list not filled data)
madapterindexes.swapcursor(data); this fragment use loader:
public class fragmentamerica extends fragment implements loadermanager.loadercallbacks<cursor> { private nonscrolllistview mnewslistview; private nonscrolllistview mindexeslistview; private scrollview mscrollview; private boolean mrotationdone=false; private static final string key_posx="x_pos"; private static final string key_posy="y_pos"; private static final int news_loader=0; private static final int indexes_loader=1; private rssnewsadapter madapter; private indexesadapter madapterindexes; // private indexesadapter madapterindexes; private static final string selectionnews =capstonecontract.newsentity.region + " =?"; private static final string[] selectionargsnews =new string[]{"america"}; private static final string selectionindexes=capstonecontract.indexesentity.region + " =?"; private static final string[] selectionargsindexes=new string[]{"america"}; private static final string sortbydatedesc = capstonecontract.newsentity.date + " desc"; private int x; private int y; linearlistview.onitemclicklistener mlistener = new linearlistview.onitemclicklistener() { @override public void onitemclick(linearlistview parent, view view, int position,long id) { final textview tvlink,tvtitle; tvlink= (textview) view.findviewbyid(r.id.txturllink); tvtitle= (textview) view.findviewbyid(r.id.txttitulo); uri uri=null; uri = uri.parse(tvlink.gettext().tostring()); //customization possibilities customtabsintent customtabsintent = new customtabsintent.builder() .settoolbarcolor(contextcompat.getcolor(getactivity(),r.color.colorprimary)) .setshowtitle(true) .build(); customtabactivityhelper.opencustomtab(getactivity(), customtabsintent,uri, //in case user doen't have chromium v 45 installed, offer alternative //browser experience webview new customtabactivityhelper.customtabfallback() { @override public void openuri(activity activity, uri uri) { intent intent=new intent(getactivity(),detailsnewsactivity.class); intent.putextra("url",tvlink.gettext()); intent.putextra("title",tvtitle.gettext()); startactivity(intent); } }); } }; @override public void onactivitycreated(@nullable bundle savedinstancestate) { //getactivity().getsupportloadermanager().initloader(indexes_loader, null, this); getloadermanager().initloader(news_loader,null,this); //getactivity().getsupportloadermanager().initloader(news_loader, null, this); getloadermanager().initloader(indexes_loader,null,this); super.onactivitycreated(savedinstancestate); } @nullable @override public view oncreateview(layoutinflater inflater, @nullable viewgroup container, @nullable bundle savedinstancestate) { view view=inflater.inflate(r.layout.fragment_america,container,false); mnewslistview = (nonscrolllistview) view.findviewbyid(r.id.newslist); mindexeslistview= (nonscrolllistview) view.findviewbyid(r.id.indexeslist); mscrollview= (scrollview) view.findviewbyid(r.id.scrollviewam); mscrollview.getviewtreeobserver().addonscrollchangedlistener(new viewtreeobserver.onscrollchangedlistener() { @override public void onscrollchanged() { x=mscrollview.getscrollx(); log.d("villanueva","x pos:"+mscrollview.getscrollx()+",y pos:"+mscrollview.getscrolly()); y=mscrollview.getscrolly(); } }); madapter =new rssnewsadapter(getactivity(),null,news_loader); madapterindexes=new indexesadapter(getactivity(),null,indexes_loader); //set both adapters mindexeslistview.setadapter(madapterindexes); mnewslistview.setadapter(madapter); // mnewslistview.setonitemclicklistener(mlistener); if(savedinstancestate==null) { } else { mrotationdone=true; //scroll saved position mscrollview.scrollto(savedinstancestate.getint(key_posx),savedinstancestate.getint(key_posy)); } toast.maketext(getactivity(),"oncreateviewamerica",toast.length_short).show(); return view; } @override public void onresume() { super.onresume(); toast.maketext(getactivity(),"onresumeamerica",toast.length_short).show(); } @override public void onsaveinstancestate(bundle outstate) { super.onsaveinstancestate(outstate); outstate.putint(key_posx,mscrollview.getscrollx()); outstate.putint(key_posy,mscrollview.getscrolly()); } @override public loader<cursor> oncreateloader(int id, bundle args) { if (id==indexes_loader) { return new cursorloader(getactivity().getapplicationcontext(), capstonecontract.indexesentity.content_uri,null,selectionindexes,selectionargsindexes,null); } else if(id==news_loader) { return new cursorloader(getactivity().getapplicationcontext(), capstonecontract.newsentity.content_uri, null, selectionnews, selectionargsnews, sortbydatedesc); } return null; } @override public void onloadfinished(loader<cursor> loader, cursor data) { switch(loader.getid()) { case indexes_loader: madapterindexes.swapcursor(data); //if comment out line //line of code app works fine break; case news_loader: madapter.swapcursor(data); break; } // mscrollview.postdelayed(new runnable() { // @override // public void run() { // mscrollview.scrollto(x,y); // } // },200); log.d("villanueva","move x pos:"+x+",y pos:"+y); } @override public void onloaderreset(loader<cursor> loader) { switch(loader.getid()) { case news_loader: madapter.swapcursor(null); break; case indexes_loader: madapterindexes.swapcursor(null); break; } } @override public void ondestroy() { super.ondestroy(); // exampleapplication application = (exampleapplication) getactivity().getapplicationcontext(); // application.mustdie(this); } } this query methond in content provider:
@nullable @override public cursor query(uri uri, string[] projection, string selection, string[] selectionargs, string sortorder) { cursor retcursor=null; final int match = murimatcher.match(uri); switch (match) { case news: retcursor=mdbhelper.getreadabledatabase().query( capstonecontract.newsentity.table_name, projection, selection, selectionargs, null, //group null, //having sortorder); break; case index: retcursor=mdbhelper.getreadabledatabase().query( capstonecontract.indexesentity.table_name, projection, selection, selectionargs, null, null, sortorder); break; default: throw new unsupportedoperationexception("unknown uri" + uri); } retcursor.setnotificationuri(getcontext().getcontentresolver(),uri); return retcursor; } canaryleak log:
02-06 12:22:41.195 7809-8716/com.carlos.capstone d/leakcanary: in com.carlos.capstone:1.0:1. 02-06 12:22:41.195 7809-8716/com.carlos.capstone d/leakcanary: * com.carlos.capstone.mainactivity has leaked: 02-06 12:22:41.195 7809-8716/com.carlos.capstone d/leakcanary: * gc root static android.view.windowmanagerglobal.sdefaultwindowmanager 02-06 12:22:41.195 7809-8716/com.carlos.capstone d/leakcanary: * references android.view.windowmanagerglobal.mviews 02-06 12:22:41.195 7809-8716/com.carlos.capstone d/leakcanary: * references java.util.arraylist.array 02-06 12:22:41.195 7809-8716/com.carlos.capstone d/leakcanary: * references array java.lang.object[].[0] 02-06 12:22:41.195 7809-8716/com.carlos.capstone d/leakcanary: * references com.android.internal.policy.impl.phonewindow$decorview.mattachinfo 02-06 12:22:41.195 7809-8716/com.carlos.capstone d/leakcanary: * references android.view.view$attachinfo.mscrollcontainers 02-06 12:22:41.195 7809-8716/com.carlos.capstone d/leakcanary: * references java.util.arraylist.array 02-06 12:22:41.195 7809-8716/com.carlos.capstone d/leakcanary: * references array java.lang.object[].[1] 02-06 12:22:41.195 7809-8716/com.carlos.capstone d/leakcanary: * references com.carlos.capstone.customcomponents.nonscrolllistview.madapter 02-06 12:22:41.195 7809-8716/com.carlos.capstone d/leakcanary: * references com.carlos.capstone.adapters.indexesadapter.mcursor 02-06 12:22:41.195 7809-8716/com.carlos.capstone d/leakcanary: * references android.content.contentresolver$cursorwrapperinner.mcursor 02-06 12:22:41.195 7809-8716/com.carlos.capstone d/leakcanary: * references android.database.sqlite.sqlitecursor.mdatasetobservable 02-06 12:22:41.195 7809-8716/com.carlos.capstone d/leakcanary: * references android.database.datasetobservable.mobservers 02-06 12:22:41.195 7809-8716/com.carlos.capstone d/leakcanary: * references java.util.arraylist.array 02-06 12:22:41.195 7809-8716/com.carlos.capstone d/leakcanary: * references array java.lang.object[].[0] 02-06 12:22:41.195 7809-8716/com.carlos.capstone d/leakcanary: * references android.widget.cursoradapter$mydatasetobserver.this$0 02-06 12:22:41.195 7809-8716/com.carlos.capstone d/leakcanary: * references com.carlos.capstone.adapters.indexesadapter.mcontext 02-06 12:22:41.195 7809-8716/com.carlos.capstone d/leakcanary: * leaks com.carlos.capstone.mainactivity instance 02-06 12:22:41.195 7809-8716/com.carlos.capstone d/leakcanary: * reference key: 08e1a3e5-78cd-4f09-8cc7-1c307201d763 02-06 12:22:41.195 7809-8716/com.carlos.capstone d/leakcanary: * device: genymotion generic google nexus 5 - 5.1.0 - api 22 - 1080x1920 vbox86p 02-06 12:22:41.195 7809-8716/com.carlos.capstone d/leakcanary: * android version: 5.1 api: 22 leakcanary: 1.3.1 02-06 12:22:41.195 7809-8716/com.carlos.capstone d/leakcanary: * durations: watch=6235ms, gc=114ms, heap dump=983ms, analysis=4339ms 02-06 12:22:41.195 7809-8716/com.carlos.capstone d/leakcanary: * details: updated nonscrolllistview class
public class nonscrolllistview extends listview { public nonscrolllistview(context context) { super(context); } public nonscrolllistview(context context, attributeset attrs) { super(context, attrs); } public nonscrolllistview(context context, attributeset attrs, int defstyle) { super(context, attrs, defstyle); } @override public void onmeasure(int widthmeasurespec, int heightmeasurespec) { int heightmeasurespec_custom = measurespec.makemeasurespec(integer.max_value >> 2, measurespec.at_most); super.onmeasure(widthmeasurespec, heightmeasurespec_custom); viewgroup.layoutparams params = getlayoutparams(); params.height = getmeasuredheight(); } } updated 2 solution:
@override public void onloadfinished(loader<cursor> loader, cursor data) { mcursor=data; switch(loader.getid()) { case indexes_loader: log.d(log_tag,"onloadfinished indexes_loader"); madapterindexes.swapcursor(mcursor); break; case news_loader: log.d(log_tag,"onloadfinished news_loader"); madapternews.swapcursor(mcursor); } } and following:
public void ondestroy() { if(mcursor!=null && !mcursor.isclosed()) { mcursor.close(); } super.ondestroy(); }
i have been through similar situation not in case of loader. main reason behind leak cursor still open while orientation getting changed. in code see same reason returning cursor on query method. try implement cursor.close() on orientation change , re-query once orientation change complete.
Comments
Post a Comment