RecycleView 是2014年Google IO 引入的新的控件,它是以 v7 support libraries的形式存在的,可以用在之前的Android系统版本。它的引入主要是用于增强ListView的功能。与其它的View不一样的地方是RecyclerView不负责子view的展现和布局工作,它关注的是子view的回收与复用。而子view的布局、装饰、动画都交给了其内部类来负责。

ViewHolder :用来放置每个item所包含子view的容器。在Adapter中负责创建和填充ViewHolder
Adapter :用于绑定数据和ViewHolder
LayoutManager :布局管理器,负责子View的位置安排
ItemDecoration :用来装饰子view
ItemAnimator :用于添加子View,增加删除的动画

RecycleView的简单使用

下面就由简单到复杂一步一步介绍它的使用。

1.在项目中引入recycleview的依赖关系。

compile 'com.android.support:recyclerview-v7:23.4.0'

如果大家不是很清楚recycleview的版本号的话,可以使用project structrue -> dependencies 输入recycleview,这时候会自动帮你查找对应的版本。

  1. Adapter 负责生成出绑定数据后的ViewHolder,它继承自RecyclerView.Adapter,一般而言它有一个构造方法用于用于传入两个参数,一个是上下文内容,一个是数据列表,还可以有另外一个参数用于传入布局id。
    public class MyRecycleViewAdapter extends RecyclerView.Adapter<MyRecycleViewAdapter.ViewHolder> {

    private Context mContext;
    private ArrayList<String> mList;
    MyRecycleViewAdapter(Context context, List<String> list) {
    mContext = context;
    mList = (ArrayList<String>) list;
    }
    }
    由于它继承自RecyclerView.Adapter所以必须覆写:
    onCreateViewHolder
    onBindViewHolder
    getItemCount
    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    LayoutInflater mInflater = LayoutInflater.from(parent.getContext());
    View itemView = mInflater.inflate(R.layout.recycleview_item, parent, false);
    return new ViewHolder(itemView);
    }
    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
    String content = mList.get(position);
    holder.mContentView.setText(content);
    }
    @Override
    public int getItemCount() {
    return mList.size();
    }
    onCreateViewHolder 负责使用item layout 初始化出一个ItemView,再将ItemView传入ViewHoder,在ViewHolder中创建出构成ItemView的每个子View然后作为参数传递给onBindViewHolder,onBindViewHolder有两个参数,一个是onCreateViewHolder创建的ViewHolder,另一个是数据对应的位置,可以通过第二个参数重数据源中取出数据,然后和ViewHoder中的控件绑定。

下面是ViewHolder的实现:

public class ViewHolder extends RecyclerView.ViewHolder {
public TextView mContentView;
public ViewHolder(View itemView) {
super(itemView);
mContentView = (TextView) itemView.findViewById(R.id.listview_item);
}
}

最后初始化整个RecycleView:

public class MainActivity extends AppCompatActivity {
private RecyclerView mRecycleView = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mRecycleView = (RecyclerView) findViewById(R.id.recycle_view);
mRecycleView.setLayoutManager(new GridLayoutManager(this,2));
List<String> stringlist = new ArrayList<>();
for(int i =0;i<100;i++) {
stringlist.add("Item " + i);
}
mRecycleView.setAdapter(new MyRecycleViewAdapter(this,stringlist));
mRecycleView.setItemAnimator(new DefaultItemAnimator());
}
}

RecycleView组成

RecyclerView.LayoutManager
RecyclerView.ItemDecoration
RecyclerView.ItemAnimator
ItemAnimator 用于在往RecycleView中添加删除或者移动Item的时候添加动画。默认情况下使用的是DefaultItemAnimator,在实际项目的时候会需要实现这个部分,如果大家有这种需求可以参考:
https://github.com/wasabeef/recyclerview-animators

多类型Item布局

在RecyclerView.Adopter中要实现多类型Item布局需要覆写如下方法:

public int getItemViewType(int position)  

并按照如下方法重新修改Adapter:

public class MyRecycleViewAdapter extends
/*这里改为RecyclerView.ViewHolder 因为这时候需要两个ViewHoder*/
RecyclerView.Adapter<RecyclerView.ViewHolder> {
private Context mContext;
private ArrayList<String> mList;
/*定义一个枚举类型用于指定item的类型*/
private enum ITEM_TYPE {
TYPE_ONE,
TYPE_TWO
};
/*根据对应的position返回当前的item类型*/
@Override
public int getItemViewType(int position) {
return (position % 2 == 0) ? ITEM_TYPE.TYPE_ONE.ordinal():ITEM_TYPE.TYPE_TWO.ordinal();
}

MyRecycleViewAdapter(Context context, List<String> list) {
mContext = context;
mList = (ArrayList<String>) list;
}

/*根据对应的viewType创建并返回对应的ViewHolder*/
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater mInflater = LayoutInflater.from(parent.getContext());
View itemView = null;
if(viewType == ITEM_TYPE.TYPE_ONE.ordinal()) {
itemView = mInflater.inflate(R.layout.recycleview_item, parent, false);
return new ViewHolder(itemView);
}else{
itemView = mInflater.inflate(R.layout.recycleview_two, parent, false);
return new ViewHolderTwo(itemView);
}
}

@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
String content = mList.get(position);
if(holder instanceof MyRecycleViewAdapter.ViewHolder) {
((ViewHolder) holder).mContentView.setText(content);
}else if(holder instanceof MyRecycleViewAdapter.ViewHolderTwo) {
((ViewHolderTwo) holder).mImageView.setImageResource(R.mipmap.ic_launcher);
((ViewHolderTwo) holder).mContentView.setText(content);
}
}

@Override
public int getItemCount() {
return mList.size();
}

public class ViewHolder extends RecyclerView.ViewHolder {
public TextView mContentView;
public ViewHolder(View itemView) {
super(itemView);
mContentView = (TextView) itemView.findViewById(R.id.listview_item);
}
}
public class ViewHolderTwo extends RecyclerView.ViewHolder {
public TextView mContentView;
private ImageView mImageView;
public ViewHolderTwo(View itemView) {
super(itemView);
mImageView = (ImageView) itemView.findViewById(R.id.imageicon);
mContentView = (TextView) itemView.findViewById(R.id.itemtext);
}
}
}

添加ItemDecoration

首先创建一个新的类继承自RecyclerView.ItemDecoration。
https://gist.github.com/alexfu/0f464fc3742f134ccd1e/

class ItemDecortion extends RecyclerView.ItemDecoration {
private static final int[] ATTRS = new int[]{
android.R.attr.listDivider
};
public static final int HORIZONTAL_LIST = LinearLayoutManager.HORIZONTAL;
public static final int VERTICAL_LIST = LinearLayoutManager.VERTICAL;
private Drawable mDivider;
private int mOrientation;
public ItemDecortion(Context context, int orientation) {
final TypedArray a = context.obtainStyledAttributes(ATTRS);
mDivider = a.getDrawable(0);
a.recycle();
setOrientation(orientation);
}

public void setOrientation(int orientation) {
if (orientation != HORIZONTAL_LIST && orientation != VERTICAL_LIST) {
throw new IllegalArgumentException("invalid orientation");
}
mOrientation = orientation;
}

@Override
public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
if (mOrientation == VERTICAL_LIST) {
drawVertical(c, parent);
} else {
drawHorizontal(c, parent);
}
}

public void drawVertical(Canvas c, RecyclerView parent) {
final int left = parent.getPaddingLeft();
final int right = parent.getWidth() - parent.getPaddingRight();
final int childCount = parent.getChildCount();
for (int i = 0; i < childCount; i++) {
final View child = parent.getChildAt(i);
final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
final int top = child.getBottom() + params.bottomMargin;
final int bottom = top + mDivider.getIntrinsicHeight();
mDivider.setBounds(left, top, right, bottom);
mDivider.draw(c);
}
}
public void drawHorizontal(Canvas c, RecyclerView parent) {
final int top = parent.getPaddingTop();
final int bottom = parent.getHeight() - parent.getPaddingBottom();
final int childCount = parent.getChildCount();
for (int i = 0; i < childCount; i++) {
final View child = parent.getChildAt(i);
final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
final int left = child.getRight() + params.rightMargin;
final int right = left + mDivider.getIntrinsicHeight();
mDivider.setBounds(left, top, right, bottom);
mDivider.draw(c);
}
}
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
if (mOrientation == VERTICAL_LIST) {
outRect.set(0, 0, 0, mDivider.getIntrinsicHeight());
} else {
outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0);
}
}
}

然后在设置adapter之前,使用addItemDecoration()方法添加分割线.

mRecycleView.addItemDecoration(new ItemDecortion(this,ItemDecortion.VERTICAL_LIST));
mRecycleView.setAdapter(new MyRecycleViewAdapter(this,stringlist));
添加点击事件:

ListView 和RecycleView最大的不同就是没有OnItemClickListener来识别item的点击,我们必须自己通过扩展RecyclerView.OnItemTouchListener类来实现这个功能。

private interface onClickListener {
public void onClick(View view, int position);
public void onLongClick(View view,int position);
}
public static class RecyclerTouchListener implements RecyclerView.OnItemTouchListener {
private GestureDetector gestureDetector;
private MainActivity.onClickListener clickListener;
public RecyclerTouchListener(Context context, final RecyclerView recyclerView, final MainActivity.onClickListener clickListener) {
this.clickListener = clickListener;
gestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() {
@Override
public boolean onSingleTapUp(MotionEvent e) {
return true;
}
public void onLongPress(MotionEvent e) {
View child = recyclerView.findChildViewUnder(e.getX(), e.getY());
if (child != null && clickListener != null) {
clickListener.onLongClick(child, recyclerView.getChildPosition(child));
}
}
});
}
public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
View child = rv.findChildViewUnder(e.getX(), e.getY());
if (child != null && clickListener != null && gestureDetector.onTouchEvent(e)) {
clickListener.onClick(child, rv.getChildPosition(child));
}
return false;
}
public void onTouchEvent(RecyclerView rv, MotionEvent e) {
}

public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {

}
}
recyclerView.addOnItemTouchListener(new RecyclerTouchListener(getApplicationContext(), recyclerView, new ClickListener() {
public void onClick(View view, int position) {
Movie movie = movieList.get(position);
Toast.makeText(getApplicationContext(), movie.getTitle() + " is selected!", Toast.LENGTH_SHORT).show();
}
public void onLongClick(View view, int position) {

}
}));

增删改Item项

在ListView中每当Adapter数据项改变的时候一般执行notifyDataSetChanged()来通知数据集的改变,但是RecyclerView.Adapter 提供了 notifyItemInserted(), notifyItemChanged() 和 notifyItemRemoved()三个方法来通知数据集的修改。

Android working with Card View and Recycler View

翻译:林晓海
文章地址:http://www.androidhive.info/2016/05/android-working-with-card-view-and-recycler-view/

CardView 是 Material Design 引入的又一个重要的新控件,使用CardView可以用一个带有阴影和圆弧的卡片来展示信息,CardView继承自FragmentLayout,可以通过兼容包的形式向后兼容到Androd 2.x版本。

可以将CardView和RecycleView结合实现漂亮的UI效果,通过这篇文章我们可以通过创建一个漂亮的Music app 来学习如何结合CardView和RecycleView。

怎样添加CardView?
为了在你的app中使用CardView,添加CardView依赖到build.gradle,然后同步下项目:

dependencies {
// CardView
compile 'com.android.support:cardview-v7:23.3.+'
}

要使用CardView就要在布局文件中添加<android.support.v7.widget.CardView> 然后在节点里面添加其他的UI控件。下面的布局中CardView只有一个简单的TextView。

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:card_view="http://schemas.android.com/apk/res-auto">

<android.support.v7.widget.CardView
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:id="@+id/card_view"
android:layout_gravity="center"
android:layout_width="250dp"
android:layout_height="250dp"
card_view:cardCornerRadius="4dp">

<TextView
android:text="Hello Card"
android:layout_width="match_parent"
android:layout_height="match_parent" />

</android.support.v7.widget.CardView>

</LinearLayout>
  1. 创建新项目
    通过 File ⇒ New Project 的方式在Android Studio中创建一个新项目,然后在弹出选择Activity的模板页中选择Empty Activity。

  2. 下载 res.zip 然后将其添加到你刚刚创建项目的资源文件夹上,这个资源文件夹中包含了专辑封面以及其他需要的图标。

  3. 将下面的字符串,颜色和尺寸资源添加到strings.xml, colors.xml and dimens.xml文件中.

strings.xml

<resources>
<string name="app_name">Card View</string>
<string name="action_settings">Settings</string>
<string name="action_add_favourite">Add to Favourites</string>
<string name="action_play_next">Play Next</string>
<string name="backdrop_title">LOVE MUSIC</string>
<string name="backdrop_subtitle">This season top 20 albums</string>
</resources>

colors.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="colorPrimary">#F50057</color>
<color name="colorPrimaryDark">#F50057</color>
<color name="colorAccent">#FF4081</color>
<color name="viewBg">#f1f5f8</color>
<color name="album_title">#4c4c4c</color>
</resources>

dimens.xml

<resources>
<!-- Default screen margins, per the Android Design guidelines. -->
<dimen name="activity_horizontal_margin">16dp</dimen>
<dimen name="activity_vertical_margin">16dp</dimen>
<dimen name="fab_margin">16dp</dimen>
<dimen name="item_offset">10dp</dimen>
<dimen name="detail_backdrop_height">250dp</dimen>
<dimen name="backdrop_title">30dp</dimen>
<dimen name="backdrop_subtitle">18dp</dimen>
<dimen name="card_margin">5dp</dimen>
<dimen name="card_album_radius">0dp</dimen>
<dimen name="album_cover_height">160dp</dimen>
<dimen name="album_title_padding">10dp</dimen>
<dimen name="album_title">15dp</dimen>
<dimen name="songs_count_padding_bottom">5dp</dimen>
<dimen name="songs_count">12dp</dimen>
<dimen name="ic_album_overflow_width">20dp</dimen>
<dimen name="ic_album_overflow_height">30dp</dimen>
<dimen name="ic_album_overflow_margin_top">10dp</dimen>
</resources>
  1. 打开 build.gradle 往上面添加CardView, RecyclerView 和 Glide 的依赖. RecyclerView 用于以网格的方式显示专辑信息,CardView 用于现实单个专辑信息,Glide用于显示专辑封面图片。
build.gradle
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
testCompile 'junit:junit:4.12'
compile 'com.android.support:appcompat-v7:23.3.0'
compile 'com.android.support:design:23.3.0'
// RecyclerView
compile 'com.android.support:recyclerview-v7:23.3.+'
// CardView
compile 'com.android.support:cardview-v7:23.3.+'
// Glide
compile 'com.github.bumptech.glide:glide:3.7.0'
}
  1. 为了创建单个专辑的实例,我们使用一个单独的model类来存放专辑姓名,歌曲数目和封面图片,下面是这个类的源码:
    Abum.java
    package info.androidhive.cardview;
    public class Album {
    private String name;
    private int numOfSongs;
    private int thumbnail;
    public Album() {
    }
    public Album(String name, int numOfSongs, int thumbnail) {
    this.name = name;
    this.numOfSongs = numOfSongs;
    this.thumbnail = thumbnail;
    }
    public String getName() {
    return name;
    }
    public void setName(String name) {
    this.name = name;
    }
    public int getNumOfSongs() {
    return numOfSongs;
    }
    public void setNumOfSongs(int numOfSongs) {
    this.numOfSongs = numOfSongs;
    }
    public int getThumbnail() {
    return thumbnail;
    }
    public void setThumbnail(int thumbnail) {
    this.thumbnail = thumbnail;
    }
    }
  2. 我们还需要一个xml布局文件用于现实专辑卡片,这里我们新建一个album_card.xml 布局文件,这里我们增加了<android.support.v7.widget.CardView> 并且添加了专辑姓名,歌曲数目,和专辑封面等信息。并且我们还添加了三个点的按钮,在我们按下它的时候会弹出Popup 菜单。

album_card.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.v7.widget.CardView
android:id="@+id/card_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
android:layout_margin="@dimen/card_margin"
android:elevation="3dp"
card_view:cardCornerRadius="@dimen/card_album_radius">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/thumbnail"
android:layout_width="match_parent"
android:layout_height="@dimen/album_cover_height"
android:background="?attr/selectableItemBackgroundBorderless"
android:clickable="true"
android:scaleType="fitXY" />
<TextView
android:id="@+id/title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/thumbnail"
android:paddingLeft="@dimen/album_title_padding"
android:paddingRight="@dimen/album_title_padding"
android:paddingTop="@dimen/album_title_padding"
android:textColor="@color/album_title"
android:textSize="@dimen/album_title" />
<TextView
android:id="@+id/count"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/title"
android:paddingBottom="@dimen/songs_count_padding_bottom"
android:paddingLeft="@dimen/album_title_padding"
android:paddingRight="@dimen/album_title_padding"
android:textSize="@dimen/songs_count" />
<ImageView
android:id="@+id/overflow"
android:layout_width="@dimen/ic_album_overflow_width"
android:layout_height="@dimen/ic_album_overflow_height"
android:layout_alignParentRight="true"
android:layout_below="@id/thumbnail"
android:layout_marginTop="@dimen/ic_album_overflow_margin_top"
android:scaleType="centerCrop"
android:src="@drawable/ic_dots" />
</RelativeLayout>
</android.support.v7.widget.CardView>
</LinearLayout>
  1. 创建一个menu文件,这个menu将会在用户点击弹出菜单的按钮的时候作为菜单显现出来的。

    menu_album.xml
    <menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools">
    <item
    android:id="@+id/action_add_favourite"
    android:orderInCategory="100"
    android:title="@string/action_add_favourite" />
    <item
    android:id="@+id/action_play_next"
    android:orderInCategory="101"
    android:title="@string/action_play_next" />
    </menu>
  2. 为了使用RectycleView我们需要一个Adapter类它通过将有用的数据inflates album_card.xml 布局.因此我们需要创建一个AlbumsAdapter.java的类然后添加如下的内容:

AlbumsAdapter.java

package info.androidhive.cardview;
import android.content.Context;
import android.support.v7.widget.PopupMenu;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import com.bumptech.glide.Glide;
import java.util.List;
public class AlbumsAdapter extends RecyclerView.Adapter<AlbumsAdapter.MyViewHolder> {
private Context mContext;
private List<Album> albumList;
public class MyViewHolder extends RecyclerView.ViewHolder {
public TextView title, count;
public ImageView thumbnail, overflow;
public MyViewHolder(View view) {
super(view);
title = (TextView) view.findViewById(R.id.title);
count = (TextView) view.findViewById(R.id.count);
thumbnail = (ImageView) view.findViewById(R.id.thumbnail);
overflow = (ImageView) view.findViewById(R.id.overflow);
}
}
public AlbumsAdapter(Context mContext, List<Album> albumList) {
this.mContext = mContext;
this.albumList = albumList;
}
@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.album_card, parent, false);
return new MyViewHolder(itemView);
}
@Override
public void onBindViewHolder(final MyViewHolder holder, int position) {
Album album = albumList.get(position);
holder.title.setText(album.getName());
holder.count.setText(album.getNumOfSongs() + " songs");
// loading album cover using Glide library
Glide.with(mContext).load(album.getThumbnail()).into(holder.thumbnail);
holder.overflow.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
showPopupMenu(holder.overflow);
}
});
}
/**
* Showing popup menu when tapping on 3 dots
*/
private void showPopupMenu(View view) {
// inflate menu
PopupMenu popup = new PopupMenu(mContext, view);
MenuInflater inflater = popup.getMenuInflater();
inflater.inflate(R.menu.menu_album, popup.getMenu());
popup.setOnMenuItemClickListener(new MyMenuItemClickListener());
popup.show();
}
/**
* Click listener for popup menu items
*/
class MyMenuItemClickListener implements PopupMenu.OnMenuItemClickListener {
public MyMenuItemClickListener() {
}
@Override
public boolean onMenuItemClick(MenuItem menuItem) {
switch (menuItem.getItemId()) {
case R.id.action_add_favourite:
Toast.makeText(mContext, "Add to favourite", Toast.LENGTH_SHORT).show();
return true;
case R.id.action_play_next:
Toast.makeText(mContext, "Play next", Toast.LENGTH_SHORT).show();
return true;
default:
}
return false;
}
}
@Override
public int getItemCount() {
return albumList.size();
}
}
  1. 打卡main Activity 的布局文件activity_main.xml和content_main 添加AppBarLayout, CollapsingToolbarLayout, Toolbar and RecyclerView.

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/main_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/white"
android:fitsSystemWindows="true">
<android.support.design.widget.AppBarLayout
android:id="@+id/appbar"
android:layout_width="match_parent"
android:layout_height="@dimen/detail_backdrop_height"
android:fitsSystemWindows="true"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">
<android.support.design.widget.CollapsingToolbarLayout
android:id="@+id/collapsing_toolbar"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
app:contentScrim="?attr/colorPrimary"
app:expandedTitleMarginEnd="64dp"
app:expandedTitleMarginStart="48dp"
app:expandedTitleTextAppearance="@android:color/transparent"
app:layout_scrollFlags="scroll|exitUntilCollapsed">
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/backdrop"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
android:scaleType="centerCrop"
app:layout_collapseMode="parallax" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:gravity="center_horizontal"
android:orientation="vertical">
<TextView
android:id="@+id/love_music"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/backdrop_title"
android:textColor="@android:color/white"
android:textSize="@dimen/backdrop_title" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/backdrop_subtitle"
android:textColor="@android:color/white"
android:textSize="@dimen/backdrop_subtitle" />
</LinearLayout>
</RelativeLayout>
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_collapseMode="pin"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light" />
</android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>
<include layout="@layout/content_main" />
</android.support.design.widget.CoordinatorLayout>

content_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/viewBg"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
tools:context="info.androidhive.cardview.MainActivity"
tools:showIn="@layout/activity_main">
<android.support.v7.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clipToPadding="false"
android:scrollbars="vertical" />
</RelativeLayout>

10.最后打开MainActivity.java 做一些必要的修改.

  • initCollapsingToolbar() 在toolbar展开或者合上的时候显示或者隐藏toolbar。
  • prepareAlbums() 添加RecycleView所需要的样本专辑数据。
  • GridLayoutManager 用于将RecyclerView 以网格的方式显示出来。
  • GridSpacingItemDecoration 用于添加RecycleView网格item的空白边界。
  • AlbumsAdapter 创建后将分配给RecycleViewm,RecycleView通过网格的形式将其显示出来。MainActivity.java
    package info.androidhive.cardview;
    import android.content.res.Resources;
    import android.graphics.Rect;
    import android.os.Bundle;
    import android.support.design.widget.AppBarLayout;
    import android.support.design.widget.CollapsingToolbarLayout;
    import android.support.v7.app.AppCompatActivity;
    import android.support.v7.widget.DefaultItemAnimator;
    import android.support.v7.widget.GridLayoutManager;
    import android.support.v7.widget.RecyclerView;
    import android.support.v7.widget.Toolbar;
    import android.util.TypedValue;
    import android.view.View;
    import android.widget.ImageView;
    import com.bumptech.glide.Glide;
    import java.util.ArrayList;
    import java.util.List;
    public class MainActivity extends AppCompatActivity {
    private RecyclerView recyclerView;
    private AlbumsAdapter adapter;
    private List<Album> albumList;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
    setSupportActionBar(toolbar);
    initCollapsingToolbar();
    recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
    albumList = new ArrayList<>();
    adapter = new AlbumsAdapter(this, albumList);
    RecyclerView.LayoutManager mLayoutManager = new GridLayoutManager(this, 2);
    recyclerView.setLayoutManager(mLayoutManager);
    recyclerView.addItemDecoration(new GridSpacingItemDecoration(2, dpToPx(10), true));
    recyclerView.setItemAnimator(new DefaultItemAnimator());
    recyclerView.setAdapter(adapter);
    prepareAlbums();
    try {
    Glide.with(this).load(R.drawable.cover).into((ImageView) findViewById(R.id.backdrop));
    } catch (Exception e) {
    e.printStackTrace();
    }
    }
    /**
    * Initializing collapsing toolbar
    * Will show and hide the toolbar title on scroll
    */
    private void initCollapsingToolbar() {
    final CollapsingToolbarLayout collapsingToolbar =
    (CollapsingToolbarLayout) findViewById(R.id.collapsing_toolbar);
    collapsingToolbar.setTitle(" ");
    AppBarLayout appBarLayout = (AppBarLayout) findViewById(R.id.appbar);
    appBarLayout.setExpanded(true);
    appBarLayout.addOnOffsetChangedListener(new AppBarLayout.OnOffsetChangedListener() {
    boolean isShow = false;
    int scrollRange = -1;
    @Override
    public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) {
    if (scrollRange == -1) {
    scrollRange = appBarLayout.getTotalScrollRange();
    }
    if (scrollRange + verticalOffset == 0) {
    collapsingToolbar.setTitle(getString(R.string.app_name));
    isShow = true;
    } else if (isShow) {
    collapsingToolbar.setTitle(" ");
    isShow = false;
    }
    }
    });
    }
    /**
    * Adding few albums for testing
    */
    private void prepareAlbums() {
    int[] covers = new int[]{
    R.drawable.album1,
    R.drawable.album2,
    R.drawable.album3,
    R.drawable.album4,
    R.drawable.album5,
    R.drawable.album6,
    R.drawable.album7,
    R.drawable.album8,
    R.drawable.album9,
    R.drawable.album10,
    R.drawable.album11};
    Album a = new Album("True Romance", 13, covers[0]);
    albumList.add(a);
    a = new Album("Xscpae", 8, covers[1]);
    albumList.add(a);
    a = new Album("Maroon 5", 11, covers[2]);
    albumList.add(a);
    a = new Album("Born to Die", 12, covers[3]);
    albumList.add(a);
    a = new Album("Honeymoon", 14, covers[4]);
    albumList.add(a);
    a = new Album("I Need a Doctor", 1, covers[5]);
    albumList.add(a);
    a = new Album("Loud", 11, covers[6]);
    albumList.add(a);
    a = new Album("Legend", 14, covers[7]);
    albumList.add(a);
    a = new Album("Hello", 11, covers[8]);
    albumList.add(a);
    a = new Album("Greatest Hits", 17, covers[9]);
    albumList.add(a);
    adapter.notifyDataSetChanged();
    }
    /**
    * RecyclerView item decoration - give equal margin around grid item
    */
    public class GridSpacingItemDecoration extends RecyclerView.ItemDecoration {
    private int spanCount;
    private int spacing;
    private boolean includeEdge;
    public GridSpacingItemDecoration(int spanCount, int spacing, boolean includeEdge) {
    this.spanCount = spanCount;
    this.spacing = spacing;
    this.includeEdge = includeEdge;
    }
    @Override
    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
    int position = parent.getChildAdapterPosition(view); // item position
    int column = position % spanCount; // item column
    if (includeEdge) {
    outRect.left = spacing - column * spacing / spanCount; // spacing - column * ((1f / spanCount) * spacing)
    outRect.right = (column + 1) * spacing / spanCount; // (column + 1) * ((1f / spanCount) * spacing)
    if (position < spanCount) { // top edge
    outRect.top = spacing;
    }
    outRect.bottom = spacing; // item bottom
    } else {
    outRect.left = column * spacing / spanCount; // column * ((1f / spanCount) * spacing)
    outRect.right = spacing - (column + 1) * spacing / spanCount; // spacing - (column + 1) * ((1f / spanCount) * spacing)
    if (position >= spanCount) {
    outRect.top = spacing; // item top
    }
    }
    }
    }

    /**
    * Converting dp to pixel
    */
    private int dpToPx(int dp) {
    Resources r = getResources();
    return Math.round(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, r.getDisplayMetrics()));
    }
    }

适配器应用场景:

适配器常常用在如下场景,比如现在已经有一个已有的功能,但是现在客户端的需求改变了,我们要么重新修改源码来适应新的接口,但是这种方案的缺点是改动较大,原有的代码不能复用,还有一种方案就是使用适配器模式将已有的功能适配成满足最新需求的形式,这样就可以复用已有的功能了,而不是重新实现新的接口,适配器模式主要负责把不兼容的接口转换成客户端期望的样子。
适配器的UML图:

适配器中Taget 和Adaptee是没有什么必然的联系的,两者当中的方法可以各不相同。

一般适配器通常是一个类,它去实现Target接口,然后在适配器的具体实现里面调用Adaptee。而Adaptee就是我们原先已经有的代码。通过这种方式就可以调整已有的代码来满足最近接口Taget的需求了。

类适配器:


就是通过让Adapter 去继承Adaptee,同时实现Target接口来完成适配的。
其实类适配器和对象器本质没有任何区别,只不过是Adapter 类引入Adaptee的方式不一样罢了。具体可以使用继承,构造方法注入,形参方式注入,

public class Adaptee {
public void originalOperation() {
System.out.println("originalOperation");
}
}
public interface Target {
public void targetOperation();
}
public class Adapter implements Target{
private Adaptee adaptee = null;
public Adapter() {
this.adaptee = new Adaptee();
}
public void targetOperation() {
this.adaptee.originalOperation();
}
}
public class Client {
public static void main(String args[]) {
Target target = new Adapter();
target.targetOperation();
}
}

概述

迭代器的关键点在于把对聚合对象的遍历和访问的功能从聚合对象中分离出来,可以在访问一个聚合对象的内容的时候,无须暴露出该聚合对象的内部表示,从而提高聚合对象的封装性,这样不但简化了聚合对象,并且可以让迭代器和聚合对象可以独立变化和发展,从而大大加强系统的灵活性。

在普通的迭代器的实现中还可以添加遍历策略,以及实现双向迭代。

迭代器可以用在如下场景:

不想暴露所要访问的聚合对象的内容。
希望为遍历不同的对象提供一个统一的接口。
迭代器模式把聚合对象和访问聚合的机制实现了分离,通过这种模式可以在迭代器上实现不同的迭代策略。

public interface Iterator {
public void first();
public void next();
public boolean hasnext();
public Object CurrentItem();
}
public class ConcreIterator implements Iterator {
private Aggresive agressive = null;
private int index = -1;
public ConcreIterator(Aggresive agressive) {
this.agressive = agressive;
}
@Override
public void first() {
index = 0;
}
@Override
public void next() {
index++;
}
@Override
public boolean hasnext() {
if(index < this.agressive.size()) {
return true;
}
return false;
}
@Override
public Object CurrentItem() {
return this.agressive.getItem(index);
}
}
public interface Aggresive {
public int size();
public Object getItem(int index);
public Iterator createIterator();
}
public  class ConcreAggressiveArray implements Aggresive {
private int array[];
public ConcreAggressiveArray(int array[]) {
this.array = array;
}

@Override
public int size() {
return this.array.length;
}
@Override
public Object getItem(int index) {
return this.array[index];
}
@Override
public Iterator createIterator() {
return new ConcreIterator(this);
}
}
import java.util.ArrayList;
public class ConcreAggressiveList implements Aggresive {
private ArrayList<Integer> list;
public ConcreAggressiveList(ArrayList<Integer> list) {
this.list = list;
}

@Override
public int size() {
return this.list.size();
}
@Override
public Object getItem(int index) {
return this.list.get(index);
}
@Override
public Iterator createIterator() {
return new ConcreIterator(this);
}
}
import java.util.ArrayList;
public class Client {
public static void main(String args[]) {
int testArray[] = {1,2,3,4,5,5,6,7,7,8,8,9};
ConcreAggressiveArray aggressive = new ConcreAggressiveArray(testArray);
Iterator iterator = aggressive.createIterator();
iterator.first();
while(iterator.hasnext()) {
Object obj = iterator.CurrentItem();
System.out.println("obj = "+obj.toString());
iterator.next();
}
System.out.println("====================================================");
ArrayList<Integer> lists = new ArrayList<>();
lists.add(1);
lists.add(12);
lists.add(13);
lists.add(14);
lists.add(15);
lists.add(16);
lists.add(17);
ConcreAggressiveList list = new ConcreAggressiveList(lists);
Iterator iterators = list.createIterator();
iterators.first();
while(iterators.hasnext()) {
Object obj = iterators.CurrentItem();
System.out.println("obj = "+obj.toString());
iterators.next();
}
}
}

概述

责任链主要应用在如下场景:客户端发出一个请求,很多对象都有机会来处理这个请求,这些能够处理这个请求的对象组成一个责任链,客户发出的请求可以顺着这个责任链传递。
这个责任链是可以动态变化的,也就是客户端请求的处理流程是可以变化的。责任链中的各个处理请求的对象时可以替换的。
在标准的责任链模式中,只要有对象处理了请求,这个请求就不再被处理和传递了。但是也有种变体:每个责任链的对象都对这个请求进行一定功能处理,而不是被处理后就停止,这种变体一般称为功能链。

责任链的组织方式:

责任链中最关键的问题是如何组织这个责任链,一般有如下几种方式:

  1. 在客户端组合责任链,这种称为外部链。
  2. 在Handler类中实现链的组合,这种称为内部链。
  3. 在各个职责对象中,各个职责对象自己决定后续的处理对象。

责任链的创建可以在程序中动态组合,也可以通过数据库或者配置文件来记录组合信息。
每个对象都会按照条件来判断是否属于自己处理的范围,如果是就处理,如果不是就转发请求给下个对象,如果传到最后还是没有被处理就传给默认的处理对象对其进行处理。

在责任链模式中,请求者和接收者之间是一种松散耦合的关系。请求者并不知道接收者是谁,也不知道具体将会如何处理,请求者只是负责向责任链发出请求,而每个处理对象也不管请求者或者是其他的职责对象,只负责处理自己的部分,其他就交给其他的处理对象来处理。
并且责任链是动态的,责任链上的处理对象都是可换的。

public interface Handler {
public void setNext(Handler handler);
public void handleRequest(Request rq);
}
public class HandlerOne implements Handler {
private int HandleCode = 1;
private Handler mNextHandler = null;
public void setNext(Handler handler) {
mNextHandler = handler;

}
public void handleRequest(Request rq) {
if(rq.getRequestCode() == HandleCode) {
System.out.println("This Request has been handle by HandlerOne");
}else {
if(mNextHandler != null) {
mNextHandler.handleRequest(rq);
}
}
}
}
public class HandlerTwo implements Handler {
private int HandleCode = 2;
private Handler mNextHandler = null;
public void setNext(Handler handler) {
mNextHandler = handler;

}
public void handleRequest(Request rq) {
if(rq.getRequestCode() == HandleCode) {
System.out.println("This Request has been handle by HandlerTwo");
}else {
if(mNextHandler != null) {
mNextHandler.handleRequest(rq);
}
}
}
}
public class HandlerThree implements Handler {
private int HandleCode = 3;
private Handler mNextHandler = null;
public void setNext(Handler handler) {
mNextHandler = handler;
}
public void handleRequest(Request rq) {
if(rq.getRequestCode() == HandleCode) {
System.out.println("This Request has been handle by HandlerThree");
}else {
if(mNextHandler != null) {
mNextHandler.handleRequest(rq);
}
}
}
}
public class DefaultHandler implements Handler {
public void setNext(Handler handler) {
throw new UnsupportedOperationException();
}
public void handleRequest(Request rq) {
System.out.println("This Request has been handle by DefaultHandler");
}
}
public class Request {
private int requestCode = -1;
public void setRequestCode(int requestCode) {
this.requestCode = requestCode;
}
public int getRequestCode() {
return requestCode;
}
}
public class Client {
public static void main(String[] args) {
Handler handler1 = new HandlerOne();
Handler handler2 = new HandlerTwo();
Handler handler3 = new HandlerThree();
Handler handler4 = new DefaultHandler();

handler1.setNext(handler2);
handler2.setNext(handler3);
handler3.setNext(handler4);

Request request = new Request();
request.setRequestCode(2);
handler1.handleRequest(request);
}
}

概述

访问者模式是一个个人认为比较绕的设计模式,它有两个比较常用的用途

第一:给某个已有的对象在运行时时期添加某个方法,这个方法就是在Visitor类中实现的方法。
声明我需要添加哪个方法,以及实现这个方法需要谁的帮助。这里Leader 要给老板作报告,但是他不会抓了个雇员从参数里面扔进来。

public interface Visitor {
public void doAsTheBossOrder(Employee me);
}
public class Leader implements Visitor{
public void doAsTheBossOrder(Employee me) {
me.operation1();
me.operation2();
me.operation3();
reportToBoss();
}
public void reportToBoss() {
System.out.println("这是我办的");
}
}
public abstract class Employee {
public abstract void accept(Visitor leader);
public void operation1() {
System.out.println("施展我的技能1");
}
public void operation2() {
System.out.println("施展我的技能2");
}
public void operation3() {
System.out.println("施展我的技能3");
}
}
public class Engeener extends Employee{
public void accept(Visitor leader) {
leader.doAsTheBossOrder(this);
}
}
public class Client {
public static void main(String args[]) {
Employee engeener = new Engeener();
Visitor leader = new Leader();
engeener.accept(leader);
}
}

我们从上面例子可以看出Engeener类并没有doAsTheBossOrder的方法,但是调用engeener.accept(leader)的时候实际上运行的就是doAsTheBossOrder方法,这相当于在运行时的时候Engeener临时添加了一个doAsTheBossOrder方法。这个和装饰模式有存在很大的差异,虽然二者都是通过组合对象来实现的,但是装饰模式是一种静态添加的,添加后装饰类就拥有了这个方法,而访问者模式中是动态添加的,并没有在类代码中实际添加该方法。

遍历不用结构的元素:

public interface Visitor {
public void visit(CommentEmployee employee);
public void visit(Leader leader);
}
public class ConcreVisitor implements Visitor {

public void visit(CommentEmployee employee) {
System.out.println(this.getCommonEmployeeInfo(employee));
}

public void visit(Leader leader) {
System.out.println(this.getLeaderInfo(leader));
}

private String getBasicInfo(Employee employee) {
return "Id :" +employee.getId() + "Name :"+employee.getName()
+"Sex :"+((employee.getSex() == 0)? "MAN":"LAYDY")
+"Salary :" + employee.getSalary();
}

private String getLeaderInfo(Leader leader) {
String basicInfo = this.getBasicInfo(leader);
String otherInfo = "Performance :"+leader.getPerformence();
return basicInfo + otherInfo;
}

private String getCommonEmployeeInfo(CommentEmployee employee) {
String basicInfo = this.getBasicInfo(employee);
String otherInfo = "Job :"+employee.getJob();
return basicInfo + otherInfo;
}
}
public abstract class Employee {

private long id;
private String name;
private int sex;
private int salary;

public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getSex() {
return sex;
}
public void setSex(int sex) {
this.sex = sex;
}
public int getSalary() {
return salary;
}
public void setSalary(int salary) {
this.salary = salary;
}
public abstract void accept(Visitor visitor);
}
public class CommentEmployee extends Employee {
private String job;
public String getJob() {
return job;
}
public void setJob(String job) {
this.job = job;
}
public void accept(Visitor visitor) {
visitor.visit(this);
}
}
public class Leader extends Employee {

private String performence;
public String getPerformence() {
return performence;
}
public void setPerformence(String performence) {
this.performence = performence;
}
public void accept(Visitor visitor) {
visitor.visit(this);
}
}
import java.awt.List;
import java.util.ArrayList;

public class ObjectStruct {

private ArrayList<Employee> memberlist = new ArrayList<Employee>();

public void addMember(Employee employee) {
memberlist.add(employee);
}

public void handleRequest() {
for(Employee em: memberlist) {
Visitor visitor = new ConcreVisitor();
em.accept(visitor);
}
}
}
public class Client {

public static void main(String args[]) {
ObjectStruct objectStruce = new ObjectStruct();
CommentEmployee em1 = new CommentEmployee();
em1.setId(1);
em1.setName("jimmy1");
em1.setSex(0);
em1.setSalary(10000);
em1.setJob("码农");
objectStruce.addMember(em1);

Leader em2 = new Leader();
em2.setId(2);
em2.setName("hello ketty");
em2.setSex(3);
em2.setSalary(40000);
em2.setPerformence("Well done");
objectStruce.addMember(em2);

objectStruce.handleRequest();
}
}

解释器模式这个不是很常用所以不是很熟悉,下面是网上找的一篇文章:
转载自: http://www.cnblogs.com/java-my-life/archive/2012/06/19/2552617.html

概述

在阎宏博士的《JAVA与模式》一书中开头是这样描述解释器(Interpreter)模式的:
解释器模式是类的行为模式。给定一个语言之后,解释器模式可以定义出其文法的一种表示,并同时提供一个解释器。客户端可以使用这个解释器来解释这个语言中的句子。

解释器模式的结构

下面就以一个示意性的系统为例,讨论解释器模式的结构。系统的结构图如下所示:

模式所涉及的角色如下所示:

  • 抽象表达式(Expression)角色:声明一个所有的具体表达式角色都需要实现的抽象接口。这个接口主要是一个interpret()方法,称做解释操作。
  • 终结符表达式(Terminal Expression)角色:实现了抽象表达式角色所要求的接口,主要是一个interpret()方法;文法中的每一个终结符都有一个具体终结表达式与之相对应。比如有一个简单的公式R=R1+R2,在里面R1和R2就是终结符,对应的解析R1和R2的解释器就是终结符表达式。
  • 非终结符表达式(Nonterminal Expression)角色:文法中的每一条规则都需要一个具体的非终结符表达式,非终结符表达式一般是文法中的运算符或者其他关键字,比如公式R=R1+R2中,“+”就是非终结符,解析“+”的解释器就是一个非终结符表达式。
  • 环境(Context)角色:这个角色的任务一般是用来存放文法中各个终结符所对应的具体值,比如R=R1+R2,我们给R1赋值100,给R2赋值200。这些信息需要存放到环境角色中,很多情况下我们使用Map来充当环境角色就足够了。

为了说明解释器模式的实现办法,这里给出一个最简单的文法和对应的解释器模式的实现,这就是模拟Java语言中对布尔表达式进行操作和求值。

在这个语言中终结符是布尔变量,也就是常量true和false。非终结符表达式包含运算符and,or和not等布尔表达式。这个简单的文法如下:

Expression ::= Constant | Variable | Or | And | Not
And     ::= Expression ‘AND’ Expression
Or     ::= Expression ‘OR’ Expression
Not     ::= ‘NOT’ Expression
Variable  ::= 任何标识符
Constant ::= ‘true’ | ‘false’
解释器模式的结构图如下所示:

源代码

抽象表达式角色

public abstract class Expression {
/**
* 以环境为准,本方法解释给定的任何一个表达式
*/public abstract boolean interpret(Context ctx);
/**
* 检验两个表达式在结构上是否相同
*/public abstract boolean equals(Object obj);
/**
* 返回表达式的hash code
*/public abstract int hashCode();
/**
* 将表达式转换成字符串
*/public abstract String toString();
}

一个Constant对象代表一个布尔常量

public class Constant extends Expression{

private boolean value;

public Constant(boolean value){
this.value = value;
}

@Override
public boolean equals(Object obj) {

if(obj != null && obj instanceof Constant){
return this.value == ((Constant)obj).value;
}
return false;
}

@Override
public int hashCode() {
return this.toString().hashCode();
}

@Override
public boolean interpret(Context ctx) {

return value;
}

@Override
public String toString() {
return new Boolean(value).toString();
}

}

一个Variable对象代表一个有名变量

public class Variable extends Expression {

private String name;

public Variable(String name){
this.name = name;
}
@Override
public boolean equals(Object obj) {

if(obj != null && obj instanceof Variable)
{
return this.name.equals(
((Variable)obj).name);
}
return false;
}

@Override
public int hashCode() {
return this.toString().hashCode();
}

@Override
public String toString() {
return name;
}

@Override
public boolean interpret(Context ctx) {
return ctx.lookup(this);
}

}

代表逻辑“与”操作的And类,表示由两个布尔表达式通过逻辑“与”操作给出一个新的布尔表达式的操作

public class And extends Expression {

private Expression left,right;

public And(Expression left , Expression right){
this.left = left;
this.right = right;
}
@Override
public boolean equals(Object obj) {
if(obj != null && obj instanceof And)
{
return left.equals(((And)obj).left) &&
right.equals(((And)obj).right);
}
return false;
}

@Override
public int hashCode() {
return this.toString().hashCode();
}

@Override
public boolean interpret(Context ctx) {

return left.interpret(ctx) && right.interpret(ctx);
}

@Override
public String toString() {
return "(" + left.toString() + " AND " + right.toString() + ")";
}

}

代表逻辑“或”操作的Or类,代表由两个布尔表达式通过逻辑“或”操作给出一个新的布尔表达式的操作

public class Or extends Expression {
private Expression left,right;

public Or(Expression left , Expression right){
this.left = left;
this.right = right;
}
@Override
public boolean equals(Object obj) {
if(obj != null && obj instanceof Or)
{
return this.left.equals(((Or)obj).left) && this.right.equals(((Or)obj).right);
}
return false;
}

@Override
public int hashCode() {
return this.toString().hashCode();
}

@Override
public boolean interpret(Context ctx) {
return left.interpret(ctx) || right.interpret(ctx);
}

@Override
public String toString() {
return "(" + left.toString() + " OR " + right.toString() + ")";
}

}

代表逻辑“非”操作的Not类,代表由一个布尔表达式通过逻辑“非”操作给出一个新的布尔表达式的操作

public class Not extends Expression {

private Expression exp;

public Not(Expression exp){
this.exp = exp;
}
@Override
public boolean equals(Object obj) {
if(obj != null && obj instanceof Not)
{
return exp.equals(
((Not)obj).exp);
}
return false;
}

@Override
public int hashCode() {
return this.toString().hashCode();
}

@Override
public boolean interpret(Context ctx) {
return !exp.interpret(ctx);
}

@Override
public String toString() {
return "(Not " + exp.toString() + ")";
}

}

环境(Context)类定义出从变量到布尔值的一个映射

public class Context {

private Map<Variable,Boolean> map = new HashMap<Variable,Boolean>();

public void assign(Variable var , boolean value){
map.put(var, new Boolean(value));
}

public boolean lookup(Variable var) throws IllegalArgumentException{
Boolean value = map.get(var);
if(value == null){
throw new IllegalArgumentException();
}
return value.booleanValue();
}
}

客户端类

public class Client {

public static void main(String[] args) {
Context ctx = new Context();
Variable x = new Variable("x");
Variable y = new Variable("y");
Constant c = new Constant(true);
ctx.assign(x, false);
ctx.assign(y, true);

Expression exp = new Or(new And(c,x) , new And(y,new Not(x)));
System.out.println("x=" + x.interpret(ctx));
System.out.println("y=" + y.interpret(ctx));
System.out.println(exp.toString() + "=" + exp.interpret(ctx));
}

}

概述

观察者模式是一个非常常见的一个模式,在Android开发中如果说你没遇到我是非常不信的,它是一种一对多的关系,多个对象监听某个目标对象的事件,当目标对象的事件发生的时候,所有监听这个事件的对象都将得到通知,并执行对应的方法。这种模型会把目标对象自身通过方法传递给观察者,这样观察者就可以通过这个引用来获取了。

具体的目标实现对象需要维护观察者的注册信息,最常用的就是通过ArrayList来维护,
在事件发生后更新完所有的状态再执行通知监听对象的动作。

数据传递的两种方式

在观察者模式中数据传递有两种方式:

  • 推模型:
    目标对象主动向观察者推送目标的详细信息,不管观察者是否需要,推送的信息是对象的全部或者部分数据。
  • 拉模型:
    目标对象在通知观察者的时候,只传少量信息,如果观察者需要具体的信息,由观察者主动到目标对象中获取,相当于是观察者从目标对象中拉数据。

监听者需要将自己自身注册到目标实现对象中,并且实现观察者接口。

public interface Observer {
public void update(Subject subject);
}
public class ConcreObserver implements Observer{
@Override
public void update(Subject subject) {
System.out.println("The Subject Status is :" + subject.getStatus());
}
}
import java.util.ArrayList;
public class Subject {
private String mStatus = null;
private ArrayList<Observer> observerlist = new ArrayList<>();
public void registerObserver(Observer observer) {
observerlist.add(observer);
}
public void unregisterObserver(Observer observer) {
observerlist.remove(observer);
}
public String getStatus() {
return mStatus;
}
public void setStatus(String status) {
this.mStatus = status;
for(Observer observer: observerlist) {
observer.update(this);
}
}
}
public class Client {
public static void main(String args[]) {
Observer observer = new ConcreObserver();
Subject subject = new Subject();
subject.registerObserver(observer);
subject.setStatus("new Status");
subject.unregisterObserver(observer);
subject.setStatus("new new Status");
}
}