Android学习CursorWrapper与Decorator模式 (转至http://www.cnblogs.com/bastard/archive/2012/05/31/2527944.html)

一 Decorator模式


意图:

  动态的给一个对象添加一些额外的职责。就增加功能来说,Decorator模式相比生成子类更为灵活。

  

  动态的给一个对象,而不是对整个类添加额外职责,说明此模式将采用的结构是组合而不是继承;

要给一个对象添加职责,通常可以使用其类的派生类对象替换当前对象,但这显得不够灵活,

继承结构属于静态形式,系统往往并不知道有这样的类存在;

  而我们需要的在某些时刻让对象具有一些额外的职责,额外的职责很可能是来自我们自己的扩展或者某些时刻的特定需求等。

于是通过一种方式对现有的对象进行动态的包装(Wrapper)和进行修饰(Decorator),

  所以如果能够动态的给对象添加某些职责功能将使系统变得更加灵活和具有扩展性。

适用性:

  l 
在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责;

  l  处理那些可以撤销的职责;

  l 
当不适合采用生成子类的方法进行扩充时:一种情况是支持每一种组合将产生大量子类,

    另一种情况是类定义被隐藏无法得知具体的类;

结构:

  

      

理解:

在初次学习Decorator模式的时候,我产生如下疑问:

  我觉得使用Deccorator或许并不好用,Decorator让对象被装饰进行包装,得到的将是一个被装饰后的对象,而已不是对象本身。

虽然可以通过Decorator传递请求,但势必让事情变得更麻烦。故通常我们仍然需要操作的是原对象本身。

这样一来需要维护两个对象……麻烦,Why?

  结果的确是这样:需要通过Decorator传递对原对象的请求,让结构层次变得较深稍微复杂,

如果使用继承(假设让某Commponent继承某Decorator),构造一个更复杂的类,我们就可以直接维护一个对象即可。

  但是使用继承我们实际上需要维护的职责功能没有变,仍然是两个部分:Decorator和Component;

在大多数情况下我们可能根本不需要Decorator而只需要Commponent部分,没能做到在需要时动态添加功能;

  使用Decorator去动态的包装Component,可以做到“即付即用”的方法添加职责,

也可以逐步的个一个简单对象添加职责构造复杂的对象;对象的维护具有层次性:客户端仅仅需要维护Decorator即可,

被装饰的对象交给Decorator来维护即可,还降低了复杂性。

  能做到如此最重要的是:Decorator是一个透明的包装;也就说被包装后的对象和被包装的对象具有一致性,

在使用装饰对象时就像使用原对象一样,而不需要加以区分;故要使Decorator和Component具有一致的接口,

从同一个父类派生下来——保持接口的一致性。

  Decorator是对象的装饰包装,Decorator如果太复杂,有可能破坏Decorator与Component的一致性,

故Decorator尽量保持简单所添加的职责单一。

  所以Decorator要做到:动态的包装对象,添加对象新的职责,保持与原对象一致性;

二 Android中Cursor应用


  Cursor:数据库查询的时候返回的数据集合类型,提供用来访问其中元素的接口;public
interface Cursor {};

      其中提供了很多方法来访问数据库中存储的元素:光标移动和数据获取等;提供了对于数据查询结果处理通用的接口;

  CursorWrapper:public class CursorWrapper
implements Cursor 是对Cursor的一个包装,

    可以看到实现的接口中都是直接对Cursor接口的包装而没有干其他事情,这样看来好像没有什么意义;

    是直接使用Cursor还是使用CursorWrapper没有任何区别;但是CursorWrapper也没有提供任何额外的职责和功能。

  CursorWrapper作用:包装一个Cursor类,代理对一个Cursor对象所有的方法调用;主要的用途就是重写Cursor中某些方法进行扩展。

    所以仅仅是提供这样一个类,使我们可以重写其中某些方法进行扩展的,直接从Cursor继承需要重写所有接口太多没有意义。

  代码中对此使用所见并不多,下面用一个简单的信息排序的例子来学习这种模式。

三 信息对话排序


  有这样一个需求:

    信息中对话主界面的列表显示是根据时间先后来排序的;对于信息量非常大的用户来说,

    有些未读信息可能排在后面查找不是很方便,或者最重要的是:未读信息应排在前,而不应该是按照时间排序。

  信息是以数据库的方式进行存储的,进入信息时,查询返回的结果就是一个Curosr类型的对象,然后去更新显示列表;

  要对此进行排序首先Cursor本身是不具备此功能的,并且Cursor也是只能读不能写的;

要对信息列表排序,数据在Cursor里面不能改变,怎么排序呢?对显示后的ViewItem进行排序,

但是ViewItem是按需创建的也不行;只能对Cursor进行改造了。

  Cursor没有排序的功能那我们就给Cursor增加一个排序共功能的包装;并保证包装后的接口一致;

使其在使用中仍然显示用原来的Cursor一样。

  因此按照信息模块的实现框架,调整后其结构如下:

    

  ——>ConversationList得到查询后的数据类型Cursor,

  ——>创建CursorThreadMsgSort对象将其包装起来,

  ——>再传递给ConversationListAdapter(维护Cursor数据提取)。

  ——>此时的Cursor就是装饰后的对象,添加了排序的职责。

  为什么不使用继承的方式呢?这里可以看到我们从数据库查询得到的是一个Cursor(接口),

而根本不知道具体的类是哪一个;即使知道了也是无法替换的,因为系统提供的是一个通用的数据查询方式,

而排序功能是一个特殊的应用,无法更改;所以只能在使用时动态的进行替换以添加排序的职责。

  下面就是排序的具体实现。

四 对Cursor排序实现

  对Cursor排序不管怎样实现,Cursor是不能够改变的;能改变的是重写其中的方法,光标移动位置等;

而排序本身就是数据比较位置的移动,Cursor位置不能移动,但是只要得到合适的位置数据,就可以实现排序。

  所以我们只要对Cursor建立一张对应的长度和Cursor一致的索引表,表按照规则是经过排序,表中每一项对应的是Cursor中的位置。

在移动光标的时候实际上按照表的对应位置移动即可。

  下面看看具体的实现就比较简单了。

可参考:http://blog.csdn.net/yangzongquan/article/details/6547860 对Cursor排序方法。

信息排序实现代码:  


package com.android.mms.ui;

import android.database.CursorWrapper;
import android.database.Cursor;

import java.util.ArrayList;
import java.util.List;
import android.util.Log;

import java.util.Collections;
import java.util.Comparator;

public class ThreadMsgSortCursor extends CursorWrapper {
private static final String LOGTAG = "xmp_sort_1";

public static final int SORT_BY_TIME = 1;
public static final int SORT_BY_READ = 2;
public static final int SORT_BY_NAME = 3;

private static final int ID = 0;
private static final int DATE = 1;
private static final int RECIPIENT_IDS = 3;
private static final int READ = 6;

private int mSortType ;
private int mPos;

private List<SortEntry> mSortList;
/**
*
* @param cursor
* @param sortType
*/
public ThreadMsgSortCursor(Cursor cursor,int sortType) {
super(cursor);
mSortType = sortType;
mPos = -1;

initSortList();
EexecuteSortList();
}

/**
* 建立与Cursor对应的索引表
*/
protected void initSortList(){
int i = 0;

if(mSortList != null){
mSortList.clear();
}
else{
mSortList = new ArrayList<SortEntry>();
}

while(mCursor.moveToNext()){
SortEntry sortKey = new SortEntry();
sortKey.mNameIds = mCursor.getString(RECIPIENT_IDS);
sortKey.mRead = mCursor.getInt(READ);
sortKey.mDate = mCursor.getLong(DATE);
sortKey.mOrder = i++;

Log.v(LOGTAG,sortKey.toString());
mSortList.add(sortKey);
}
}
/**
* 对表进行排序
*/
protected void EexecuteSortList(){
if(mSortList == null){
return;
}

ComparatorEx comparator = new ComparatorEx();
Collections.sort(mSortList,comparator);

for (int i = 0; i < mSortList.size(); i++) {
Log.v(LOGTAG,mSortList.get(i).toString());
}
}

/**
* 索引表数据
*/
public class SortEntry{
public String mNameIds;
public long mDate;
public int mRead; //保存阅读状态

public int mOrder;
public String toString(){
String strInfo = " mOrder" + mOrder + "---->" +
" mNameIds--> " + mNameIds + " " +
"mDate-->" + mDate + " " +
"mRead-->" + mRead + " ";
return strInfo;
}
}
/**
* 比较
*/
public class ComparatorEx implements Comparator{

@Override
public int compare(Object obj1, Object obj2) {

SortEntry entry1 = (SortEntry)obj1;
SortEntry entry2 = (SortEntry)obj2;
switch (mSortType) {
case SORT_BY_TIME:
return compareByTime(entry1,entry2);
case SORT_BY_READ:
return compareByRead(entry1,entry2);
case SORT_BY_NAME:
return compareByName(entry1,entry2);
default:
return 0;
}
}
/**
* 鎸夐槄璇荤姸鎬佹瘮杈冩帓搴?
* @param entry1
* @param entry2
* @return
*/
protected int compareByRead(SortEntry entry1, SortEntry entry2){

Log.v(LOGTAG,"ComparatorEx------->compareByRead");
if (entry1.mRead >= entry2.mRead){
return 1;
}
else{
return -1;
}
}
protected int compareByName(SortEntry entry1, SortEntry entry2){
return 1;
}
protected int compareByTime(SortEntry entry1, SortEntry entry2){
return 1;
}
}

/**
* 鏍规嵁cursor鐨凱os鑾峰彇涓€涓浉瀵圭殑绱㈠紩琛ㄤ腑瀛樺偍鐨勪綅缃?
* @param position
* @return
*/
protected int getRelativePos(int position){

int relativePos = position;
switch (mSortType) {
case SORT_BY_TIME:
break;
case SORT_BY_READ:
relativePos = mSortList.get(position).mOrder;
break;
case SORT_BY_NAME:
break;
default:
break;
}

//閫氳繃log鏌ョ湅瀵瑰簲鍏崇郴
Log.v(LOGTAG,"ThreadMsgSortCursor-->position-->" + position +
" relativePos --->" + relativePos);
return relativePos;
}
/**
* 浣嶇疆鍙樻崲 鍙栧叾鍦ㄧ储寮曡〃涓搴斾綅缃?
* @param position
* @return
*/
public boolean moveToPosition(int position){
mPos = position;

//鑾峰彇鍚堥€傜殑pos
int order = getRelativePos(position);

return mCursor.moveToPosition(order);
}

public boolean moveToFirst(){
Log.v(LOGTAG,"ThreadMsgSortCursor---------->moveToFirst------");
return moveToPosition(0);
}

public boolean moveToLast(){
Log.v(LOGTAG,"ThreadMsgSortCursor---------->moveToLast------");
return moveToPosition(getCount() - 1);
}

public boolean moveToNext(){
Log.v(LOGTAG,"ThreadMsgSortCursor---------->moveToNext------");
return moveToPosition(mPos + 1);
}

public boolean moveToPrevious(){
Log.v(LOGTAG,"ThreadMsgSortCursor---------->moveToPrevious------");
return moveToPosition(mPos - 1);
}

public boolean move(int offset) {
Log.v(LOGTAG,"ThreadMsgSortCursor---------->move------");
return moveToPosition(mPos + offset);
}

public int getPosition() {
return mPos;
}

@Override
public void close() {
Log.v(LOGTAG,"ThreadMsgSortCursor---------->close------");
mCursor.close();
}
}


package com.android.mms.ui;

import android.database.CursorWrapper;
import android.database.Cursor;

import java.util.ArrayList;
import java.util.List;
import android.util.Log;

import java.util.Collections;
import java.util.Comparator;

public class ThreadMsgSortCursor extends CursorWrapper {
private static final String LOGTAG = "xmp_sort_1";

public static final int SORT_BY_TIME = 1;
public static final int SORT_BY_READ = 2;
public static final int SORT_BY_NAME = 3;

private static final int ID = 0;
private static final int DATE = 1;
private static final int RECIPIENT_IDS = 3;
private static final int READ = 6;

private int mSortType ;
private int mPos;

private List<SortEntry> mSortList;
/**
*
* @param cursor
* @param sortType
*/
public ThreadMsgSortCursor(Cursor cursor,int sortType) {
super(cursor);
mSortType = sortType;
mPos = -1;

initSortList();
EexecuteSortList();
}

/**
* 建立与Cursor对应的索引表
*/
protected void initSortList(){
int i = 0;

if(mSortList != null){
mSortList.clear();
}
else{
mSortList = new ArrayList<SortEntry>();
}

while(mCursor.moveToNext()){
SortEntry sortKey = new SortEntry();
sortKey.mNameIds = mCursor.getString(RECIPIENT_IDS);
sortKey.mRead = mCursor.getInt(READ);
sortKey.mDate = mCursor.getLong(DATE);
sortKey.mOrder = i++;

Log.v(LOGTAG,sortKey.toString());
mSortList.add(sortKey);
}
}
/**
* 对表进行排序
*/
protected void EexecuteSortList(){
if(mSortList == null){
return;
}

ComparatorEx comparator = new ComparatorEx();
Collections.sort(mSortList,comparator);

for (int i = 0; i < mSortList.size(); i++) {
Log.v(LOGTAG,mSortList.get(i).toString());
}
}

/**
* 索引表数据
*/
public class SortEntry{
public String mNameIds;
public long mDate;
public int mRead; //保存阅读状态

public int mOrder;
public String toString(){
String strInfo = " mOrder" + mOrder + "---->" +
" mNameIds--> " + mNameIds + " " +
"mDate-->" + mDate + " " +
"mRead-->" + mRead + " ";
return strInfo;
}
}
/**
* 比较
*/
public class ComparatorEx implements Comparator{

@Override
public int compare(Object obj1, Object obj2) {

SortEntry entry1 = (SortEntry)obj1;
SortEntry entry2 = (SortEntry)obj2;
switch (mSortType) {
case SORT_BY_TIME:
return compareByTime(entry1,entry2);
case SORT_BY_READ:
return compareByRead(entry1,entry2);
case SORT_BY_NAME:
return compareByName(entry1,entry2);
default:
return 0;
}
}
/**
* 鎸夐槄璇荤姸鎬佹瘮杈冩帓搴?
* @param entry1
* @param entry2
* @return
*/
protected int compareByRead(SortEntry entry1, SortEntry entry2){

Log.v(LOGTAG,"ComparatorEx------->compareByRead");
if (entry1.mRead >= entry2.mRead){
return 1;
}
else{
return -1;
}
}
protected int compareByName(SortEntry entry1, SortEntry entry2){
return 1;
}
protected int compareByTime(SortEntry entry1, SortEntry entry2){
return 1;
}
}

/**
* 鏍规嵁cursor鐨凱os鑾峰彇涓€涓浉瀵圭殑绱㈠紩琛ㄤ腑瀛樺偍鐨勪綅缃?
* @param position
* @return
*/
protected int getRelativePos(int position){

int relativePos = position;
switch (mSortType) {
case SORT_BY_TIME:
break;
case SORT_BY_READ:
relativePos = mSortList.get(position).mOrder;
break;
case SORT_BY_NAME:
break;
default:
break;
}

//閫氳繃log鏌ョ湅瀵瑰簲鍏崇郴
Log.v(LOGTAG,"ThreadMsgSortCursor-->position-->" + position +
" relativePos --->" + relativePos);
return relativePos;
}
/**
* 浣嶇疆鍙樻崲 鍙栧叾鍦ㄧ储寮曡〃涓搴斾綅缃?
* @param position
* @return
*/
public boolean moveToPosition(int position){
mPos = position;

//鑾峰彇鍚堥€傜殑pos
int order = getRelativePos(position);

return mCursor.moveToPosition(order);
}

public boolean moveToFirst(){
Log.v(LOGTAG,"ThreadMsgSortCursor---------->moveToFirst------");
return moveToPosition(0);
}

public boolean moveToLast(){
Log.v(LOGTAG,"ThreadMsgSortCursor---------->moveToLast------");
return moveToPosition(getCount() - 1);
}

public boolean moveToNext(){
Log.v(LOGTAG,"ThreadMsgSortCursor---------->moveToNext------");
return moveToPosition(mPos + 1);
}

public boolean moveToPrevious(){
Log.v(LOGTAG,"ThreadMsgSortCursor---------->moveToPrevious------");
return moveToPosition(mPos - 1);
}

public boolean move(int offset) {
Log.v(LOGTAG,"ThreadMsgSortCursor---------->move------");
return moveToPosition(mPos + offset);
}

public int getPosition() {
return mPos;
}

@Override
public void close() {
Log.v(LOGTAG,"ThreadMsgSortCursor---------->close------");
mCursor.close();
}
}

Android学习CursorWrapper与Decorator模式
(转至http://www.cnblogs.com/bastard/archive/2012/05/31/2527944.html)

时间: 2024-11-15 16:01:50

Android学习CursorWrapper与Decorator模式 (转至http://www.cnblogs.com/bastard/archive/2012/05/31/2527944.html)的相关文章

Android学习CursorWrapper与Decorator模式

Android学习CursorWrapper与Decorator模式 - Dufresne - 博客园 一 Decorator模式 意图: 动态的给一个对象添加一些额外的职责.就增加功能来说,Decorator模式相比生成子类更为灵活. 动态的给一个对象,而不是对整个类添加额外职责,说明此模式将采用的结构是组合而不是继承: 要给一个对象添加职责,通常可以使用其类的派生类对象替换当前对象,但这显得不够灵活, 继承结构属于静态形式,系统往往并不知道有这样的类存在: 而我们需要的在某些时刻让对象具有一

Android实现下拉导航选择菜单效果【转载地址:http://www.cnblogs.com/hanyonglu/archive/2012/07/31/2617488.html】

本文介绍在Android中如何实现下拉导航选择菜单效果.   关于下拉导航选择菜单效果在新闻客户端中用的比较多,当然也可以用在其他的项目中,这样可以很方便的选择更多的菜单.我们可以让我们的应用顶部有左右滑动或进行切换的导航菜单,也可以为了增强用户体验在应用中添加这样的下拉导航选择菜单效果. 关于它的实现原理,其实也是挺简单的,就是使用PopupWindow来进行展现,在显示时控制其高度并配置以相应的动画效果.在PopupWindow中我使用GridView来控制里面的菜单项,每个菜单项对应相应的

Android学习——ActivityManager与Proxy模式的运用

Android学习--ActivityManager与Proxy模式的运用 - Dufresne - 博客园 一 Proxy模式 意图: ?????? 为其他对象提供一种代理以控制这个对象的访问. 适用性: l? 远程代理( Remote Proxy ): 为一个对象在不同的地址空间提供局部代表. l? 虚代理(Virtual Proxy)根据需要创建开销很大的对象.使用一个代理对象作为代表,在真正的需要时进行创建. l? 保护代理(Protection Proxy):控制对原始对象的访问.保护

Android实现推送方式解决方案【转载地址:http://www.cnblogs.com/hanyonglu/archive/2012/03/04/2378971.html】

本文介绍在Android中实现推送方式的基础知识及相关解决方案.推送功能在手机开发中应用的场景是越来起来了,不说别的,就我们手机上的新闻客户端就时不j时的推送过来新的消息,很方便的阅读最新的新闻信息.这种推送功能是好的一面,但是也会经常看到很多推送过来的垃圾信息,这就让我们感到厌烦了,关于这个我们就不能多说什么了,毕竟很多商家要做广告.本文就是来探讨下Android中实现推送功能的一些解决方案,也希望能够起到抛砖引玉的作用.^_^ 1.推送方式基础知识:  在移动互联网时代以前的手机,如果有事情

爬虫基础学习 转【http://www.cnblogs.com/huangxincheng/archive/2012/11/08/2759752.html】

这一篇我们聊聊在页面抓取时应该注意到的几个问题. 一:网页更新 我们知道,一般网页中的信息是不断翻新的,这也要求我们定期的去抓这些新信息,但是这个“定期”该怎么理解,也就是多长时间需要 抓一次该页面,其实这个定期也就是页面缓存时间,在页面的缓存时间内我们再次抓取该网页是没有必要的,反而给人家服务器造成压力. 就比如说我要抓取博客园首页,首先清空页面缓存, 从Last-Modified到Expires,我们可以看到,博客园的缓存时间是2分钟,而且我还能看到当前的服务器时间Date,如果我再次 刷新

Android学习笔记——Activity的启动和创建

http://www.cnblogs.com/bastard/archive/2012/04/07/2436262.html Android Activity学习笔记--Activity的启动和创建 最近学习Android相关知识,感觉仅仅了解Activity几个生命周期函数基本上没有任何意义的: 于是想深入了解一下Activity到底是怎么一回事怎么运行来的:里面的东东真是叫个庞大: 现在只能简单的了解其框架性的概念和流程: 一 Activity概念 Android的核心不是Applicati

Android学习Scroller(四)——实现拉动后回弹的布局

MainActivity如下: package cc.testscroller2; import android.os.Bundle; import android.app.Activity; /** * Demo描述: * 实现可以拉动后回弹的布局. * 类似于下拉刷新的. * * 参考资料: * 1 http://gundumw100.iteye.com/blog/1884373 * 2 http://blog.csdn.net/gemmem/article/details/7321910

Android学习Scroller(三)

MainActivity如下: package cc.testscroller2; import android.os.Bundle; import android.app.Activity; /** * Demo描述: * 实现可以拉动后回弹的布局. * 类似于下拉刷新的. * * 参考资料: * 1 http://gundumw100.iteye.com/blog/1884373 * 2 http://blog.csdn.net/gemmem/article/details/7321910

Android学习Scroller(二)

MainActivity如下: package cc.testscroller1; import android.app.Activity; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.os.Bundle; import android.view.View; import android.view.View.OnClick