gpt4 book ai didi

android - 仔细检查 fragment + view holder 模式是否正确实现

转载 作者:塔克拉玛干 更新时间:2023-11-02 20:38:15 25 4
gpt4 key购买 nike

由于内存泄漏,我一直在重新编写一些代码。该代码是应用程序帮助部分的一部分,我们在其中使用 FragmentActivity 和 FragmentPageAdapter 允许用户滑动不同的帮助屏幕。每个 fragment ,下面的 SectionFragment 类,包括一个图像、一些标题文本和正文文本。

内存泄漏本身就是因为每次在 Fragment 中调用 onCreateView 时都会膨胀一个新 View 。

public class SectionFragment extends Fragment {

private ImageView imgvw;
private TextView headerTxvw;
private TextView bodyTxvw;

public int[][] content;
protected int pageIdx;

public SectionFragment(int idx, int[][] content ){
super();
pageIdx = idx;
this.content = content;
}

protected int getPageIdx() {
return pageIdx;
}

protected Drawable getImageDrawable() {
return getResources().getDrawable( content[pageIdx][0] );
}

protected String getHeaderText() {
return getResources().getString( content[pageIdx][1] );
}

protected String getSubeaderText() {
return getResources().getString( content[pageIdx][2] );
}

protected void loadView( View vw ) {
imgvw = (ImageView)vw.findViewById( R.id.top_img );
headerTxvw = (TextView)vw.findViewById( R.id.header_txt );
bodyTxvw = (TextView)vw.findViewById( R.id.body_txt );

imgvw.setImageDrawable( getImageDrawable() );
headerTxvw.setText( getHeaderText() );
bodyTxvw.setText( getSubeaderText() );
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View vw = inflater.inflate( R.layout.help_fragment, null );
loadView( vw );
return vw;
}
}

我对 Fragments 还是个新手,也不是最初编码工作的一部分,所以我不确定我的解决方案是否正确,但它类似于我在列表 Activity 中多次实现的 View 持有者模式。我非常感谢对以下实现的任何反馈,所以我会更放心这是正确的。

public class SectionFragment extends Fragment {

static private class ViewHolder {
ImageView imgvw;
TextView headerTxvw;
TextView bodyTxvw;
}

public int[][] _content;
protected int _pageIdx;

public SectionFragment( int idx, int[][] content ){
super();
_pageIdx = idx;
_content = content;
}

protected int getPageIdx() {
return _pageIdx;
}

protected Drawable getImageDrawable() {
return getResources().getDrawable( _content[_pageIdx][0] );
}

protected String getHeaderText() {
return getResources().getString( _content[_pageIdx][1] );
}

protected String getSubeaderText() {
return getResources().getString( _content[_pageIdx][2] );
}

protected void loadView( View vw ) {

_holder.imgvw.setImageDrawable( getImageDrawable() );
_holder.headerTxvw.setText( getHeaderText() );
_holder.bodyTxvw.setText( getSubeaderText() );
}

private View _vw;
private ViewHolder _holder;

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
if ( _vw == null ) {
_vw = inflater.inflate( R.layout.help_fragment, null );

_holder = new ViewHolder();
_holder.imgvw = (ImageView)_vw.findViewById( R.id.top_img );
_holder.headerTxvw = (TextView)_vw.findViewById( R.id.header_txt );
_holder.bodyTxvw = (TextView)_vw.findViewById( R.id.body_txt );
_vw.setTag( _holder );
} else {
ViewParent oldparent = (ViewParent)_vw.getParent();
if ( oldparent != container ) {
((ViewGroup)oldparent).removeView( _vw );
}
_holder = (ViewHolder)_vw.getTag();
}
loadView( _vw );
return _vw;
}
}

我没有包含与此代码关联的其他类,特别是 FragmentActivity 和 FragmentPagerAdapter,因为它们似乎已正确实现,但如果需要,我也可以包含它们。

最佳答案

关于 Android 应用中的一般内存泄漏

您确定它正在泄漏内存而不仅仅是延迟垃圾收集吗?您是否在应用程序上运行过例如 eclipse 内存分析器插件?它通常可以准确显示泄漏发生的位置。

关于 fragment viewpager 及其回收(或缺乏回收)

我对 fragment 寻呼机内存泄漏/增加的第一个猜测是有一个动态适配器。 fragmentpageradapter 非常笨,不能很好地处理变化

据我从源代码中所见,即使您将计数从 5 更改为 4,它也永远不会销毁 fragment (第五个 fragment 将保留在 fragment 管理器中)。这是因为它被分离而不是被摧毁。 fragmentstatepageradapter 会在 View 超出页边距时破坏 View 。

从长远来看,所有这些实际上并不会导致内存泄漏,因为当 fragmentmanager 稍后清除 fragment 时,这些 fragment 将被清除。但是,它会增加内存使用量(可能导致内存不足错误)。

每次创建 fragment 时都会创建一个新 View (如果将 retaininstance 设置为 true,则创建的次数会更多),但除非您使用 FragmentStatePagerAdapter,因为正常的寻呼机适配器会分离和附加,所以每个 fragment 应该只出现一次来自 fragment 管理器的相同 fragment 。在任何情况下, View 都将在 Activity 被销毁后被释放,除非您保留对它的引用。

您似乎确实在类里面保留了对 View 的引用,这是我通常尽量避免的事情。我更喜欢在需要时使用 getView().findViewById(),但在这种情况下,我认为成员引用应该由 gc 找到并删除。当然,这完全取决于您是否在其他地方泄漏了这些引用。

fragment 分页器中的查看器

您不应该尝试在 fragment 中做类似 viewholder 的事情。在这个例子中它可能不会受到伤害,但我看不到你从中获得任何好处。只需在 oncreateview 中扩充 View 并设置值即可。

没有 View 的回收,例如在 ListView 中,因此 ViewHolder 模式没有意义,只会冒引入内存泄漏或由于悬空引用而延迟垃圾回收的风险。

View 不是为了重复使用而设计的,即使它们可能会像您使用的那样在某些父欺骗期间被重复使用。这只能作为最后的出路。然而,如果流程中有任何问题,它可能会导致可怕的泄漏。

如果有人可以合理使用它,请纠正我。

关于 ViewHolder 的旁注

我实际上会避免使用 viewholder,除非我真的需要它,即使在 ListView 中也是如此。我已经看到这些标签在某些游标适配器中导致非常严重的内存泄漏,我会在尝试引用保存之前考虑使我的行布局更简单。 Findviewbyid 在良好的布局中不会那么昂贵。

关于android - 仔细检查 fragment + view holder 模式是否正确实现,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9933783/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com