说到RecyclerView,相信大家都不陌生,它是我们经典级ListView的升级版,升级后的RecyclerView展现了极大的灵活性。同时内部直接封装了ViewHolder,不用我们自己定义ViewHolder就能实现item的回收和复用功能。当然它肯定不止这些好处,比如我们可以自定义分割线,可以更加方便的实现列表的布局方式等等。虽说我们自己在第一次使用时,会比使用listView和gridView稍微的复杂一些,需要自定义的也多了一点,但是它却更好的体现了灵活性,可以随自己的喜好来随便的定义,当然最主要的是能更好的复用,只需一次的定义,却可随处的复用。

下面,我们来好好的学习下它的使用。

首先,我们要是用RecyclerView必须引入support-V7包,拿android studio来举例:

先打开File->选择Project Structure,之后在左边Modules选择你的项目,然后在点击右边的Dependencies,然后点击绿色的+号选择添加Library,然后找到recyclerview-v7双击加入到依赖库中。然后可以在build.gradle中查看:

dependencies {
compile fileTree(include: ['*.jar'], dir: 'libs')
testCompile 'junit:junit:4.12'
compile 'com.android.support:appcompat-v7:23.3.0'
compile 'com.android.support:recyclerview-v7:23.3.0'
}

可以找dependencies 中找到对recyclerview的支持,则说明添加成功,如果还没有的,可以clean下自己的工程。

接下来,我们就进入Recyclerview的学习。RecyclerView的学习目标就是以下四个方法,把以下四个方法完全的掌握了,也就真正的掌握了RecyclerView。

RecyclerView.setAdapter:用来设置adapter,显示数据

RecyclerView.setLayoutManager :用来设置显示布局的,目前系统给出三种布局,分别是垂直,水平和瀑布流式布局

RecyclerView.setItemAnimator :用来设置显示动画的

RecyclerView.addItemDecoration :用来设置列表分割线的

接下来我们就学习怎么使用以上四个方法来真正掌握Recyclerview的使用。要使用Recyclerview,我们必须先定义一个类(CustomRecyclerAdapter)并继承Recyclerview.Adapter,且实现它里面的方法,代码如下:

public class CustomRecyclerAdapter extends RecyclerView.Adapter<CustomRecyclerAdapter.ViewHolderHelper>{

    @Override
public ViewHolderHelper onCreateViewHolder(ViewGroup parent, int viewType) {
return null;
}
@Override
public void onBindViewHolder(ViewHolderHelper holder, int position) { }
@Override
public int getItemCount() {
return 0;
} public class ViewHolderHelper extends RecyclerView.ViewHolder{ public ViewHolderHelper(View itemView) {
super(itemView);
}
}
}

在我们还没正式开始使用之前,先大体上了解下上面三个方法是做什么的:

A. onCreateViewHolder()方法:该方法就是将布局文件转化为View并传递给RecyclerView封装好的ViewHolder。

B. onBindViewHolder()方法:该方法将会在固定的位置上把ViewHolder里的itemView数据映射在item中。

C. getItemCount()方法:该方法和listView中的getCount()一样,都是返回Item的个数。

了解了这三个方法,我们来先实现最简单的应用,把我们的数据显示在app中。

首先,我们创建一个布局文件recycler_view.xml,如下

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"> <android.support.v7.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent">
</android.support.v7.widget.RecyclerView> </LinearLayout>

创建RecycerActivity用来加载布局文件:

public class RecycerActivity extends Activity {
private RecyclerView mRecyclerView;
private List<String> mData;
private CustomRecyclerAdapter mCustomRecyclerAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.recycer_view);
mRecyclerView = (RecyclerView) findViewById(R.id.recycler_view);
initData();
//线性布局管理器
recyclerViewLayoutManager = new LinearLayoutManager(this);
//设置布局管理器
mRecyclerView.setLayoutManager(recyclerViewLayoutManager);
//设置显示动画
mRecyclerView.setItemAnimator(new DefaultItemAnimator());
//设置adapter
mCustomRecyclerAdapter = new CustomRecyclerAdapter(mData);
mRecyclerView.setAdapter(mCustomRecyclerAdapter); }
private void initData() {
mData = new ArrayList<String>();
for(int i = 0; i < 10; i++){
mData.add("第"+i+"item");
}
}
}

经过修改的CustomRecyclerAdapter 如下,

public class CustomRecyclerAdapter extends RecyclerView.Adapter<CustomRecyclerAdapter.ViewHolderHelper>{

    private List<String> mData;
public CustomRecyclerAdapter(List<String> data) {
mData = data;
} @Override
public ViewHolderHelper onCreateViewHolder(ViewGroup parent, int viewType) {
//onCreateViewHolder方法就是将布局文件转化为View并传递给RecyclerView封装好的ViewHolder
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_view, parent, false);
return new ViewHolderHelper(view);
} @Override
public void onBindViewHolder(ViewHolderHelper holder, int position) {
holder.textView.setText(mData.get(position));
} @Override
public int getItemCount() {
return mData.size();
}
}

item_view.xml布局文件

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<TextView
android:id="@+id/tv_item"
android:layout_toRightOf="@+id/iv_item"
android:layout_width="match_parent"
android:layout_height="30dp"
android:text="I am item view"/> </RelativeLayout>

好,基础工作已做足,我们先来看看效果吧

已经显示出来了,不过,大家看着是不是很别扭呢,连个分割线也没有,还不如listView呢,别急,我们在上面也提到过,RecyclerView给了我们最大的发挥自由度,它本身并没有给定列表的分割线,这是需要我们自己定义的。由此我们来定义自己的分割线。自定义分割线是需要我们继承RecyclerView.ItemDecoration类,并实现它的onDraw()方法。请看代码:

public class DividerItemDecoration extends RecyclerView.ItemDecoration{

    public static final int HORIZONTAL_LIST = LinearLayoutManager.HORIZONTAL;
public static final int VERTICAL_LIST = LinearLayoutManager.VERTICAL;
private int mOrientation;
private Context mContext;
private TextPaint mTextPaint;
private float listDividerSize = 2;
private int listDividerColor;
public DividerItemDecoration(Context context,int orientation){
mContext = context;
mTextPaint = new TextPaint();
mTextPaint.setColor(Color.RED);
setOrientation(orientation);
}
public void setOrientation(int orientation) {
if (orientation != HORIZONTAL_LIST && orientation != VERTICAL_LIST) {
throw new IllegalArgumentException("invalid orientation");
}
mOrientation = orientation;
}
@Override
public void onDraw(Canvas c, RecyclerView parent) {
super.onDraw(c, parent);
if(mOrientation == HORIZONTAL_LIST){
drawHorizontal(c, parent);
}else{
drawVertical(c, parent);
}
}
/**
* 绘制垂直分割线
* @param c
* @param parent
*/
private void drawVertical(Canvas c, RecyclerView parent) {
//分割线的左边界 = 子View的左padding值
int rectLeft = parent.getPaddingLeft();
//分割线的右边界 = 子View的宽度 - 子View的右padding值
int rectRight = parent.getWidth() - parent.getPaddingRight();
int childCount = parent.getChildCount();
for(int i = 0; i < childCount; i ++){
View child = parent.getChildAt(i);
RecyclerView.LayoutParams layoutParams = (RecyclerView.LayoutParams) child.getLayoutParams();
// 分割线的top = 子View的底部 + 子View的margin值
int rectTop = child.getBottom() + layoutParams.bottomMargin;
// 分割线的bottom = 分割线的top + 分割线的高度
float rectBottom = rectTop + listDividerSize;
c.drawRect(rectLeft,rectTop,rectRight,rectBottom,mTextPaint);
}
} /**
* 绘制水平分割线
* @param c
* @param parent
*/
private void drawHorizontal(Canvas c, RecyclerView parent) {
//分割线的上边界 = 子View的上padding值
int rectTop = parent.getPaddingTop();
//分割线的下边界 = 子View的高度 - 子View的底部padding值
int rectBottom = parent.getHeight() - parent.getPaddingBottom();
int childCount = parent.getChildCount();
for(int i = 0; i < childCount; i ++){
View child = parent.getChildAt(i);
RecyclerView.LayoutParams layoutParams = (RecyclerView.LayoutParams) child.getLayoutParams();
//分割线的Left = 子View的右边界 + 子View的左margin值
int rectLeft = child.getRight() + layoutParams.rightMargin;
//分割线的right = 分割线的Left + 分割线的宽度
float rectRight = rectLeft + listDividerSize;
c.drawRect(rectLeft,rectTop,rectRight,rectBottom,mTextPaint);
}
} @Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
super.getItemOffsets(outRect, view, parent, state);
if(mOrientation == VERTICAL_LIST){
outRect.set(0,0,0,(int)listDividerSize);
} else{
outRect.set(0,0,(int)listDividerSize,0);
}
}
}

代码很好理解,这里考虑了两个情况,分别是垂直和水平的布局,然后再ondraw()里面计算出四角边值,最后直接绘制一个矩形即可。

在RecycerActivity 中的onCreate中添加上一句

mRecyclerView.addItemDecoration(new DividerItemDecoration(this,DividerItemDecoration.VERTICAL_LIST));

现在再来看看效果。

现在已显示出来了,分割线也出来了,在这里只列出了垂直方向的布局,就不再列出其他样式的布局代码了,伙伴们可自行写写看。

或许有经验的小伙伴们已经知道我们的RecyclerView自己是没有实现点击事件的,这里需要我们来根据业务的需求自己来实现。这里我们利用事件回调机制来完成事件的触发。

首先我们需要在CustomRecyclerAdapter中定义一个接口,并在其中定义两个可用的事件方法,如下:

public interface OnItemClickListener{
void onItemClickListener();
void onLongItemClickListener();
}

这里提供了用于点击和长按的事件方法,接下来我们需要对外暴露该接口用于被调用

 public void setOnClickItemListener(OnItemClickListener onItemClickListener){
mOnItemClickListener = onItemClickListener;
}

然后我们可以在ViewHolderHelper 做如下的修改:

public class ViewHolderHelper extends RecyclerView.ViewHolder{

        private TextView textView;
public ViewHolderHelper(View itemView) {
super(itemView);
textView = (TextView)itemView.findViewById(R.id.tv_item);
textView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mOnItemClickListener.onItemClickListener();
}
});
textView.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
mOnItemClickListener.onLongItemClickListener();
return false;
}
});
}
}

首先得到我们itemView中的textView对应的Id,然后为textView添加事件,但是只是添加却并不实现,它的用意是谁调用谁实现。

最后在我们的RecycerActivity中添加如下代码,请看:

mCustomRecyclerAdapter.setOnClickItemListener(new CustomRecyclerAdapter.OnItemClickListener() {
@Override
public void onItemClickListener() {
Toast.makeText(getContext(),"单击",Toast.LENGTH_SHORT).show();
} @Override
public void onLongItemClickListener() {
Toast.makeText(getContext(),"长单击",Toast.LENGTH_SHORT).show();
}
});

下面在来看看是否可以实现事件的触发了呢?

ok,学到这里大家至少对RecylerView有了一个初步的认识,但是我们一想,这样写的话肯定达不到我们标题所说的无限复用,甚至连复用也遥不可及,是的,这样写是不可能完成复用的,接下来我们一步一步的慢慢调整,让它可以支持一次编写N次复用,达到极大多数的重复使用,即使不符合需求,我们也只需要修改丁点即可满足需求,这是我们的目标,接下来一步一步的实现。

首先,我们先整理下,看看可以调整哪些目标能逐步的实现重复使用的目标:

1. 数据类型:我们在使用List集合时,是无法固定类型的,有可能是String,int等等类型,所以我们不应该固定为哪一种类型。

2. 在onCreateViewHolder方法中,它需要映射一个布局文件并转化为View或是一个自定义View传递给RecyclerView封装好的ViewHolder,为了可以达到复用,所以我们就不可以在此直接映射布局文件。

3. 在onBindViewHolder方法中也不应该直接为itemView设置属性,如上面的:holder.textView.setText(mData.get(position));

4. 我们不应该在ViewHolder的构造方法中直接获取我们的itemView,并给它添加触发事件

以上几个是我们能很直观的得到的能重构的问题所在,至于其他的不容易想到的我们再重构的时候慢慢讲解。现在我们逐一的解决上面的问题,使我们能更达到重复使用的目的。

1,针对数据类型的不一致,我们可以根据具体的使用场景利用泛型进行传递到Adapter中,比如:我们再定义CustomRecyclerAdapter时使用泛型,让调用者传递过来它所拥有的类型,这样我们就可以不用考虑类型的不一致了。请看下面片段代码

public class CustomRecyclerAdapter<T> extends RecyclerView.Adapter<CustomViewHolderHelper>{
private Context mContext;
private List<T> mData;
private CustomOnItemClickListener mOnItemClickListener;
public CustomRecyclerAdapter(Context context, List<T> data) {
mContext = context;
mData = data;
}
}
...

RecycerActivity中在调用时可以这样使用:

mCustomRecyclerAdapter = new CustomRecyclerAdapter(this,mData);

这样就可以把类型给确定下来了,同时也解决了问题1的复用。

2 , 在onCreateViewHolder方法中,和问题一的解决方案是一样的,我们把需要的itemView给传递过去而不是固定写死在方法中

public class CustomRecyclerAdapter<T> extends RecyclerView.Adapter<CustomViewHolderHelper>{
private Context mContext;
private List<T> mData;
protected int mLayoutResId;
private CustomOnItemClickListener mOnItemClickListener;
public CustomRecyclerAdapter(Context context, int layoutResId, List<T> data) {
mContext = context;
mLayoutResId = layoutResId;
mData = data;
} /**
* Called when RecyclerView needs a new ViewHolder of the given type to represent
* an item.
* 当 RecyclerView 依据给出的类型需要一个新的 ViewHolder 去展示一个 item 时,该方法将会被调用
*
* 这个给出的类型是在 getItemViewType返回的,默认返回 0 。
*
* @param parent
* @param viewType
* @return
*/
@Override
public CustomViewHolderHelper onCreateViewHolder(ViewGroup parent, int viewType) {
//onCreateViewHolder方法就是将布局文件转化为View并传递给RecyclerView封装好的ViewHolder
View view = LayoutInflater.from(parent.getContext()).inflate(mLayoutResId, parent, false);
return new CustomViewHolderHelper(view);
}
}

RecycerActivity中在调用时可以这样使用:

mCustomRecyclerAdapter = new CustomRecyclerAdapter(this,R.layout.item_view,mData);

3 , 在onBindViewHolder方法中也不应该直接为itemView设置属性,我们可以在这里记录itemView的position,并给它设置监听事件,更重要的我们这这里可以创建一个抽象方法,让调用者自己去实现业务逻辑。请看代码:

public abstract class CustomRecyclerAdapter<T> extends RecyclerView.Adapter<CustomViewHolderHelper>
implements View.OnClickListener,View.OnLongClickListener{
private Context mContext;
private List<T> mData;
protected int mLayoutResId;
private CustomOnItemClickListener mOnItemClickListener;
public CustomRecyclerAdapter(Context context, int layoutResId, List<T> data) {
mContext = context;
mLayoutResId = layoutResId;
mData = data;
} /**
* Called when RecyclerView needs a new ViewHolder of the given type to represent
* an item.
* 当 RecyclerView 依据给出的类型需要一个新的 ViewHolder 去展示一个 item 时,该方法将会被调用
*
* 这个给出的类型是在 getItemViewType返回的,默认返回 0 。
*
* @param parent
* @param viewType
* @return
*/
@Override
public CustomViewHolderHelper onCreateViewHolder(ViewGroup parent, int viewType) {
//onCreateViewHolder方法就是将布局文件转化为View并传递给RecyclerView封装好的ViewHolder
View view = LayoutInflater.from(parent.getContext()).inflate(mLayoutResId, parent, false);
return new CustomViewHolderHelper(view);
} /**
* Called by RecyclerView to display the data at the specified position. This method should
* update the contents of the ViewHolder#itemView to reflect the item at the given position.
*
* RecyclerView 将要在特殊的位置上显示数据时,该方法将被调用。该方法将会在固定的位置上
* 把ViewHolder里的itemView数据映射在item中。
* @param holder
* @param position
*/
@Override
public void onBindViewHolder(CustomViewHolderHelper holder, int position) {
//把每一个itemView设置一个标签,方便以后根据标签获取到该itemView以便做其他事项,比如点击事件
holder.itemView.setTag(position);
holder.itemView.setOnClickListener(this);
holder.itemView.setOnLongClickListener(this);
T itemData = mData.get(position);
displayContents(holder,itemData);
} /**
*用来在holder中设置每个ItemView的显示数据
* 设定为抽象方法,是为:自己本身并不实现,谁使用谁设置
* @param holder
* @param itemData
*/
protected abstract void displayContents(CustomViewHolderHelper holder, T itemData);
}

上面注解也写的很清楚,相信大家一看就明白,至于为什么可以直接使用holder.itemView来获取每个itemView是因为在onCreateViewHolder()方法中,我们返回了一个新的对象引用,这个对象的构造方法中使用super(itemView);把我们的itemView传递到了ViewHolder中,请看它的源码构造方法:

 public ViewHolder(View itemView) {
if (itemView == null) {
throw new IllegalArgumentException("itemView may not be null");
}
this.itemView = itemView;
}

因此我们可以在onBindViewHolder()方法中,直接使用holder.itemView来获取itemView。那么接下来,在RecycerActivity中,我们这样使用:

 mCustomRecyclerAdapter = new CustomRecyclerAdapter<String>(this, R.layout.item_view, mData) {
@Override
protected void displayContents(CustomViewHolderHelper holder, String itemData) {
holder.setText(R.id.tv_item,itemData);
}
};

当然你必须也得在ViewHolder中定义相应的方法,如:

public class CustomViewHolderHelper extends RecyclerView.ViewHolder{

    private SparseArray<View> views;
public CustomViewHolderHelper(View itemView) {
super(itemView);
views = new SparseArray<View>();
}
private <T extends View> T converToViewFromId(int resId) {
View view = views.get(resId);
if(view == null){
view = itemView.findViewById(resId);
}
views.put(resId,view);
return (T)view;
} public CustomViewHolderHelper setText(int resId, String value){
TextView itemView = converToViewFromId(resId);
if (TextUtils.isEmpty(value)) {
itemView.setText("");
} else {
itemView.setText(value);
}
return this;
}
}

ok,这样我们连第四个问题也一并解决了,看下效果吧,完全的一样,这样我们就实现的重复使用,但是有人会有疑问,这里也就只能使用TextView啊,其实已经在ViewHolder中给出了答案,大家只需要在添加相对应的方法即可,比如

public CustomViewHolderHelper setImageResource(int viewId, int imageResId) {
ImageView view = converToViewFromId(viewId);
view.setImageResource(imageResId);
return this;
}
public CustomViewHolderHelper setOnClickListener(int viewId, View.OnClickListener listener) {
View view = converToViewFromId(viewId);
view.setOnClickListener(listener);
return this;
}

上面我又添加了两个方法,用于点击事件和加载图片的ImageView,下面我们再把itemView布局文件修改下:

item_view.xml布局文件:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"> <ImageView
android:id="@+id/iv_item"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:id="@+id/tv_item"
android:layout_toRightOf="@+id/iv_item"
android:layout_width="match_parent"
android:layout_height="30dp"
android:text="I am item view"/>
<Button
android:id="@+id/btn_item"
android:layout_toRightOf="@+id/iv_item"
android:layout_below="@+id/tv_item"
android:layout_width="wrap_content"
android:text="点我"
android:layout_height="wrap_content" />
</RelativeLayout>

RecycerActivity中在调用时可以这样使用:

mCustomRecyclerAdapter = new CustomRecyclerAdapter<String>(this, R.layout.item_view, mData) {
@Override
protected void displayContents(CustomViewHolderHelper holder, String itemData) {
holder.setText(R.id.tv_item,itemData)
.setImageResource(R.id.iv_item,R.mipmap.ic_launcher)
.setOnClickListener(R.id.btn_item, new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(RecycerActivity.this,"您单击了按钮",Toast.LENGTH_SHORT).show();
}
});
}
};

ok,来看下效果吧

是不是可以了呢,这样我们就可以完全的一次定义N次复用了,每次使用只需要更换不同的布局文件即可而不需要再次编写代码,学会了吧。

其实我们这节课主要讲解的RecyclerView.setAdapter的内容,其他的三个我们并没有详细的介入,我们会再以后的博文中陆续的讲解。

好了,今天就讲到这里吧,祝大家学习愉快。

更多资讯请关注微信平台,有博客更新会及时通知。爱学习爱技术。

Android 5.X新特性之RecyclerView基本解析及无限复用的更多相关文章

  1. android 5.0新特性学习--RecyclerView

    在过去很多年,我们的PC或者手机设备都是采用拟物化的设计风格,IOS采用扁平化的特性,android在2014年IO大会上说采用Material Design的设计风格,显示效果不能过于生硬的转换,而 ...

  2. Android 5.X新特性之为RecyclerView添加下拉刷新和上拉加载及SwipeRefreshLayout实现原理

    RecyclerView已经写过两篇文章了,分别是Android 5.X新特性之RecyclerView基本解析及无限复用 和 Android 5.X新特性之为RecyclerView添加Header ...

  3. Android 5.X新特性之为RecyclerView添加HeaderView和FooterView

    上一节我们讲到了 Android 5.X新特性之RecyclerView基本解析及无限复用 相信大家也应该熟悉了RecyclerView的基本使用,这一节我们来学习下,为RecyclerView添加H ...

  4. 《Android群英传》读书笔记 (5) 第十一章 搭建云端服务器 + 第十二章 Android 5.X新特性详解 + 第十三章 Android实例提高

    第十一章 搭建云端服务器 该章主要介绍了移动后端服务的概念以及Bmob的使用,比较简单,所以略过不总结. 第十三章 Android实例提高 该章主要介绍了拼图游戏和2048的小项目实例,主要是代码,所 ...

  5. Android 6.0 新特性 整理 资料来自网络

    Android 6.0新特性 Runtime Permissions Doze and App Standby Apache HTTP Client Removal BoringSSL Access ...

  6. 腾讯云安全:开发者必看|Android 8.0 新特性及开发指南

    欢迎大家关注腾讯云技术社区-博客园官方主页,我们将持续在博客园为大家推荐技术精品文章哦~ 背景介绍 谷歌2017 I/O开发者大会今年将于5月17-19日在美国加州举办.大会将跟往年一样发布最新的 A ...

  7. Android 8.0 新特性

    Android 8.0 (Android Oreo(奥利奥))新特性介绍 通知渠道 - Notification Channels 通知渠道是由应用自行定义的通知内容类别,借助渠道,开发者可以让用户对 ...

  8. 开发者必看|Android 8.0 新特性及开发指南

    背景介绍 谷歌2017 I/O开发者大会今年将于5月17-19日在美国加州举办.大会将跟往年一样发布最新的 Android 系统,今年为 Android 8.0.谷歌在今年3 月21日发布 Andro ...

  9. android 7.0 新特性 和对开发者的影响

    android 7.0新特性 - jiabailong的专栏 - 博客频道 - CSDN.NEThttp://blog.csdn.net/jiabailong/article/details/5241 ...

随机推荐

  1. raspberrypi(树莓派)上安装mono和jexus,运行asp.net程序

    参考网址: http://www.linuxdot.net/ http://www.cnblogs.com/mayswind/p/3279380.html http://www.raspberrypi ...

  2. To Java程序员:切勿用普通for循环遍历LinkedList

    ArrayList与LinkedList的普通for循环遍历 对于大部分Java程序员朋友们来说,可能平时使用得最多的List就是ArrayList,对于ArrayList的遍历,一般用如下写法: p ...

  3. AngularJS实例实战

    学习了这么多天的AngularJS,今天想从实战的角度和大家分享一个简单的Demo--用户查询系统,以巩固之前所学知识.功能需求需要满足两点 1.查询所有用户信息,并在前端展示 2.根据id查询用户信 ...

  4. 在 Linux 打造属于自己的 Vim

    Linux 系统中很多东西都是以脚本代码.配置文件的形式存在,使用 Linux 系统时,需经常对这些文件进行编辑.很显然,如果没有文本编辑器,江湖之路寸步难行. 我的选择是 Vim.Vim 是 Lin ...

  5. 架构设计:一种远程调用服务的设计构思(zookeeper的一种应用实践)

    在深入学习zookeeper我想先给大家介绍一个和zookeeper相关的应用实例,我把这个实例命名为远程调用服务.通过对这种应用实例的描述,我们会对zookeeper应用场景会有深入的了解. 远程调 ...

  6. git 行动指南

    Git是一个分布式的版本管理工具. 在本地项目和服务器都会拥有版本库,本地版本库由自己控制,自由选择提交代码到服务器端 windows上也建议使用命令的方式来使用git,推荐使用客户端 :http:/ ...

  7. ABP框架 - 数据传输对象

    文档目录 本节内容: DTO 必要性 领域层的抽象 数据隐藏 序列化和延迟加载问题 DTO 约定和验证 示例 DTO和实体间自动映射 使用特性和扩展方法进行映射 辅助接口和类 Data Transfe ...

  8. Windows操作系统下tomcat安装版图文教程

    下载tomcat安装文件,官方下载地址是:http://tomcat.apache.org/,本文以tomcat-7.0.26版本为例进行安装过程的说明: 1.双击apache-tomcat-7.0. ...

  9. 【原】SDWebImage源码阅读(四)

    [原]SDWebImage源码阅读(四) 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 SDWebImage中主要实现了NSURLConnectionDataDelega ...

  10. 推荐几款jquery图片切换插件

    一.前言 毕业季到了,大家都在匆匆忙忙的记录大学里最美好的时光,照片中各种花式.各种姿势都涌现出来了.这么多的照片怎么展示出来给自己的好友看呢?有人选择做成视频,有人选择ps之后做成图片集,而我选择利 ...