RecyclerView显示 列表
来源:互联网 发布:c语言入门书 编辑:程序博客网 时间:2024/05/29 12:41
一,简介
1. RecyclerView、Adapter和ViewHolder的关系
我们需要CrimeListFragment向用户展示crime列表,这就要用到RecyclerView类。RecyclerView是ViewGroup的子类,每一个列表项都是作为一个View子对象显示的。这些View子对象既可以是复杂的View对象,也可以是简单的View对象,这取决于我们对列表显示复杂度的需要
RecyclerView的任务仅限于回收和定位屏幕上的TextView。TextView能够显示数据还离不开另外两个类的支持:Adapter子类和ViewHolder子类。ViewHolder要做的事很少,我们首先讨论它。顾名思义,ViewHolder只做一件事:容纳View视图
adapter
图9-6进行了简化,实际上隐藏了一些信息。RecyclerView自己不创建ViewHolder。这个任务实际是由adapter来完成的。adapter是个控制器对象,从模型层获取数据,然后提供给RecyclerView显示,起到了沟通的桥梁作用。
adapter负责:
创建必要的ViewHolder;
绑定ViewHolder至模型层数据。
要创建adapter,首先要定义RecyclerView.Adapter子类。然后由它封装从CrimeLab获取的crime。
RecyclerView需要显示视图对象时,就会去找它的adapter。图9-7展示了一个RecyclerView可能发起的会话。
首先,通过调用adapter的getItemCount()方法,RecyclerView询问数组列表中包含多少个对象。
接 着 , RecyclerView 调 用adapter的createViewHolder(ViewGroup, int)方 法 创 建ViewHolder以及ViewHolder要显示的视图。
最后, RecyclerView会传入ViewHolder及其位置,调用onBindViewHolder(ViewHolder,int)方法。adapter会找到目标位置的数据并绑定到ViewHolder的视图上。所谓绑定,就是使用模型数据填充视图。
整个过程执行完毕, RecyclerView就能在屏幕上显示crime列表项了。需要注意的是,相对于onBindViewHolder(ViewHolder, int)方法,createViewHolder(ViewGroup, int)方法
的调用并不频繁。一旦创建了够用的ViewHolder,RecyclerView就会停止调用createViewHolder(...)方法。然后,通过回收利用旧的ViewHolder节约时间和内存。
实质上,recycler类似于安卓内联的listview,只是其是支持库而已
添加支持库:
单击File→Project Structure....菜单项切换至项目结构窗口,选择左边的app模块,然后单击Dependencies选项页。单击+按钮弹出依赖库添加窗口。找到并选择recyclerview-v7支持库,单击OK按钮完成依赖库添加,
例程:该例子是基于fragment显示的
1. RecyclerView的XML,Recycler界面用于容乃列表项:
<?xml version="1.0" encoding="utf-8"?><android.support.v7.widget.RecyclerView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/crime_recycler_view" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"></android.support.v7.widget.RecyclerView>2. 列表项的布局XML,用于设置每一项的布局:
<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content"> <TextView android:id="@+id/crime_list_LabelText" android:layout_width="match_parent" android:layout_height="wrap_content" android:textStyle="bold" android:padding="4dp" android:layout_toLeftOf="@+id/crime_list_CheckBox" android:text="TextView"/> <TextView android:id="@+id/crime_list_DateText" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_toLeftOf="@+id/crime_list_CheckBox" android:layout_below="@id/crime_list_LabelText" android:padding="4dp" android:text="TextView"/> <CheckBox android:id="@+id/crime_list_CheckBox" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentRight="true" android:text="CheckBox" android:padding="4dp"/></RelativeLayout>3. Crime类,自定义类,表示每个元素的数据,模型里的单个数据结构:
//基本元素单位类public class Crime { private UUID yID; private String yTitle; private Date yDate; private boolean CrimeFlag; public Crime() { yID = UUID.randomUUID(); yDate = new Date(); } public UUID getyID() { return yID; } public String getyTitle() { return yTitle; } public void setyTitle(String yTitle) { this.yTitle = yTitle; } public Date getyDate() { return yDate; } public void setyDate(Date yDate) { this.yDate = yDate; } public boolean getCrimeFlag() { return CrimeFlag; } public void setCrimeFlag(boolean crimeFlag) { CrimeFlag = crimeFlag; }}4. List类,模型本身:
//元素组合类public class CrimeListLab { private static CrimeListLab yCrimeLab; private List<Crime>yCrime; private CrimeListLab(Context context) { yCrime = new ArrayList<>(); for(int i=0;i<100;i++){ Crime crime = new Crime(); crime.setyTitle("Crime #" + i); crime.setCrimeFlag(i%2 == 0); yCrime.add(crime); } } public static CrimeListLab getyCrimeLab(Context context) { if(null == yCrimeLab){ yCrimeLab = new CrimeListLab(context); } return yCrimeLab; } public List<Crime> getyCrime() { return yCrime; } public Crime getCrime(UUID uuid) { for (Crime crime:yCrime) { if(crime.getyID().equals(uuid)){ return crime; } } return null; }}5. fragment的内容,也是决定Recycler如何显示:
//控制RecyclerView的Fragmentpublic class CrimeListFragment extends Fragment{ //RecyclerView对象 private RecyclerView yCrimeRecyclerView; //Adapter对象 private CrimeAdapter yCrimeAdapter; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { //绑定布局 View view = inflater.inflate(R.layout.fragment_crime_list, container, false); //绑定并实例化Recycler yCrimeRecyclerView = (RecyclerView) view .findViewById(R.id.crime_recycler_view); yCrimeRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity())); //自定义的将Adapter与Recycler绑定的函数 updateUI(); return view; } //自定义的将Adapter与Recycler绑定的函数 public void updateUI(){ CrimeListLab crimelistlab = CrimeListLab.getyCrimeLab(getActivity()); List<Crime>crimeList = crimelistlab.getyCrime(); yCrimeAdapter = new CrimeAdapter(crimeList); yCrimeRecyclerView.setAdapter(yCrimeAdapter); } //继承Holder的内部类定义,该类实例化布局内部组件资源 //此处还继承监听事件接口 public class CrimeHolder extends RecyclerView.ViewHolder implements View.OnClickListener{ private Crime yCrime;//用于接受Crime元素对象 private TextView yTitleLabel; private TextView yTitleDate; private CheckBox yCheckBox; public CrimeHolder(View itemView) { super(itemView); itemView.setOnClickListener(this);//监听 //关联布局内的组件资源实例化 yTitleLabel = (TextView) itemView.findViewById(R.id.crime_list_LabelText); yTitleDate = (TextView) itemView.findViewById(R.id.crime_list_DateText); yCheckBox = (CheckBox) itemView.findViewById(R.id.crime_list_CheckBox); } //自定义方法,用于在Adapter的视图和数据绑定函数调用以实现数据绑定 public void bindCrime(Crime crime){ yCrime = crime;//通过每个传进来的Crime元素来获取数据 yTitleLabel.setText(yCrime.getyTitle()); yTitleDate.setText(yCrime.getyDate().toString()); yCheckBox.setChecked(yCrime.getCrimeFlag()); } //监听事件的相应 @Override public void onClick(View v){ Toast.makeText(getActivity(), yCrime.getyTitle() + " clicked!", Toast.LENGTH_SHORT) .show(); } } //决定项的布局,项的数目,并将项和数据模型绑定的Adpater类 public class CrimeAdapter extends RecyclerView.Adapter<CrimeHolder>{ //用于接收存放List资源的对象 private List<Crime> yCrimelist; //构造类,内部用于接受存放List资源 public CrimeAdapter(List<Crime>yCrimelist){//可能有内外部类同名隐患 this.yCrimelist = yCrimelist; } //创建项视图,关联项布局 @Override public CrimeHolder onCreateViewHolder(ViewGroup parent, int viewType) { LayoutInflater layoutInflater = LayoutInflater.from(getActivity()); //寻找项的布局文件 View view = layoutInflater.inflate(R.layout.fragment_crime_list_item,parent,false); return new CrimeHolder(view); } //将视图和数据模型绑定 @Override public void onBindViewHolder(CrimeHolder holder, int position) { Crime crime = yCrimelist.get(position);//获取每个crime数据 holder.bindCrime(crime);//调用CrimeHolder的方法将数据传递并更新 } //返回一共有多少项 @Override public int getItemCount() { return yCrimelist.size(); } }}6. 托管fragment的Activity
//在Activity建立fragmentmanager来托管xml布局,此时继承的是通用ActivityFragmentManager抽象类public class CrimeListActivity extends CrimeActivity { @Override protected Fragment createFragment(){ return new CrimeListFragment(); }}7. 其他,托管fragment的Activity的超类:
//创建通用的ActivityFragmentManager的抽象类,防止重复代码public abstract class CrimeActivity extends FragmentActivity { protected abstract Fragment createFragment();//抽象创建Fragment布局接口 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.crime_layout); FragmentManager fm = getSupportFragmentManager(); Fragment yFragment = fm.findFragmentById(R.id.fragment_container); if(null == yFragment){ yFragment = createFragment();//用抽象接口创建Fragment布局,可以根据需要创建不同接口 fm.beginTransaction() .add(R.id.fragment_container,yFragment) .commit(); } }}
深入学习: ListView和 GridView
Android操作系统核心库包含ListView、GridView和Adapter类。Android 5.0之前,创建列表项或网格项都应该优先使用这些类。
这些类的API与RecyclerView非常相似。ListView和GridView不关心具体的展示项,只负责展示项的滚动。Adapter负责创建列表项的所有视图。不过,使用ListView和GridView不一定非要使用ViewHolder模式(虽然可以并且应该使用)。
过去传统的实现方式现已被RecyclerView的实现方式取代,因为我们不用再费力地去调整ListView和GridView的工作行为了。举例来说,ListView API不支持创建水平滚动的ListView,我们需要许多额外的定制工作。
使用RecyclerView时,虽然创建定制布局和滚动行为需要额外的工作,但RecyclerView天生支持拓展,所以使用体验还不错。
此外, RecyclerView还有支持列表项动画效果的优点。如果要让ListView和GridView支持添加和删除列表项的动画效果,实施任务既复杂又容易出错;而对于天生支持动画特效的RecyclerView来说,对付这些任务简直是小菜一碟。
口吐莲花,不如直接秀代码。例如,如果crime列表项要从位置0移动到位置5,下面这段代码就可以做到:
mRecyclerView.getAdapter().notifyItemMoved(0, 5);
深入学习:单例
Android开发实践中,经常会用到CrimeLab中使用过的单例模式。然而,单例使用不当的话,会导致应用难以维护,因此它也常遭人诟病。
Android开发常用到单例的一大原因是,它们比fragment或activity活得久。例如,在设备旋转或是在fragment和activity间跳转的场景下,单例不会受到影响,而旧的fragment或activity已经不复存在了。
单例能方便地存储控制模型层对象。假设有个比CriminalIntent更为复杂的CriminalIntent应用,它的许多个activity和fragment会修改crime数据。某个控制单元修改了crime数据之后,怎么保证发送给其他控制单元的是最新数据呢?如果CrimeLab掌控数据对象,所有的修改都由它来处理,是不是数据的一致性控制就容易多了?而且,在控制单元间流转时,我们还可以给每个crime添加ID标识,让控制单元使用ID标识从CrimeLab获取完整的crime数据。
再来谈谈单例的缺点。举个例子,虽然单例能存储数据,活得比控制单元长久,但这并不代表它能永存。在我们切换至其他应用,又逢Android回收内存时,单例连同那些实例变量也就不复存在了。结论很明显:单例无法做到持久存储。(将文件写入磁盘或是发送到Web服务器是不
错的数据持久化存储方案。)
单例还不利于单元测试。例如,如果应用代码直接调用CrimeLab对象的静态方法,测试时以模拟版本的CrimeLab代替实际CrimeLab实例就不太现实。实践中,Android开发人员会使用依赖注入工具解决这个问题。这个工具允许以单例模式使用对象,对象也可以按需替换。
单例使用很方便,因而很容易被滥用。在想用就用,想存就存之前,希望你能深思熟虑:数据究竟用在哪里?用在哪里能真正解决问题?假如不慎重对待这个问题,很可能后来人在查看你的单例代码时,就像打开了一个满是乱糟糟废品的抽屉:废电池、拉链扣、旧照片,等等。它们有什么存在的意义?再强调一次:请确保有充足的理由使用单例模式存储你的共享数据!
使用得当,单例就是拥有优秀架构的Android应用中的关键部件
- RecyclerView显示 列表
- 通过recyclerView实现列表显示
- Android | 使用RecyclerView显示列表
- RecyclerView 列表无法显示或者显示不正常
- Android读书笔记之用RecyclerView显示列表项
- RecyclerView替代Listview,实现滚动列表的显示
- Android编程权威指南之使用RecyclerView显示列表
- RecyclerView实现倒序列表
- RecyclerView列表数据刷新
- RecyclerView头部分组列表
- Kotlin实现recyclerView列表
- RecyclerView实现二级列表
- RecyclerView 不一样的列表
- Android中使用RecyclerView+RxJava2+Retrofit2+Butterkinfe8.5.1实现简单的新闻列表显示
- RecyclerView分栏显示处理
- recyclerView不显示数据
- RecyclerView 不显示
- Recyclerview不显示内容
- logstash入门(简单而全面)
- 【怎样写代码】工厂三兄弟之抽象工厂模式(一):问题案例
- 神奇密码锁(BFS)
- codeforces 706B Interesting drink
- 多dex打包时在 android5.0一下报错的问题 ,有谁能解决
- RecyclerView显示 列表
- Java二进制兼容性原理
- swift_032(Swift enum枚举高级使用范例)
- 微信文章转发到wordpress的php实现
- PPT模板、简历模板、图片素材网站
- [QTP]基本使用
- 关于 Java 中的 @Override 覆写
- 2.1 Windows核心编程-进程UAC下以管理员权限运行
- 【面经笔记】管道