-
Notifications
You must be signed in to change notification settings - Fork 1
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
2019-08-07:说说你对RecyclerView的了解,是否了解其缓存的内部机制? #7
Comments
RecyclerView 是什么?RecyclerView是Android5.0推出,Google工程师在support-v7包中引入的一个全新列表控件,用于显示庞大数据集容器,可通过保持有限数量的视图进行非常有效的滚动操作,它不关心item是否显示在正确的位置以及如何显示,通过LayoutManager控制布局是横向还是纵向,它不关心 item 如何 分隔,通过 ItemDecoration 来绘制分割线,它不关心 item 增加或删除的动画效果,你可以通过 ItemAnimation 绘制你想要的动画效果,RecyclerView仅仅关注如何回收和复用view,如果有数据集合,其中元素将因用户操作或网络事件而发生改变,建议使用RecyclerView RecyclerView使用一.添加依赖 使用RecyclerView需要在 app/build.gradle添加 相关依赖,然后同步一下就可以使用依赖了: implementation 'com.android.support:recyclerview-v7:25.3.1' 二.编写代码 创建布局文件 <androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerview"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</androidx.constraintlayout.widget.ConstraintLayout> 创建完成后在Activity获取RecycleView对象,并声明 LayoutManager 与 Adapter,代码如下: public class MainActivity extends AppCompatActivity implements SimpleAdapter.OnItemClickListener {
private RecyclerView mRecyclerView;
private List<String> mDatas;
private SimpleAdapter mAmAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initDatas();
initView();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
final int itemId = item.getItemId();
switch (itemId) {
case R.id.action_add:
mAmAdapter.addData(1);
mRecyclerView.setAdapter(mAmAdapter);
break;
case R.id.action_delete:
mAmAdapter.deleteData(1);
mRecyclerView.setAdapter(mAmAdapter);
break;
case R.id.action_grid_view:
mRecyclerView.setAdapter(new SimpleAdapter(this, mDatas, false));
mRecyclerView.setLayoutManager(new GridLayoutManager(this, 5));
break;
case R.id.action_list_view:
mRecyclerView.setAdapter(new SimpleAdapter(this, mDatas, true));
mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
break;
case R.id.action_hor_grid_view:
mRecyclerView.setAdapter(new SimpleAdapter(this, mDatas, false));
mRecyclerView.setLayoutManager(new StaggeredGridLayoutManager(5, StaggeredGridLayoutManager.HORIZONTAL));
break;
case R.id.action_stagger_view:
startActivity(new Intent(this, StaggeredGridViewActivity.class));
break;
default:
break;
}
return super.onOptionsItemSelected(item);
}
private void initView() {
mRecyclerView = (RecyclerView) findViewById(R.id.recyclerview);
mAmAdapter = new SimpleAdapter(this, mDatas, true);
// 设置RecyclerView的布局管理
mRecyclerView.setAdapter(mAmAdapter);
mRecyclerView.setLayoutManager(new LinearLayoutManager(this, RecyclerView.HORIZONTAL, false));
mAmAdapter.setOnItemClickListener(this);
}
private void initDatas() {
mDatas = new ArrayList<>();
for (int i = 'A'; i < 'z'; i++) {
mDatas.add("" + (char) i);
}
}
@Override
public void onItemClick(View view, int position) {
Toast.makeText(MainActivity.this, "Click:" + position
, Toast.LENGTH_LONG).show();
}
@Override
public void onItemLongClick(View view, int position) {
mAmAdapter.deleteData(position);
}
} RecycleView 和 ListView 一样需要适配器的,但是 RecycleView 需要设置 布局管理器(setLayoutManager),这是为了方便扩展,这里使用了 LinearLayoutManager.其中 Adapter 的创建比较关键,来看一下 SimpleAdapter 的代码: public class SimpleAdapter extends RecyclerView.Adapter<MyViewHolder> {
public LayoutInflater mInflater;
private Context mContext;
private List<String> mDatas;
private boolean mIsListView;
public OnItemClickListener mListener;
public interface OnItemClickListener {
void onItemClick(View view, int position);
void onItemLongClick(View view, int position);
}
public void setOnItemClickListener(OnItemClickListener listener) {
this.mListener = listener;
}
public SimpleAdapter(Context context, List<String> datas, boolean isListView) {
this.mContext = context;
this.mDatas = datas;
this.mInflater = LayoutInflater.from(context);
this.mIsListView = isListView;
}
public void addData(int position) {
if (position >= 1) {
mDatas.add(mDatas.get(position));
notifyItemInserted(position);
}
}
public void deleteData(int postion) {
mDatas.remove(postion);
notifyItemRemoved(postion);
}
@Override
public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
final View view = mInflater.inflate(mIsListView ? R.layout.item_simple_list_view : R.layout.item_simple_text_view, parent, false);
MyViewHolder viewHolder = new MyViewHolder(view);
return viewHolder;
}
@Override
public void onBindViewHolder(@NonNull final MyViewHolder holder, final int position) {
holder.tv.setText(mDatas.get(position));
setUpItemEvent(holder);
}
public void setUpItemEvent(@NonNull final MyViewHolder holder) {
if (mListener != null) {
final int layoutPosition = holder.getLayoutPosition();
holder.tv.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
mListener.onItemClick(holder.tv, layoutPosition);
}
});
holder.tv.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View view) {
mListener.onItemLongClick(holder.tv, layoutPosition);
return false;
}
});
}
}
@Override
public int getItemCount() {
return mDatas.size();
}
} 上面用到 item_simple_text_view.xml 布局文件,代码如下: <?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="wrap_content"
android:background="@color/colorAccent"
android:layout_margin="3dp"
android:id="@+id/layout_frame"
android:layout_height="wrap_content">
<TextView
android:id="@+id/id_tv"
android:gravity="center"
android:layout_width="72dp"
android:layout_height="72dp"/>
</FrameLayout> SimpleAdapter 继承 RecyclerView.Adapter ,需要一个ViewHolder 泛型,创建 ViewHolder 需要继承 RecycleView.ViewHolder , ViewHolder 的构造方法需要传递 View 对象, View 对象 需要继承 RecycleView.ViewHolder,ViewHolder 构造方法需要传递 View对象,View对象会和 ViewHolder 进行绑定. public class MyViewHolder extends RecyclerView.ViewHolder {
TextView tv;
public MyViewHolder(@NonNull View itemView) {
super(itemView);
tv = (TextView) itemView.findViewById(R.id.id_tv);
}
} 三.运行 写完这些代码后,这个simple就可以运行起来了,从例子也可以看出,RecycleView的用法并不比 ListView 复杂,反而更加灵活好用,它将数据,排列方式,数据展示方式都分割开来,因此自定义的形式也非常多,非常灵活 RecyclerView不同布局的排列方式上面的效果是水平列表,还可以选择其他排列方式,非常灵活,这就是比单一的listView/GridView强大的地方
以垂直列表方式展示显示项目 mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
以垂直列表方式展示显示表格布局 mRecyclerView.setLayoutManager(new GridLayoutManager(this, 5));
如果想设置一个横向的列表,只要设置 LinearLayoutManager 就行,注意, 要声明 LayoutManager 的类型是 LinearLayoutManager ,而不是父类的 LayoutManager mRecyclerView.setLayoutManager(new LinearLayoutManager(this, RecyclerView.HORIZONTAL, false));
以水平列表方式展示显示表格布局 mRecyclerView.setLayoutManager(new StaggeredGridLayoutManager(5, StaggeredGridLayoutManager.HORIZONTAL))```
一.高度绘制 for (int i = 0; i < mDatas.size(); i++) {
mHeight.add((int) (100 + Math.random() * 300));
} 二.布局绘制 @Override
public void onBindViewHolder(@NonNull MyViewHolder holder, int position) {
final ViewGroup.LayoutParams layoutParams = holder.itemView.getLayoutParams();
layoutParams.height = mHeight.get(position);
holder.itemView.setLayoutParams(layoutParams);
holder.tv.setText(mDatas.get(position));
} 三.设置RecyclerView的布局管理 StaggeredGridLayoutManager manager = new StaggeredGridLayoutManager(3,StaggeredGridLayoutManager.VERTICAL);
mRecyclerView.setLayoutManager(manager); 四.RecyclerView添加点击事件 当使用一段时间的RecycleView,发现为其实现每一项点击事件并没有ListView那么轻松,ListView直接加一个 OnItemClickListerner 即可,实际上我们不要把 public interface OnItemClickListener {
void onItemClick(View view, int position);
void onItemLongClick(View view, int position);
} 定义完接口,在 Adapter 中添加 要实现的接口和添加设置的方法 public OnItemClickListener mListener;
public void setOnItemClickListener(OnItemClickListener listener) {
this.mListener = listener;
} 那么这个接口用在什么地方呢?如下代码,为Adapter 实现 onClickListerner 方法: @Override
public void onBindViewHolder(@NonNull final MyViewHolder holder, final int position) {
holder.tv.setText(mDatas.get(position));
setUpItemEvent(holder);
}
public void setUpItemEvent(@NonNull final MyViewHolder holder) {
if (mListener != null) {
final int layoutPosition = holder.getLayoutPosition();
holder.tv.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
mListener.onItemClick(holder.tv, layoutPosition);
}
});
holder.tv.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View view) {
mListener.onItemLongClick(holder.tv, layoutPosition);
return false;
}
});
}
} 做完这些事情就可以在 Activity 或者其他地方 为 RecycleView 添加项目点击事件了,如: private void initView() {
mRecyclerView = (RecyclerView) findViewById(R.id.recyclerview);
mAmAdapter = new SimpleAdapter(this, mDatas, true);
// 设置RecyclerView的布局管理
mRecyclerView.setAdapter(mAmAdapter);
mRecyclerView.setLayoutManager(new LinearLayoutManager(this, RecyclerView.HORIZONTAL, false));
mAmAdapter.setOnItemClickListener(this);
}
@Override
public void onItemClick(View view, int position) {
Toast.makeText(MainActivity.this, "Click:" + position
, Toast.LENGTH_LONG).show();
}
@Override
public void onItemLongClick(View view, int position) {
mAmAdapter.deleteData(position);
} 五.RecycleView添加删除数据 添加数据: public void addData(int position) {
if (position >= 1) {
mDatas.add(mDatas.get(position));
notifyItemInserted(position);
}
} 删除数据: public void deleteData(int postion) {
mDatas.remove(postion);
notifyItemRemoved(postion);
} 注意,这里更新数据集不是 adapter.notifyDataSetChange(),而是 notifyItemInserted(postion)与 notifyItemRemoved(postion),否则没有动画效果 RecyclerView核心类
没有实现 view Holder 的 getView() 会重复执行 findViewById,findViewById 底层实现是一个 dns ,深度优先复杂度,所以viewHolder模式实现了getView方法,他的来历是用来保存View的convertView 不实现 view Holder 还会复用 item view 吗?这个问题我还有待研究.
RecyclerView与ListView相比的优势因为ListView只有纵向列表一种布局,不像RecyleView一样支持 Linear, Grild ,Stagged,Stagged ,Grid 各种可扩展布局,没有支持动画的API,但是RecyleView可以通过ItemAnimation自定义你想要的动画,相关监听接口如:setOnClickListerner(),setOnLongItenListerner(),setSelection()的设计和系统也不一致,并且没有强制实现ViewHolder,RecyleView做到了这一点,降低了耦合,另外ListView性能也不如RecyclerView,所以强烈推荐大家使用RecyclerView |
RecyclerView 滑动场景下的回收复用涉及到的结构体两个: mCachedViews 优先级高于 RecyclerViewPool,回收时,最新的 ViewHolder 都是往 mCachedViews 里放,如果它满了,那就移出一个扔到 ViewPool 里好空出位置来缓存最新的 ViewHolder。 复用时,也是先到 mCachedViews 里找 ViewHolder,但需要各种匹配条件,概括一下就是只有原来位置的卡位可以复用存在 mCachedViews 里的 ViewHolder,如果 mCachedViews 里没有,那么才去 ViewPool 里找。 在 ViewPool 里的 ViewHolder 都是跟全新的 ViewHolder 一样,只要 type 一样,有找到,就可以拿出来复用,重新绑定下数据即可。 |
RecyclerView性能优化策阅
new LinearLayoutManager(this) {
@Override
protected int getExtraLayoutSpace(RecyclerView.State state) {
return size;
}
}; |
RecyclerView缓存机制暂时没搞明白,欢迎一块儿探讨~ |
recyclerView算是Android中比较常用的控件了,平常的使用也很简单,没什么说的。 另外使用itemDecoration可以灵活控制布局之间的间距和装饰等效果。 缓存机制的话确实还没读过源码,找了篇技术文章,可以参考下:https://blog.csdn.net/wzy_1988/article/details/81569156 |
RecyclerView vs ListView 1.addHeaderView(), addFooterView()添加头视图和尾视图。 这些功能在RecyclerView中都没有直接的接口,要自己实现(虽然实现起来很简单),因此如果只是实现简单的显示功能,ListView无疑更简单。 RecyclerView相比ListView,有一些明显的优点: 1.默认已经实现了View的复用,不需要类似if(convertView == null)的实现,而且回收机制更加完善。 RecyclerView是一个插件式的实现,对各个功能进行解耦,从而扩展性比较好。 找到一篇基本可以全面了解recyclerview的文章,可以参考下 |
那你是如何解决下划线渲染两次的呢? |
RecyclerView是Android 5.0推出的一个可以展示大量数据的、灵活的控件。 优势
重要组件
性能优化
RecyclerView缓存
|
RecyclerView内部缓存机制是四级缓存:Scrap、Cache、ViewCacheExtension、RecycledViewPool,RecyclerView是通过LayoutManager里面的Recycler来管理缓存; |
据我观察,公用一个 RecycledViewPool,不能达到完美的优化效果,只是节省了内存. mRecycledViewPool.setMaxRecycledViews(1, 10); mRecyclerView1.setRecycledViewPool(recycledViewPool); 比如 mRecyclerView1 type=1,保存了 5个. |
No description provided.
The text was updated successfully, but these errors were encountered: