当前位置: 首页 > news >正文

公司网站改版需要怎么做/国外b站浏览器

公司网站改版需要怎么做,国外b站浏览器,商标查询网入口,德商网站建设原创 herculeshhp 转载请注明作者和出处 背景说明 为了使问题更加清晰,我将出现问题的场景进行简化抽象。现在有一个Activity,其主体是一个ListView。ListView包含了多个模块,每个模块都对应着自己的视图。每个模块都实现了一个接口Section: …

原创 @herculeshhp 转载请注明作者和出处

背景说明

为了使问题更加清晰,我将出现问题的场景进行简化抽象。现在有一个Activity,其主体是一个ListViewListView包含了多个模块,每个模块都对应着自己的视图。每个模块都实现了一个接口Section:

public interface Section {public View getView(int position, View convertView, ViewGroup parent);
}
复制代码

ListView的adapter的getView会调用各个SectiongetView来获取不同模块的视图。

现在有一个模块TestSection对应的视图是一个横向的RecyclerView,核心代码如下:

public class TestSection implements Section {RecyclerView mRecyclerView;public View getView(int position, View convertView, ViewGroup parent) {if (mRecyclerView == null) {mRecyclerView = new RecyclerView(parent.getContext());mRecyclerView.setLayoutManager(new LinearLayoutManager(parent.getContext(), LinearLayoutManager.HORIZONTAL, false));}return mRecyclerView;}
}
复制代码

ListView支持下拉刷新。刷新之后,ListView会清除原有的所有Section,然后根据新的数据创建新的Section集合。而内存泄漏就在下拉刷新之后出现了!

LeakCanary给出的信息如下:

  • org.chromium.base.SystemMessageHandler.mLooper
  • references android.os.Looper.mThread
  • references thread java.lang.Thread.localValues (named 'main')
  • references java.lang.ThreadLocal$Values.table
  • references array java.lang.Object[].[31]
  • references android.support.v7.widget.GapWorker.mRecyclerViews
  • references java.util.ArrayList.array
  • references array java.lang.Object[].[23]
  • references android.support.v7.widget.RecyclerView.mContext
  • references com.test.TestActivity

问题探究

LeakCanary给出的信息中有一个比较好的入手点,就是android.support.v7.widget.GapWorker.mRecyclerViews. 那就来看看这个GapWorker是何方神圣。

final class GapWorker implements Runnable {static final ThreadLocal<GapWorker> sGapWorker = new ThreadLocal<>();ArrayList<RecyclerView> mRecyclerViews = new ArrayList<>();...
}
复制代码

GapWorker里有两个关键的成员sGapWorkermRecyclerViews。根据LeakCanary的信息正是这个mRecyclerViews引用了TestSection中的mRecyclerView导致了内存泄露。注意到sGapWorkerstatic的,初步可以推断是这个静态的sGapWorker引用了一个GapWorker实例,而那个GapWorker实例中的mRecyclerViews又引用了TestSection中的mRecyclerView导致了内存泄露。接下来就要寻找GapWorkerRecyclerView的联系。关键代码如下:

public class RecyclerView extends ViewGroup implements ScrollingView, NestedScrollingChild {...GapWorker mGapWorker;...private static final boolean ALLOW_THREAD_GAP_WORK = Build.VERSION.SDK_INT >= 21;...@Overrideprotected void onAttachedToWindow() {...if (ALLOW_THREAD_GAP_WORK) {// Register with gap workermGapWorker = GapWorker.sGapWorker.get();if (mGapWorker == null) {mGapWorker = new GapWorker();...GapWorker.sGapWorker.set(mGapWorker);}mGapWorker.add(this);}}@Overrideprotected void onDetachedFromWindow() {...if (ALLOW_THREAD_GAP_WORK) {// Unregister with gap workermGapWorker.remove(this);mGapWorker = null;}}
}
复制代码

可以看到RecyclerView中有一个GapWorker类型的成员变量mGapWorker,这个mGapWorker实际上引用的是一个全局的GapWorker实例。在onAttachedToWindowRecyclerView将自己加入到那个全局的GapWorker实例的mRecyclerViews列表里,而在onDetachedFromWindow中把自己从那个全局列表中移除。按理有onAttachedToWindow就会有onDetachedFromWindow,现在看来问题出现在onDetachedFromWindow没有被调用。

为了找到问题的真相,让我们回到现在的应用场景。ListView在下拉刷新之后会清除原有的所有Section,然后创建新的Section集合。这也就意味着一个新的TestSection实例被创建。再来看一下TestSectiongetView的实现:

public class TestSection implements Section {RecyclerView mRecyclerView;public View getView(int position, View convertView, ViewGroup parent) {if (mRecyclerView == null) {mRecyclerView = new RecyclerView(parent.getContext());mRecyclerView.setLayoutManager(new LinearLayoutManager(parent.getContext(), LinearLayoutManager.HORIZONTAL, false));}return mRecyclerView;}
}
复制代码

当这个新的TestSection实例的getView第一次被调用时,mRecyclerViewnull。由于ListView的复用机制,此时参数convertView并不为null,而实际上它引用了之前那个TestSection实例的mRecyclerView!于是现在出现了两个RecyclerView,我们将新的mRecyclerView称为NewRV,原先的mRecyclerView称为OldRV。在getView返回后,NewRV成为了ListView的子view,它的onDetachedFromWindow会被正常调用。然而OldRV就成为了一个无人管的“野孩子”,没有谁会调用它的onDetachedFromWindow。于是它就静静地待在那个全局的GapWorker实例的mRecyclerViews列表里,很无辜地泄露了整个Activity

解决方法

既然已经找到问题的真相,那解决方法也就明了了——正确地复用convertView即可。

public class TestSection implements Section {RecyclerView mRecyclerView;public View getView(int position, View convertView, ViewGroup parent) {if (mRecyclerView == null) {if (convertView instanceof RecyclerView) {mRecyclerView = (RecyclerView) convertView;} else {mRecyclerView = new RecyclerView(parent.getContext());mRecyclerView.setLayoutManager(new LinearLayoutManager(parent.getContext(), LinearLayoutManager.HORIZONTAL, false));}}return mRecyclerView;}
}
复制代码

以后在ListView中嵌套RecyclerView时真的要小心内存泄漏了!

转载于:https://juejin.im/post/5b17a4bb5188257d4c0a3412

http://www.jmfq.cn/news/4839049.html

相关文章:

  • 设计公司网站案例/优惠活动推广文案
  • 公司网站备案怎么做/账户竞价托管哪里好
  • 安徽网站建设推荐 晨飞网络/seo流量是什么意思
  • 代理分销系统开发/广东seo外包服务
  • 石家庄最新疫情最新消息解封/seo积分优化
  • wordpress自定义文章列表/海城seo网站排名优化推广
  • 重庆网站备案必须到核验点/百度统计工具
  • 做个网站多少钱一个月/福州seo公司
  • 做暧嗳xo小视频免费网站/今日桂林头条新闻
  • 浙江网站推广/百度关键词推广价格查询
  • phpwind怎么做网站/网站项目开发流程
  • b2b网站如何做社群运营/国内搜索引擎
  • 武汉做胃镜国医堂z网站/网络营销的营销策略
  • qq钓鱼网站在线生成器/b站推广网站2022
  • 实时定量引物设计网站怎么做/怎么做市场营销和推广
  • 做最好的win7系统下载网站/注册网站流程
  • 有做国外婚恋交友网站/东莞市网络seo推广服务机构
  • 2核4g做网站/词爱站的关键词
  • 柴油网站怎么做/网站查询关键词排名软件
  • 建筑木工模板包工价格/seo技术分享
  • 网站建设到发布2012sevser/2023新冠结束了吗
  • 网站 ca证书怎么做/关键词排名零芯互联排名
  • 如何选择网站建设案例/baidu百度
  • 企业网站建设webbj/南宁网站快速排名提升
  • 河北网站建设团队/网站优化关键词排名
  • 佛山市住房与城乡建设局网站/杭州网站推广优化公司
  • 佘山做网站/大数据营销成功案例
  • 北京游戏网站建设/怎么做线上销售
  • 外贸网站建设 广州/外国网站的浏览器
  • 助听器网站建设方案草稿/优秀网页设计