Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

请教一个问题,listview里面嵌套gridview的问题 #4

Closed
t2314862168 opened this issue Feb 1, 2016 · 5 comments
Closed

请教一个问题,listview里面嵌套gridview的问题 #4

t2314862168 opened this issue Feb 1, 2016 · 5 comments

Comments

@t2314862168
Copy link

你好,最近我遇到一个问题,就是listview里面嵌套gridview的问题,如果要让gridview显示完全,就需要重写gridview的onMeasure方法,但是这样会导致gridview里面的viewholder不能够被复用,假如一个item的gridview的view item 有很多(可以复用gridview的adapter然后加上分页,这是我能够想到),但是我感觉这个貌似也不算是最佳方案,不知道你是怎么解决这种问题的呢,有没有好一点的解决思路?

@wenmingvs
Copy link
Owner

我项目里面也遇到类似的,我是recyclerview嵌套了recyclerview,其中嵌套的那层RecyclerView用于显示微博图片,与你的情况应该很类似。我给你以下解决方案,应该能很好的解决这个问题

  1. 根据内容预先计算好GridView的高度,然后给GridView设置固定的高度,这样ListView在快速滑动的时候就不需要再去动态的计算高度了
//获取gridview的宽高参数
mParams = (LinearLayout.LayoutParams) ViewHolder.gridview.getLayoutParams();

/根据数据集mImageDatas的数量,计算展示这些数据集需要多少行,然后再乘以单个item的布局高度,得到总的gridview高度
mParams.height = (DensityUtil.dp2px(mContext, 110f)) * getImgLineCount(mImageDatas) + 
(DensityUtil.dp2px(mContext, 5f)) * getImgLineCount(mImageDatas);

//同上,根据数据集的内容,来计算一共需要多少列,如果是定值直接写常量即可,再乘以单个item的布局宽度,得到总的gridview的宽度
mParams.width = (DensityUtil.dp2px(mContext, 110f)) * 3 + (DensityUtil.dp2px(mContext, 5f)) * 2;

//设定参数
ViewHolder.gridview.setLayoutParams(mParams);
  1. 监听外层的ListView的滑动操作,在停止滑动的时候,才去加载图片
  2. 使用ImageLoader来统一管理每一个ImageView,尽可能的把缓存机制利用起来

@t2314862168
Copy link
Author

@wenmingvs 你的解决方法应该有一定的效果,但是比如如果gridview里面的item的count 是300个,虽然一次性计算出来了高度,但是每一个item显示的时候都是new 出来的,没有复用viewholder,这样造成滑动的时候会出现ANR的情况吧(我自己用300个做过实验)

@wenmingvs
Copy link
Owner

你好,每一个item并不会new出来,而是会去复用,new出来的是只是bitmap而已。你可以好好读一下这篇博客http://blog.csdn.net/guolin_blog/article/details/45586553

另外你说会出现ANR问题,能否发相关的Demo的github地址发我看看呢?我推测是你在listview内并没有做很好的复用,并且图片也没有做适当的裁剪,才会引起ANR问题的

@t2314862168
Copy link
Author

@wenmingvs 刚去查阅了郭神的博客结合看了下源码,不管ListView或者是GridView的高度固定或者是不固定,RecyclerBin的机制会一直都有,这算是自己的理解误区。
由于代码是在公司的项目里面,我自己不太好抽离出来,我贴下我的核心代码。
首先是ListView的Adapter代码:

@Override
    public View getView(int position, View convertView, ViewGroup parent) {
        if (convertView == null) {
            convertView = mInflater.inflate(R.layout.layout_dynamic_list_item,
                    parent, false);
        }
        // 省略代码...
        NoScrollGridView gridView = ViewHolder.get(convertView, R.id.gridview);
        // 省略代码...
        // 图片
        DynamicGridItemAdapter gridItemAdapter = null;
        if (!TextUtils.isEmpty(imageUrl)) {
            gridView.setVisibility(View.VISIBLE);
            gridView.setOnItemClickListener(new OnItemClickListener() {
                @Override
                public void onItemClick(AdapterView<?> parent, View view,
                        int position, long id) {
                    handleGridItemClick(bean);
                }
            });
            if (gridView.getAdapter() != null) {
                gridItemAdapter = (DynamicGridItemAdapter) gridView
                        .getAdapter();
                gridItemAdapter.setUrlArray(new String[] { imageUrl });
            } else {
                gridItemAdapter = new DynamicGridItemAdapter();
                gridView.setAdapter(gridItemAdapter);
                gridItemAdapter.setUrlArray(new String[] { imageUrl });
            }
            // 很重要,让listview的onItemClick有效果
            GridViewUtils.updateGridViewLayoutParams(gridView, 3);
        } else {
            gridView.setVisibility(View.GONE);
        }
        // 省略代码...
        return convertView;
    }

ViewHolder的代码:

public class ViewHolder {
    /**
     * <T extends View> 泛型的声明 , T 表示方法的返回值
     * 
     * @param view
     * @param id
     * @return
     */
    public static <T extends View> T get(View view, int id) {
        SparseArray<View> viewHolder = (SparseArray<View>) view.getTag();
        if (viewHolder == null) {
            viewHolder = new SparseArray<View>();
            view.setTag(viewHolder);
        }
        View childView = viewHolder.get(id);
        if (childView == null) {
            childView = view.findViewById(id);
            viewHolder.put(id, childView);
        }
        return (T) childView;
    }
}

GridView的DynamicGridItemAdapter里面的代码为:

public class DynamicGridItemAdapter extends BaseAdapter {
    private ArrayList<String> urlList;
    String url = "http://pic.sc.chinaz.com/files/pic/pic9/201509/apic14886.jpg";

    public DynamicGridItemAdapter() {
        urlList = new ArrayList<String>();
    }

    public void setUrlArray(String[] urlArray) {
        urlList.clear();
        for (int i = 0; i < urlArray.length; i++) {
            urlList.add(urlArray[i]);
        }
        notifyDataSetChanged();
    }

    @Override
    public int getCount() {
        return urlList != null ? urlList.size() : 0;
    }

    @Override
    public Object getItem(int position) {
        return urlList.get(position);
    }

    @Override
    public long getItemId(int position) {
        return 0;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        if (convertView == null) {
            LayoutInflater inflater = (LayoutInflater) parent.getContext()
                    .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            convertView = inflater.inflate(
                    R.layout.layout_dynamic_list_grid_item, parent, false);
        }
//      DebugToolUtils.printTest("getView", "position===="+position+"$$$$$convertView====="+convertView);
        ImageView imageView = ViewHolder
                .get(convertView, R.id.iv_gridview_item);
//       ImageLoaderUtils.displayImage(url, imageView);
        ImageLoaderUtils.displayImage(urlList.get(position), imageView);
        return convertView;
    }
}

图片加载用的UIL(内存缓存和硬盘缓存都已经设置了),具体ImageLoaderUtils.displayImage代码:

/**
     * 加载图片
     * 
     * @param uri
     *            图片地址
     * @param imageView
     *            图片控件
     */
    public static void displayImage(String uri, ImageView imageView) {
        ImageAware imageAware = new ImageViewAware(imageView, false);
        ImageLoader.getInstance().displayImage(uri, imageAware,
                getCustomOptions());
    }

图片scaleType,我设置的是center

@wenmingvs
Copy link
Owner

你好,我细看了adapter的代码,暂时没有发现不对的地方,根据你反馈的原因,引起崩溃的是ANR而不是OOM,所以我推测的原因有2点

  1. ListView在快速滑动时需要动态计算GridView的高度,大量的计算引起了UI线程的阻塞,所以会出现ANR问题
  2. 快速滑动的时候,加载图片又马上缓存图片,导致了频繁的GC操作,引起了内存抖动,加重了CPU的负担,也进一步推动了ANR问题的出现。

能否先尝试我以下2个方法,看看是否还会有ANR问题?

  1. 手动设置GridView的高度与宽度
  2. 监听ListView的滑动事件,滑动的时候不做图片的加载,只有在停止滑动了再去加载图片

如果添加这2个方法后,仍然出现ANR问题,再联系我

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants