【新兴源码】【源码试炼48】【火牛火狐源码】adapterview源码

时间:2024-12-29 11:08:06 来源:stl源码剖析 下载 编辑:libmcrypt 源码包

1.ViewPager2 FragmentStateAdapter 刷新问题
2.Android的Adapter的getVIew()
3.RecyclerView详解
4.layoutinflater.inflate 和 view.inflate 的区别
5.谈谈RecyclerView中的缓存

adapterview源码

ViewPager2 FragmentStateAdapter 刷新问题

       面临ViewPager2 FragmentStateAdapter刷新难题,经历长时间探索仍未找到解决方法。最终,通过深入源代码研究,新兴源码发现了解决之道。

       通常情况下,源码试炼48编写ViewPager2的FragmentStateAdapter时,我们遵循的基本框架如下:

       然而,此种方式并未提供直接刷新Fragment的途径。关键点在于,为了实现刷新功能,需要对源代码进行调整,具体操作如下:

       1. 重写`getItemCount()`方法。火牛火狐源码此方法用于返回集合中Fragment的数量,刷新时需确保该方法能准确反映Fragment的最新状态。

       2. 重写`containsItem(itemId: Long)`方法。小麦助教 源码此方法用于检查集合中是否包含特定ID的Fragment,刷新时利用此方法判断和更新特定Fragment。

       3. 为每个Fragment分配ID。layui源码之家这是实现刷新功能的必要前提,确保能精准定位和操作每个Fragment。

       通过以上步骤的实施,成功解决了ViewPager2 FragmentStateAdapter的刷新问题。关键在于深入理解并灵活运用源代码,针对特定需求进行针对性修改,从而达到预期效果。

Android的Adapter的getVIew()

       ViewGroup parent 就是你设置adapter的那个组件里面封装一个viewGroup用来盛放item

       position就是你选择的 item的第几条从0开始

       convertView就是item上的布局layout或者组件

       é‡å†™Adaper要 extends BaseAdapter{

       }

       ç„¶åŽé‡å†™é‡Œé¢çš„方法 网上好多例子 但是要重写的方法的参数是不能该的 你可以在你重写的adapter的类里面 增加变量来实现数据的传递

RecyclerView详解

       RecyclerView作为ListView和GridView的替代,但是和ListView不一样的是,RecyclerView不再负责Item的摆放等显示方面的功能,所有和布局、绘制等方面的工作都拆分成不同的类进行管理。

        RecyclerView与ListView的不同点,主要在于以下几个特性:

        如果你想使用RecyclerView,需要做以下操作:

        我们可以从下图更直观的了解到RecyclerView的基本结构:

        RecyclerView不再负责Item视图的布局及显示,所以RecyclerView也没有为Item开放OnItemClick等点击事件。可以通过以下方式进行:因为在ViewHolder我们可以拿到每个Item的根布局,所以如果我们为根布局设置单独的OnClick监听并将其开放给Adapter,那么就可以在组装RecyclerView时就能够设置ItemClickListener,只不过这个Listener不是设置到RecyclerView上而是设置到Adapter。

        多Item布局,getItemViewType方法,用法和ListView没有任何区别,这里要注意的是函数onCreateViewHolder(ViewGroup parent, int viewType)的第二个参数就是View的类型,可以根据这个类型判断去创建不同item的ViewHolder,从而完成多Item布局。

        在RecylerView中,Adapter扮演着两个角色:一是根据不同viewType创建与之相应的的itemView,二是访问数据集合并将数据绑定到正确的View上。这就需要我们实现以下两个函数:

        另外我们还需要重写另一个方法,像ListView-Adapter那样,同样地告诉RecyclerView-Adapter列表Items的总数:

        ViewHolder描述RecylerView中某个位置的itemView和元数据信息,属于Adapter的一部分,其实现类通常用于保存findViewById的结果。 主要元素组成有:

        关于ViewHolder,这里主要介绍mFlags:

        FLAG_BOUND——ViewHolder已经绑定到某个位置,mPosition、mItemId、mItemViewType都有效

        FLAG_UPDATE——ViewHolder绑定的View对应的数据过时需要重新绑定,mPosition、mItemId还是一致的

        FLAG_INVALID——ViewHolder绑定的View对应的数据无效,需要完全重新绑定不同的数据

        FLAG_REMOVED——ViewHolder对应的数据已经从数据集移除

        FLAG_NOT_RECYCLABLE——ViewHolder不能复用

        FLAG_RETURNED_FROM_SCRAP——这个状态的ViewHolder会加到scrap list被复用。

        FLAG_CHANGED——ViewHolder内容发生变化,通常用于表明有ItemAnimator动画

        FLAG_IGNORE——ViewHolder完全由LayoutManager管理,不能复用

        FLAG_TMP_DETACHED——ViewHolder从父RecyclerView临时分离的标志,便于后续移除或添加回来

        FLAG_ADAPTER_POSITION_UNKNOWN——ViewHolder不知道对应的Adapter的位置,直到绑定到一个新位置

        FLAG_ADAPTER_FULLUPDATE——方法addChangePayload(null)调用时设置

        LayoutManager主要作用是,测量和摆放RecyclerView中itemView,以及当itemView对用户不可见时循环复用处理。

        当我们想在某些item上加一些特殊的UI时,往往都是在itemView中先布局好,然后通过设置可见性来决定哪些位置显示不显示。RecyclerView将itemView和装饰UI分隔开来,装饰UI即ItemDecoration,主要用于绘制item间的分割线、高亮或者margin等。其源码如下:

        过去AdapterView的item项操作往往是没有动画的。现在RecyclerView的ItemAnimator使得item的动画实现变得简单而样式丰富,我们可以自定义item项不同操作(如添加,删除)的动画效果。

        Recycler用于管理已经废弃或与RecyclerView分离的(scrapped or detached)item view,便于重用。Scrapped view指依附于RecyclerView,但被标记为可移除或可复用的view。

        LayoutManager获取Adapter某一项的View时会使用Recycler。当复用的View有效(clean)时,View能直接被复用,反之若View失效(dirty)时,需要重新绑定View。对于有效的View,如果不主动调用request layout,则不需要重新测量大小就能复用。在分析Recycler的复用原理之前,我们先了解下如下两个类:

        RecyclerViewPool用于多个RecyclerView之间共享View。只需要创建一个RecyclerViewPool实例,然后调用RecyclerView的setRecycledViewPool(RecycledViewPool)方法即可。RecyclerView默认会创建一个RecyclerViewPool实例。

        通过源码我们可以看出mScrap是一个<viewType, List>的映射, mMaxScrap 是一个<viewType, maxNum>的映射,这两个成员变量代表可复用View池的基本信息。调用 setMaxRecycledViews(int viewType, int max) 时,当用于复用的 mScrap 中viewType对应的ViewHolder个数超过maxNum时,会从列表末尾开始丢弃超过的部分。调用 getRecycledView(int viewType) 方法时从 mScrap 中移除并返回viewType对应的List的末尾项。

        ViewCacheExtension是一个由开发者控制的可以作为View缓存的帮助类。调用Recycler.getViewForPosition(int)方法获取View时,Recycler先检查attached scrap和一级缓存,如果没有则检查ViewCacheExtension.getViewForPositionAndType(Recycler, int, int),如果没有则检查RecyclerViewPool。注意:Recycler不会在这个类中做缓存View的操作,是否缓存View完全由开发者控制。

        现在大家熟悉了RecyclerViewPool和ViewCacheExtension的作用后,下面开始介绍Recycler。 如下是Recycler的几个关键成员变量和方法:

        获取某个位置需要展示的View,先检查是否有可复用的View,没有则创建新View并返回。具体过程为:

        注:以上每步匹配过程都可以匹配position或itemId(如果有stableId)。

layoutinflater.inflate 和 view.inflate 的区别

       å¹³æ—¶ListView加载item中,adapter的getView方法中,我们经常用到:

       LayoutInflater.from(mContext).inflate(R.layout.it,parent,false);

       è¿™æ ·çš„方法来加载布局xml,平时一直就是这么用的,也没什么疑问。今天网上看了个自定义布局的源码,自定义布局中加载布局xml用的View.inflate方法:

       public class SettingItemView extends RelativeLayout {

       private CheckBox cb_status;

       private TextView tv_description;

       private TextView tv_title;

       private String desc_on;

       private String desc_off;

       private void iniView(Context context) {

       View.inflate(context, R.layout.setting_item_view, this);//第三个参数传布局文件的父类

       cb_status=(CheckBox) this.findViewById(R.id.cb_status);

       tv_description=(TextView) this.findViewById(R.id.tv_description);

       tv_title=(TextView) this.findViewById(R.id.tv_title);

       }

       ç¬¬ä¸€æ¬¡è§ç”¨è¿™ç§æ–¹å¼æ¥åŠ è½½å¸ƒå±€çš„,看了下他的listview加载item,也是用这种方式:

       @Override

       public View getView(final int position, View convertView, ViewGroup parent) {

       View view;

       ViewHolder holder;

       if(convertView==null){

       view=View.inflate(getApplicationContext(), R.layout.list_item_callsms, null);//最后一个传了null

       holder=new ViewHolder();

       holder.tv_number=(TextView) view.findViewById(R.id.tv_black_number);

       holder.tv_mode=(TextView) view.findViewById(R.id.tv_black_mode);

       holder.iv_delete=(ImageView) view.findViewById(R.id.iv_delete);

       view.setTag(holder);

       å¥½å§ï¼Œçœ‹ä¸€ä¸‹View.inflate的说明:

       Open Declaration View android.view.View.inflate(Context context, int resource, ViewGroup root)

       Inflate a view from an XML resource. This convenience method wraps the

       LayoutInflater class, which provides a full range of options for view

       inflation.

       Parameters: context The Context object for your activity or

       application. resource The resource ID to inflate root A view group

       that will be the parent. Used to properly inflate the layout_

*

       parameters.

       See Also: LayoutInflater

       æœ€åŽæœ‰ä¸€å¥è®©ä½ çœ‹LayoutInflater这个类,怀疑它内部也是用LayoutInflater实现的,进入源码:

       public static View inflate(Context context, int resource, ViewGroup root) {

       LayoutInflater factory = LayoutInflater.from(context);

       return factory.inflate(resource, root);

       }

       æžœç„¶å†…部也是用LayoutInflater实现的,不知道为啥android还要用View.inflat封装一下。。。o(〃’▽’〃)o

       å…¶ä¸­LayoutInflater的Inflate的三个参数意思为:

       å¯¹äºŽInflate的三个参数(int resource, ViewGroup root, boolean attachToRoot)

       å¦‚æžœinflate(layoutId, null )则layoutId的最外层的控件的宽高是没有效果的

       å¦‚æžœinflate(layoutId, root, false ) 则认为和上面效果是一样的

       å¦‚æžœinflate(layoutId, root, true ) 则认为这样的话layoutId的最外层控件的宽高才能正常显示

       å¯¹è¿™ä¸‰ä¸ªå‚数区别不理解的话可以看这篇文章:

       inflate第三个参数意思

       ä»Žæºç è§’度解析的有郭大神的:

       Android LayoutInflater原理分析,带你一步步深入了解View(一)

       ä»¥åŠå¦ä¸€ç¯‡æ„Ÿè§‰å¾ˆä¸é”™çš„:

       Android LayoutInflate深度解析 给你带来全新的认识

       çœ‹å®Œï¼Œä½ åº”该知道这个参数意思了,ok,再来看上面代码, 这时就可以替换为layoutInflater的方式了:

       å¯¹äºŽç¬¬ä¸€ä¸ªè‡ªå®šä¹‰å¸ƒå±€ï¼š

       //View.inflate(context, R.layout.setting_item_view, this);//第三个参数传布局文件的父类

       LayoutInflater.from(context).inflate(R.layout.setting_item_view, this, true);//等价于上面

       ç¬¬äºŒä¸ªé€‚配器中getView:

       //view=View.inflate(getApplicationContext(), R.layout.list_item_callsms, null);

       view=LayoutInflater.from(getApplicationContext()).inflate(R.layout.list_item_callsms,parent,false);

谈谈RecyclerView中的缓存

       Android深入理解RecyclerView的缓存机制

        RecyclerView在项目中的使用已经很普遍了,可以说是项目中最高频使用的一个控件了。除了布局灵活性、丰富的动画,RecyclerView还有优秀的缓存机制,本文尝试通过源码深入了解一下RecyclerView中的缓存机制。

        RecyclerView做性能优化要说复杂也复杂,比如说布局优化,缓存,预加载等等。其优化的点很多,在这些看似独立的点之间,其实存在一个枢纽:Adapter。因为所有的ViewHolder的创建和内容的绑定都需要经过Adaper的两个函数onCreateViewHolder和onBindViewHolder。

        因此我们性能优化的本质就是要减少这两个函数的调用时间和调用的次数。如果我们想对RecyclerView做性能优化,必须清楚的了解到我们的每一步操作背后,onCreateViewHolder和onBindViewHolder调用了多少次。因此,了解RecyclerView的缓存机制是RecyclerView性能优化的基础。

        为了理解缓存的应用场景,本文首先会简单介绍一下RecyclerView的绘制原理,然后再分析其缓存实现原理。

        RecyclerView滑动时会触发onTouchEvent#onMove,回收及复用ViewHolder在这里就会开始。我们知道设置RecyclerView时需要设置LayoutManager,LayoutManager负责RecyclerView的布局,包含对ItemView的获取与复用。以LinearLayoutManager为例,当RecyclerView重新布局时会依次执行下面几个方法:

        上述的整个调用链:onLayoutChildren()->fill()->layoutChunk()->next()->getViewForPosition(),getViewForPosition()即是是从RecyclerView的回收机制实现类Recycler中获取合适的View,下面主要就来从看这个Recycler#getViewForPosition()的实现。

        上述逻辑用流程图表示:

        RecyclerView在Recyler里面实现ViewHolder的缓存,Recycler里面的实现缓存的主要包含以下5个对象:

        public final class Recycler {

        final ArrayList mAttachedScrap = new ArrayList<>();

        ArrayList mChangedScrap = null;

        RecyclerView在设计的时候讲上述5个缓存对象分为了3级。每次创建ViewHolder的时候,会按照优先级依次查询缓存创建ViewHolder。每次讲ViewHolder缓存到Recycler缓存的时候,也会按照优先级依次缓存进去。三级缓存分别是:

        使用自定义ViewCacheExtension后,view离屏后再回来不会走onBindViewHolder()方法。

        holder.setIsRecyclable(false),这样的话每次都会走onCreateViewHolder()和onBindViewHolder()方法

        1.提前初始化viewHolder,放到缓存池中

        viewPool.putRecycledView(adapter.onCreateViewHolder(recyclerView, 1))

        2.提前初始化view,在onCreateViewHolder的时候去取view

        3.自定义ViewCacheExtension

        4.适当的增加cacheSize

        4.公用缓存池,比如多个viewPager+fragment场景使用,或者全局单利缓存池,感觉用户不大。

        有2中做法有值

        第一种

        第二种

        不会,因为prefetch(GapWorker中的一个方法)之后mViewCacheMax会变成mRequestedCacheMax + extraCache

        有2种方式可以让缓存失效

        第一种

        recyclerView.setItemViewCacheSize(-1)

        第二种

        recyclerView.setItemViewCacheSize(0)

        layoutManager.isItemPrefetchEnabled = false

        设置不缓存后,来回滑动让view进入屏幕离开屏幕,viewHolder的item时会多次走onBindViewHolder()方法。

copyright © 2016 powered by 皮皮网   sitemap