股票场内基金交易,没时间盯盘?
引言
最近学习了一下 RecyclerView ,感觉这个控件功能很强大啊,尤其是对于我这种常年使用 ListView 的人来说,不用网上去找各种什么瀑布流或者是横向滑动的 ListView 的开源控件去了,简直方便。下面我就从几个方面来对比一下 RecyclerView 和 ListView 。
1.基本用法
直接先上代码。
首先是 Listview 的代码部分:
(1)布局文件
activity_list_view_demo.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 |
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="jyx.test.demo.ListViewDemoActivity"> <ListView android:id="@+id/lv_test" android:layout_width="match_parent" android:layout_height="wrap_content"/> </RelativeLayout> |
呃,,,貌似过于简单了,但是还是贴出来吧,对比更加全面。
(2)Activity内的代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
public class ListViewDemoActivity extends AppCompatActivity { private ListView myListView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_list_view_demo); ArrayAdapter adapter = new ArrayAdapter(this,android.R.layout.simple_expandable_list_item_1,myList()); myListView = (ListView) findViewById(R.id.lv_test); myListView.setAdapter(adapter); } //创建一个list作为ListView的items private List myList(){ List list = new ArrayList(); String item; for (int i = 1; i < 20; i++) { item = "这是第"+ i + "个item"; list.add(item); } return list; } |
这样,一个ListView就完成了,我们来看看效果:
图1.适配器为ArrayAdapter的ListView
这里我使用了ArrayAdapter来做适配器,ArrayAdapter经过了封装,性能较好,而且可以直接使用android.R.layout.simple_expandable_list_item_1 这种Android自己提供的做item的view来显示数据,十分方便,我们也可以继承重写ArrayAdapter来实现我们自定义的itemView,在使用ListView的时候,大多也都是使用ArrayAdapter来做适配器。当然,我们还可以通过继承重写BaseAdapter 的方式来做,下面我们一起看一下。(布局文件都一样,只不过我们这里需要加一个自己定义的item的view)
item_listview.xml
1 2 3 4 5 6 7 8 9 10 11 |
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical"> <TextView android:id="@+id/txt_item_listview" android:layout_width="match_parent" android:layout_height="50dp" android:gravity="center_vertical"/> </LinearLayout> |
Activity内的代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
public class ListViewDemoActivity extends AppCompatActivity { private ListView myListView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_list_view_demo); myListView = (ListView) findViewById(R.id.lv_test); myListView.setAdapter(new listViewAdapter(this)); } //继承重写BaseAdapter class listViewAdapter extends BaseAdapter{ private LayoutInflater mInflater; public listViewAdapter(Context context) { mInflater = LayoutInflater.from(context); } @Override public int getCount() { return myList().size(); } @Override public Object getItem(int i) { return null; } @Override public long getItemId(int i) { return 0; } @Override public View getView(int position, View convertView, ViewGroup viewGroup) { //这里要进行convertView复用的处理 if (convertView == null){ convertView = mInflater.inflate(R.layout.item_listview,null); } TextView txtItem = view.findViewById(R.id.txt_item_listview); txtItem.setText(myList().get(position).toString()); return convertView; } } } |
效果如下:
图2.适配器为BaseAdapter的ListView效果图
上面就是ListView的代码,虽然实现了效果,但只要仔细看的朋友都会发现,每一个itemView似乎都会调用以此Adapter,然而我们上面直接在getView()方法中直接创建TextView的行为似乎有些不妥,我们的例子中数据少看不出什么端倪,但是如果是成百上千的数据,每次都要创建一次TextView就会很影响性能,这里我们介绍一个机制ViewHolder,ViewHolder是一个持有者的类,他里面一般没有方法,只有属性,作用就是一个临时的储存器,把你getView方法中每次返回的View存起来,可以下次再用。这样做的好处就是不必每次都到布局文件中去拿到你的View,提高了效率。使用ViewHolder的方式也很简单,首先我们在Activity中新建一个内部类,把你自定义的itemView中需要用到的控件都定义在里面的:
1 2 3 4 5 |
//ViewHolder private class ViewHolder{ private TextView txtItem; } |
然后,我们只需改动一下getView()方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
@Override public View getView(int position, View convertView, ViewGroup viewGroup) { ViewHolder holder = null; if (convertView == null){ holder = new ViewHolder(); convertView = mInflater.inflate(R.layout.item_listview,null); holder.txtItem = convertView.findViewById(R.id.txt_item_listview); convertView.setTag(holder); }else{ //convertView不为空时直接重复使用 holder = (ViewHolder) convertView.getTag(); } holder.txtItem.setText(myList().get(position).toString()); return convertView; } |
这样不仅提高了ListView的性能,还提高了代码的可读性。可是即使这样,我还是觉得有些不足,那就是我们还必须自己去新建这个Viewholder的类,有没有不用我们自己动手去做这件事的呢,,,,当然有,比如我们下面要说的 RecyclerView 。
RecyclerView 的代码部分:
(1)布局文件
activity_list_view_demo.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 |
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="jyx.test.demo.RecyclerViewDemoActivity"> <android.support.v7.widget.RecyclerView android:id="@+id/rv_test" android:layout_width="match_parent" android:layout_height="wrap_content"/> </RelativeLayout> |
看起来似乎和ListView的差别不大,还是看看Activity内的代码来对比一下。
(2)Activity内的代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
public class RecyclerViewDemoActivity extends AppCompatActivity { private RecyclerView myRecyclerView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_recycler_view_demo); myRecyclerView = (RecyclerView) findViewById(R.id.rv_test); //设置LayoutManager LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this); myRecyclerView.setLayoutManager(linearLayoutManager); //绑定adapter myRecyclerView.setAdapter(new recyclerViewAdapter(this)); } //创建adapter class recyclerViewAdapter extends RecyclerView.Adapter<recyclerViewAdapter.ViewHolder>{ LayoutInflater mInflater; public recyclerViewAdapter(Context context) { mInflater = LayoutInflater.from(context); } //创建一个新的view,由LayoutManager调用 @Override public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View view = mInflater.inflate(R.layout.item_listview,parent,false); ViewHolder holder = new ViewHolder(view); return holder; } //数据绑定控件 @Override public void onBindViewHolder(ViewHolder holder, int position) { holder.mTextView.setText(myList().get(position).toString()); } @Override public int getItemCount() { return myList().size(); } public class ViewHolder extends RecyclerView.ViewHolder { public TextView mTextView; public ViewHolder(View itemView) { super(itemView); mTextView = itemView.findViewById(R.id.txt_item_listview); } } } //创建一个list作为数据源 private List myList(){ List list = new ArrayList(); String item; for (int i = 1; i < 20; i++) { item = "这是第"+ i + "个item"; list.add(item); } return list; } } |
这样,一个RecyclerView也完成了,看看效果:
图3.RecyclerView效果图
呃,,,从效果上来看,不但没什么区别,反而少了item之间的分割线,而且xml中 RecyclerView 并没有divider这个属性,虽然我们可以去item的布局文件中去加上分割线,但是这样看起来就太不专业了。其实 RecyclerView 是支持自定义间隔样式的,在Activity中加上这行代码:
1 2 3 |
//添加分割线 myRecyclerView.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL)); |
让我们来看看效果:
图4.有分割线的RecyclerView
这只是默认的分割线,我们还可以通过继承 RecyclerView.ItemDecoration 这个抽象类来自定义分割线的样式,这次就先不做细致说明了。
这样看起来就和上面的 Listview 一模一样了。虽然外观一样了,但是通过代码的对比,我们可以总结出以下几点:
1.RecyclerView不用进行item的复用工作,这个工作Google已经做好了
2.RecyclerView的ViewHolder编写比Listview的更加规范化
3.RecyclerView需要进行LayoutManager和分割线的设定
这样看来,RecyclerView和 ListView也没有太大区别,但是就基本用法来说上面的效果已经可以说是 ListView的大部分“功力”了,而 RecyclerView还有更多效果。Android提供的 RecyclerView除了 线性布局 的效果,还有 网格布局 和 瀑布流布局,而且 线性布局 还可以会横向滑动,下面我们分别简单的看一下:
(1)线性布局横向滑动
想让线性布局横向滑动,在上面代码的基础上,只需修改三处:
第一步,将item的xml中TextView的长宽属性调换一下,把RecyclerView控件的高改为“match_parent”(这里不做演示)
第二步,如下:
1 2 3 4 5 |
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this); //这里将Orientation设置为横向 linearLayoutManager.setOrientation(LinearLayoutManager.HORIZONTAL); myRecyclerView.setLayoutManager(linearLayoutManager); |
第三步,修改分割线属性为横向分割线:
1 2 |
myRecyclerView.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.HORIZONTAL)); |
看下效果:
图5.横向的RecyclerView
(2)网格布局
代码
1 2 3 4 |
//这里的数字表示每行item的个数 GridLayoutManager gridLayoutManager = new GridLayoutManager(this,4); myRecyclerView.setLayoutManager(gridLayoutManager); |
效果:
图6.RecyclerView网格布局
(3)瀑布流布局
设置每个item的高度为随机的,可以让瀑布流看起来更高大上,下面直接上代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 |
public class RecyclerViewDemoActivity extends AppCompatActivity { private RecyclerView myRecyclerView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_recycler_view_demo); myRecyclerView = (RecyclerView) findViewById(R.id.rv_test); //设置LayoutManager StaggeredGridLayoutManager sgLayoutManager = new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL); myRecyclerView.setLayoutManager(sgLayoutManager); //绑定adapter myRecyclerView.setAdapter(new recyclerViewAdapter(this)); } //创建adapter class recyclerViewAdapter extends RecyclerView.Adapter<recyclerViewAdapter.ViewHolder>{ LayoutInflater mInflater; public recyclerViewAdapter(Context context) { mInflater = LayoutInflater.from(context); } //创建一个新的view,由LayoutManager调用 @Override public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View view = mInflater.inflate(R.layout.item_listview,parent,false); ViewHolder holder = new ViewHolder(view); return holder; } //数据绑定控件 @Override public void onBindViewHolder(ViewHolder holder, int position) { holder.mTextView.setText(myList().get(position).toString()); ViewGroup.LayoutParams layoutParams = holder.mTextView.getLayoutParams(); //设置item高度 layoutParams.height = (int) getHeight().get(position); holder.mTextView.setLayoutParams(layoutParams); } @Override public int getItemCount() { return myList().size(); } public class ViewHolder extends RecyclerView.ViewHolder { public TextView mTextView; public ViewHolder(View itemView) { super(itemView); mTextView = itemView.findViewById(R.id.txt_item_listview); } } } //创建一个list作为ListView的items private List myList(){ List list = new ArrayList(); String item; for (int i = 1; i < 20; i++) { item = "这是第"+ i + "个item"; list.add(item); } return list; } //创建一个存放随机数200-600的list作为item高度 private List getHeight(){ List list = new ArrayList(); int height; for (int i = 0; i < myList().size(); i++) { height = (int) (200 + Math.random() * 400); list.add(height); } return list; } } |
来看看效果:
图7.RecyclerView的瀑布流布局
虽然没设置边框,但是可以看出高度的不同。(让我很费解的是,既然有了StaggeredGridLayoutManager,为什么还要去我们自己去设置随机的高度)。
好,基本使用的对比先到这里,我们继续对比其他方面。
2.空数据的处理
ListView 为我们提供了setEmptyView这个API来让我们处理数据源为空的情况,而RecyclerView则没有,这个步骤需要自己来做,逻辑虽然简单,但是还是没有特别方便。
3.HeaderView和FootView
ListView 可以让我们设置HeaderView和FootView,当我们想加上一个下拉刷新的或者底部加载更多的视图的时候,可以很方便的就完成了,但是 RecyclerView 就没有为我们提供这种便利,实现起来比较麻烦。希望官方以后可以继续完善。
4.item的点击事件
又是一个让人郁闷的地方, RecyclerView 并没有像ListView 那样为我们提供短按监听OnItemClickListener()长按监听onLongClickListener,这里有两种方法,一是直接在adapter内直接为view设置监听,二是设置mRecyclerView.addOnItemTouchListener去监听然后去判断手势, 个人觉得第一种方法既简单又直观,我会选择这种方法。下面就演示一下。
ListView的item点击事件
代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
myListView.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) { Toast.makeText(getBaseContext(),"短按"+myList().get(i),Toast.LENGTH_SHORT).show(); } }); myListView.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() { @Override public boolean onItemLongClick(AdapterView<?> adapterView, View view, int i, long l) { Toast.makeText(getBaseContext(),"长按"+myList().get(i),Toast.LENGTH_SHORT).show(); //这里返回true表示不会触发短按事件,false则相反 return true; } }); |
看看效果:
图8.ListView点击事件
RecyclerView的item点击事件
这里我是直接在onBindViewHolder方法中绑定的点击事件,其他地方不变:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
@Override public void onBindViewHolder(ViewHolder holder, final int position) { holder.mTextView.setText(myList().get(position).toString()); holder.mTextView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Toast.makeText(getBaseContext(),"短按"+myList().get(position),Toast.LENGTH_SHORT).show(); } }); holder.mTextView.setOnLongClickListener(new View.OnLongClickListener() { @Override public boolean onLongClick(View view) { Toast.makeText(getBaseContext(),"长按"+myList().get(position),Toast.LENGTH_SHORT).show(); return true; } }); } |
看下效果:
图9.RecyclerView点击事件
这样处理貌似效果上都差不多,但是有个细节做的并不到位,就是没有动画效果,需要我们自己去代码中设置。
5.数据刷新
在ListView中,我们要刷新数据就要用到 notifyDataSetChanged(),数据源更新后我们就需要用这个方法去更新在Adapter中通过这个方法去更新视图,这十分简单,但是这个方法是将所有视图都重绘,可是没有更新数据的itemView并不需要重绘,所以我们还需要自己手动操作去控制只更新数据变化的itemView。
RecyclerView.Adapter 则我们提供了 notifyItemChanged() 用于更新单个 ItemView 的刷新,我们可以省去自己写局部更新的工作。
总结
通过这些对比,我们大概了解了两个控件的基本使用方法和区别,以后随着我们的使用,我们会更加深入了解它们的功能以及更加深入地发掘它们的使用方法。就目前来看,两个控件并没有说哪个可以完全取代另一个,各有各的优势,我们要学会灵活运用它们,这才是对比它们的意义。
最后感谢阅读,欢迎指正。
想获得去掉 5 元限制的证券账户吗?

如果您想去掉最低交易佣金 5 元限制,使用微信扫描左边小程序二维码,访问微信小程序「优财助手」,点击底部菜单「福利」,阅读文章「通过优财开证券账户无最低交易佣金 5 元限制」,按照文章步骤操作即可获得免 5 元证券账户,股票基金交易手续费率万 2.5。
请注意,一定要按照文章描述严格操作,如错误开户是无法获得免 5 元证券账户的。