在嵌套滚动视图中使用的RecyclerView一次性加载了所有数据而不是在滚动时逐个调用图片。

17

在我的应用程序中,我正在使用TabHost Activity。在TabHost的第一个标签中,我正在使用TabActivity,加载了500多张图片。

使用嵌套滚动视图:

我在RecyclerView中使用了嵌套滚动视图。当加载主页时,它首先加载所有500张图像,然后显示主页。因此,这会导致内存溢出错误。

不使用嵌套滚动视图:

如果我删除嵌套滚动视图,一切都很好。它会在滚动时逐个加载图像,不会导致内存不足错误。

我的要求:

我需要滚动放置在RecyclerView顶部的相对布局。因此,我使用了嵌套滚动视图。但它对我没有起作用。

tab_home_layout:

<?xml version="1.0" encoding="utf-8"?>

<android.support.v4.widget.NestedScrollView
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"

        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_behavior="@string/appbar_scrolling_view_behavior"
     >

<LinearLayout
    android:id="@+id/tab_home_activity"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    >

        <RelativeLayout
            android:id="@+id/home_layout_top_2_recycler"
            android:layout_width="match_parent"
            android:layout_height="60dp"
            android:background="@drawable/layout_border"
            >

            <ImageView
                android:id="@+id/img_user_home_tab_recycler"
                android:layout_width="40dp"
                android:layout_height="40dp"
                android:paddingLeft="5dp"
                android:paddingRight="5dp"
                android:layout_centerVertical="true"
                android:contentDescription="@string/cont_desc"
                android:src="@drawable/profile_pic_blue" />

            <TextView
                android:id="@+id/tv_user_mind_home_tab_recycler"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_centerVertical="true"
                android:layout_marginLeft="5dp"
                android:layout_toRightOf="@+id/img_user_home_tab_recycler"
                android:hint="@string/whats_on"
                android:textColor="@color/Black"
                android:textSize="@dimen/txt_size" />
        </RelativeLayout>

    <android.support.v7.widget.RecyclerView
            android:id="@+id/rv_list_tab_home_recycler"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:scrollbars="none"
            android:visibility="visible" />

     </LinearLayout>
</android.support.v4.widget.NestedScrollView>

以下是我尝试过的内容。

  • 我尝试了这个SO帖子。但我正在使用选项卡活动中的首页。所以我不能使用工具栏+协调员布局。因此,此解决方案对我无效。

  • 然后我尝试使用多个布局用于RecyclerView。但那对我没有用。因为那个RelativeLayout是静态的。如果我从网络服务获得任何条件,我可以使用多个布局RecyclerView。但我需要滚动视图。

  • 我计划在适配器的第0个位置设置静态RelativeLayout。但我的网络服务图像从第0个位置开始加载。所以我不能将静态RelativeLayout设置在适配器的第0个位置。

是否有其他替代解决方案来解决这个问题。谢谢。


你尝试过在滚动开始时从嵌套的视图中调用 requestDisallowInterceptTouchEvent() 吗?更多信息请参见:https://developer.android.com/reference/android/view/ViewGroup.html#requestDisallowInterceptTouchEvent(boolean) 和 https://developer.android.com/training/gestures/viewgroup.html。 - milosmns
顺便说一句,也许你想重新考虑使用TabActivity的想法,因为它在一段时间前已经被弃用了。https://developer.android.com/reference/android/app/TabActivity.html - milosmns
@milosmns 让我检查一下 requestDisallowInterceptTouchEvent(),稍后告诉你。 - Stephen
为什么不使用像Glide或Picaso这样的图像库...它们还可以将您的图像存储在缓存中.. - H Raval
2个回答

22

您可以像使用其他布局(例如LinearLayoutRelativeLayout)一样在任何地方使用CoordinatorLayout。如果您希望RelativeLayout响应RecyclerView的滚动,只需将它们放入一个带有AppBarLayoutCoordinatorLayout中即可。这是修改后的布局:

<android.support.design.widget.CoordinatorLayout
    android:id="@+id/main_content"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <android.support.design.widget.AppBarLayout
        android:id="@+id/appbar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <RelativeLayout
            android:id="@+id/home_layout_top_2_recycler"
            android:layout_width="match_parent"
            android:layout_height="60dp"
            android:background="@drawable/layout_border"
            app:layout_scrollFlags="scroll">

            <ImageView
                android:id="@+id/img_user_home_tab_recycler"
                android:layout_width="40dp"
                android:layout_height="40dp"
                android:paddingLeft="5dp"
                android:paddingRight="5dp"
                android:layout_centerVertical="true"
                android:contentDescription="@string/cont_desc"
                android:src="@drawable/profile_pic_blue" />

            <TextView
                android:id="@+id/tv_user_mind_home_tab_recycler"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_centerVertical="true"
                android:layout_marginLeft="5dp"
                android:layout_toRightOf="@+id/img_user_home_tab_recycler"
                android:hint="@string/whats_on"
                android:textColor="@color/Black"
                android:textSize="@dimen/txt_size" />
            </RelativeLayout>

    </android.support.design.widget.AppBarLayout>

    <android.support.v7.widget.RecyclerView
        android:id="@+id/rv_list_tab_home_recycler"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:scrollbars="none"
        android:visibility="visible"
        app:layout_behavior="@string/appbar_scrolling_view_behavior"/>

</android.support.design.widget.CoordinatorLayout>

更改它以符合您的偏好,但请务必将 RelativeLayoutlayout_height 设置为其他值而不是 wrap_content

如果此 CoordinatorLayout 在另一个 CoordinatorLayout 中,请使用来自此 答案NestedCoordinatorLayout 作为内部的 CoordinatorLayout


我尝试了这个解决方案,但它没有滚动relativelayout。你可以在这里检查我的布局。我没有使用嵌套的scrollview。 - Stephen
2
你的RelativeLayout中没有包含app:layout_scrollFlags="scroll",这非常重要。同时在你的RecyclerView中添加app:layout_behavior="@string/appbar_scrolling_view_behavior" - razzledazzle
你的解决方案在我的个人资料页面中运行良好,类似于Instagram,而不使用嵌套滚动视图。在该个人资料页面中,我无法在recyclerview适配器中使用多个布局。这个解决方案在关键时刻帮了我大忙。愿意为500的赏金奖励。谢谢。 - Stephen
当我从底部向上滑动滚动条时,RecyclerView会停在第0项,然后我必须再次滑动才能看到RelativeLayout... - Aman Verma
1
@razzledazzle,滚动非常顺畅。但是如何检测应用栏和RecyclerView的滚动变化? - Gary Chen
显示剩余2条评论

5

重要的是在 onBindViewHolder 方法中,你应该从 position-1 处加载来自你的 Web 服务的图片。
这是一个来自 这里 的示例,在你的情况下,Header 是你的静态 RelativeLayout

public class HeaderAdapter extends RecyclerView.Adapter < RecyclerView.ViewHolder > {
     private static final int TYPE_HEADER = 0;
     private static final int TYPE_ITEM = 1;
     String[] data;

     public HeaderAdapter(String[] data) {
         this.data = data;
     }

     @Override
     public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
         if (viewType == TYPE_ITEM) {
             //inflate your layout and pass it to view holder
             return new VHItem(null);
         } else if (viewType == TYPE_HEADER) {
             //inflate your layout and pass it to view holder
             return new VHHeader(null);
         }
     }

     @Override
     public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
         if (holder instanceof VHItem) {
             String dataItem = getItem(position);
             //cast holder to VHItem and set data

             // ***********    
             // LOAD YOUR WEBSERVICE IMAGE FROM **position - 1**
             // => for row 1 you will get the image 0 ...
             // ***********


         } else if (holder instanceof VHHeader) {
             //cast holder to VHHeader and set data for header.
         }
     }

     //increasing getItemcount to 1. This will be the row of header.
     @Override
     public int getItemCount() {
         return data.length + 1;
     }

     @Override
     public int getItemViewType(int position) {
         if (isPositionHeader(position))
             return TYPE_HEADER;

         return TYPE_ITEM;
     }

     // condition for header
     private boolean isPositionHeader(int position) {
         return position == 0;
     }

     // getItem -1 because we have add 1 header
     private String getItem(int position) {
         return data[position - 1];
     }

     class VHItem extends RecyclerView.ViewHolder {
         TextView title;

         public VHItem(View itemView) {
             super(itemView);
         }
     }

     class VHHeader extends RecyclerView.ViewHolder {
         Button button;

         public VHHeader(View itemView) {
             super(itemView);
         }
     }
 }

1
当然,我会尝试并让您知道。 - Stephen
我如何拥有2个TYPE_ITEM布局并在单击时隐藏/显示每一个? - jlively
@jlively 当然可以创建它,只需创建一个更多的项目类型即可。 - Linh
@PhanVanLinh 我已经尝试过了,但是如何在单击时显示/隐藏每个视图?如何动态更新 viewType - jlively
@jlively 抱歉我以前从未做过。 如果可能,请将其作为另一个问题发布,那么我们可以很容易地帮助您。 - Linh
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接