,,Android设计模式之适配器(Adapter)模式

,,Android设计模式之适配器(Adapter)模式

本文主要介绍Android设计模式的适配器模式,并通过源代码分析对适配器模式进行分析,有一定的参考价值,感兴趣的朋友可以参考一下。

本文分享了Android适配器模式的源代码,供大家参考。具体情况如下

1. 模式介绍

1.1模式的定义:

适配器模式将一个类的接口转换成客户端期望的另一个接口,这样两个因为接口不匹配而不能协同工作的类就可以协同工作了。

1.2模式的使用场景:

以电源接口为例。笔记本电脑的电源一般接受5V电压,但我们生活中的电线电压一般是220V输出。这时候就出现了不匹配的情况,在软件开发中叫做接口不兼容。这时就需要一个适配器来进行接口转换。软件开发中有一句话正好反映了这一点:任何问题都可以通过增加一个中间层来解决。这一层在这里可以理解为适配器层,通过它进行一次接口转换就可以达到兼容的目的。

2.模式的简单实现

2.1简单实现的介绍:

在上面的电源接口例子中,5V电压是目标接口,220V电压是Adaptee类,将220v电压转换为5V是适配器。

2.2类适配器模式:

/**

*目标角色

*/

公共接口五伏{

public int get volt 5();

}

/**

* Adaptee角色,要转换的对象。

*/

公共类Volt220 {

public int getVolt220() {

返回220;

}

}

//适配器角色

公共类ClassAdapter扩展Volt220实现{

@覆盖

public int getVolt5() {

返回5;

}

}

目标角色给出所需的目标接口,而Adaptee类是需要转换的对象。适配器是将Volt220转换为目标的接口。相应的,Target的目标是获得5V的输出电压,而Adaptee的正常输出电压是220V。这时候我们就需要电源适配器类把220V的电压转换成5V,解决接口不兼容的问题。

公共类测试{

公共静态void main(String[] args) {

class adapter adapter=new class adapter();

System.out.println('输出电压:' adapter . get volt 5());

}

}

2.3.Android源码中的模式实现

像类的适配器模式一样,对象的适配器模式将适配类的API转换成目标类的API。与类的适配器模式不同,对象的适配器模式通过代理而不是继承连接到被适配器类。

从图2中可以看出,Adaptee类(Volt220)没有getVolt5()方法,但是客户端需要这个方法。为了使客户端能够使用Adaptee类,有必要提供一个包装类适配器。这个包装器类包装了Adaptee的一个实例,因此这个包装器类可以将Adaptee的API与目标类的API连接起来。与适配器Adaptee存在委托关系,这决定了适配器模式是object。

/**

*目标角色

*/

公共接口五伏{

public int get volt 5();

}

/**

* Adaptee角色,要转换的对象。

*/

公共类Volt220 {

public int getVolt220() {

返回220;

}

}

//对象适配器模式

公共类ObjectAdapter实现{

Volt220 mVolt220

公共对象适配器(Volt220适配器){

mVolt220=adaptee

}

public int getVolt220() {

返回mvolt 220 . get volt 220();

}

@覆盖

public int getVolt5() {

返回5;

}

}

2.4.类适配器和对象适配器的权衡

*类适配器使用对象继承的方式,这是一种静态定义方式;对象适配器采用对象组合的方式,也就是动态组合的方式。

*对于类适配器,因为适配器直接继承Adaptee,所以不能和Adaptee的子类一起工作,因为继承是静态关系。当适配器继承Adaptee时,不可能处理Adaptee的子类。对于对象适配器,一个适配器可以使许多不同的源适应同一个目标。换句话说,同一个适配器可以使源类及其子类适应目标接口。因为对象适配器采用的是对象组合的关系,只要对象类型正确,是不是子类并不重要。

*对于类适配器,适配器可以重定义Adaptee的一些行为,相当于子类覆盖了父类的一些实现方法。对于对象适配器,很难重新定义Adaptee的行为。在这种情况下,需要定义Adaptee的子类来实现重定义,然后让适配器组合子类。虽然很难重新定义Adaptee的行为,但添加一些新的行为很方便,而且新添加的行为可以同时应用于所有的源。

*对于类适配器,只引入一个对象,不需要额外的引用来间接获取Adaptee。对于对象适配器,需要额外的引用来间接获取Adaptee。

建议尽量使用对象适配器的实现,多组合/聚合,少继承。当然具体问题具体分析,根据需要选择实施,最适合的才是最好的。

3.Android ListView中的Adapter模式

在开发过程中,ListView的适配器是我们最常见的类型之一。的一般用法大致如下:

//适配器

公共类MyAdapter扩展BaseAdapter{

私人LayoutInflater mInflater

ListString mDatas

公共MyAdapter(上下文上下文,列表字符串数据){

this . min flater=layoutinflater . from(上下文);

mDatas=datas

}

@覆盖

public int getCount() {

返回mdatas . size();

}

@覆盖

公共字符串getItem(int pos) {

返回mdatas . get(pos);

}

@覆盖

public long getItemId(int pos) {

退货位置;

}

//解析、设置、缓存convertView及相关内容

@覆盖

公共视图getView(int position,View convertView,ViewGroup parent) {

ViewHolder holder=null

//重用itemview

if (convertView==null) {

holder=new view holder();

convert view=min flater . inflate(r . layout . my _ listview _ item,null);

//获取标题

holder . title=(TextView)convert view . findviewbyid(r . id . title);

convert view . settag(holder);

}否则{

holder=(view holder)convert view . gettag();

}

holder . title . settext(mdatas . get(position));

返回convertView

}

}

这个好像挺麻烦的。看到这里,我们不禁要问,ListView为什么要用适配器模式?

我们知道,作为最重要的视图,ListView需要能够显示各种视图。每个人需要不同的显示效果,显示数据的种类和数量也是千变万化的。那么如何隔离这种变化就显得尤为重要。

Android的做法是增加一个适配器层来应对变化,将ListView需要的接口抽象到Adapter对象中,这样只要用户实现了适配器的接口,ListView就可以根据用户设置的显示效果、数量、数据来显示特定的项目视图。

代理数据集用于通知ListView数据的数量(getCount函数)和每个数据的类型(getItem函数)。最重要的是解决项目视图的输出。项目千变万化,但毕竟都是视图类型。适配器将项目视图统一输出为视图(getView函数),因此可以应对项目视图的可变性。

那么ListView是如何通过适配器模式(不仅仅是适配器模式)工作的呢?我们一起来看看吧。

ListView继承自AbsListView,适配器是在AbsListView中定义的。让我们来看看这个类。

公共抽象类AbsListView扩展AdapterViewListAdapter实现TextWatcher,

ViewTreeObserver。OnGlobalLayoutListener,过滤器。FilterListener,

ViewTreeObserver。OnTouchModeChangeListener,

RemoteViewsAdapter。RemoteAdapterConnectionCallback {

ListAdapter mAdapter

//与窗口关联时调用的函数

@覆盖

受保护的void onAttachedToWindow() {

super . onattachedtowindow();

//代码省略

//为适配器注册一个观察器。这种模式将在下一篇文章中介绍。

如果(mAdapter!=null mDataSetObserver==null) {

mDataSetObserver=new AdapterDataSetObserver();

ma dapter . registerdatasetobserver(mDataSetObserver);

//在我们分离时,数据可能已经更改。刷新。

mDataChanged=true

mOldItemCount=mItemCount

//获取项目的数量,调用的是马达普特的获取计数方法

mitem count=ma dapter。get count();

}

错误连接=真

}

/**

* 子类需要覆写layoutChildren()函数来布局子视图,也就是项目视图

*/

@覆盖

protected void onLayout(boolean changed,int l,int t,int r,int b) {

super.onLayout(已更改,l,t,r,b);

mInLayout=true

如果(已更改){

int子计数=get子计数();

for(int I=0;我数孩子;i ) {

getChildAt(i).强制布局();

}

mrecycler。markchildrendirty();

}

if (mFastScroller!=null mItemCount!=mOldItemCount) {

mfastscroller。onitemcountchanged(模具项目计数,mitem计数);

}

//布局子视图

布局子对象();

mInLayout=false

mOverscrollMax=(b-t)/over scroll _ LIMIT _ DIVISOR;

}

//获取一个项目视图

视图获取视图(int position,boolean[] isScrap) {

ISS crap[0]=false;

查看剪贴簿视图

//从缓存的项目视图中获取,列表视图的复用机制就在这里

废料视图=mrecycler。获取废料视图(位置);

查看孩子;

如果(scrapView!=null) {

//代码省略

孩子=妈妈。获取视图(位置,scrapView,this);

//代码省略

}否则{

孩子=妈妈。获取视图(位置,null,this);

//代码省略

}

返回孩子;

}

}

抽象视图定义了集合视图的框架,比如适配器模式的应用、复用项目视图的逻辑、布局项目视图的逻辑等。子类只需要覆写特定的方法即可实现集合视图的功能,例如列表视图。

列表视图中的相关方法。

@覆盖

受保护的void layoutChildren() {

//代码省略

尝试{

超级棒。布局子对象();

invalidate();

//代码省略

//根据布局模式来布局项目视图

开关(mLayoutMode) {

案例布局_设置_选择:

如果(纽塞尔!=null) {

sel=fillFromSelection(newsel。gettop(),childrenTop,children bottom);

}否则{

sel=fillfromiddle(儿童顶部,儿童底部);

}

打破;

案例布局_同步:

sel=fillSpecific(mSyncPosition,mSpecificTop);

打破;

案例布局_强制_底部:

sel=fillUp(mItemCount - 1,children bottom);

adjustViewsUpOrDown();

打破;

案例布局_FORCE_TOP:

mFirstPosition=0;

sel=fillFromTop(children top);

adjustViewsUpOrDown();

打破;

案例布局_具体:

sel=fill specific(reconcileSelectedPosition(),mSpecificTop);

打破;

案例布局_移动_选择:

sel=moveSelection(oldSel,newSel,delta,childrenTop,children bottom);

打破;

默认值:

//代码省略

打破;

}

}

//从上到下填充项目视图[只是其中一种填充方式]

私有视图填充(int pos,int nextTop) {

视图selectedView=null

int end=(mBottom-mTop);

if((mGroupFlags CLIP _ TO _ PADDING _ MASK)==CLIP _ TO _ PADDING _ MASK){

end-=mlistpadding。底部;

}

while(下一个顶端位置项目计数){

//这是选中的项目吗?

boolean selected=pos==mSelectedPosition;

view child=makeadaddview(pos,nextTop,true,mListPadding.left,selected);

下一个顶部=子。getbottom()mDividerHeight;

如果(选中){

selectedView=child

}

刷卡机

}

返回选定视图

}

//添加项目视图

私有视图makeadaddview(int position,int y,boolean flow,int childrenLeft,

布尔选定){

查看孩子;

//代码省略

//为此位置创建一个新视图,或者如果可能,转换一个未使用的视图

child=obtainView(位置,废话小姐);

//这个需要定位和测量

setupChild(child,position,y,flow,childrenLeft,selected,miss crap[0]);

返回孩子;

}

ListView覆盖AbsListView中的layoutChilden函数,在ABS ListView中,项目视图根据布局模式进行布局。项目视图的数量和样式通过与适配器对应的方法获得。在获得了数量和条目视图后,这些条目视图被布局在ListView对应的坐标上,加上条目视图的重用机制,整个ListView基本上就运作起来了。

当然,这里的适配器不是一个经典的适配器模式,但它是对象适配器模式的一个极好的例子,它也体现了一些面向对象的基本原则。这里目标角色和适配器角色合并在一起,适配器中的方法就是目标方法;Adaptee角色是ListView的数据集和Item View和Adapter的数据集,从而获得数据集的个数和元素。

通过增加一层适配器来抽象项目视图的操作,集合视图如ListView可以获得项目的数量、数据元素、项目视图等。通过Adapter对象,从而达到适应各种数据和各种项目视图的效果。由于项目视图和数据类型千变万化,Android架构师将这些变化的部分交给用户处理,通过getCount、getItem、getView等几种方法进行抽象,即把项目视图的构建过程交给用户处理,灵活运用适配器模式,达到无限适配、拥抱变化的目的。

4.杂谈

优点与缺点

优势

更好的可重用性

系统需要使用现有的类,而这个类的接口不符合系统的需要。然后通过适配器模式可以更好地重用这些功能。

更好的可扩展性

在实现适配器功能时,可以调用自主开发的函数,从而自然地扩展了系统的功能。

劣势

过度使用适配器会让系统非常凌乱,整体难以把握。比如很明显调用了接口A,但实际上内部接口是适配接口b的实现,如果这种情况发生在一个系统上太多,无异于灾难。因此,如果没有必要,可以不使用适配器直接重新配置系统。

这就是本文的全部内容。希望对大家的学习有帮助,支持我们。

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

相关文章阅读

  • windowsandroid手机版下载,windowsandroid安装apk
  • windowsandroid手机版下载,windowsandroid安装apk,WindowsAndroid 安装教程详解
  • android调用webview方法,androidwebview是什么,Android 中 WebView 的基本用法详解
  • android传感器高级编程,Android传感器,Android编程之光线传感器用法详解
  • android.app.Dialog,android自定义dialog对话框,Android开发笔记之-Dialog的使用详解
  • android 图片视频轮播框架,androidlayout轮播图,Android实现炫酷轮播图效果
  • android里的viewpager,安卓自定义view流程,Android自定义引导玩转ViewPager的方法详解
  • android里的viewpager,android viewpager详解
  • android里的viewpager,android viewpager详解,Android自定义超级炫酷的ViewPage指示器
  • android调用webview方法,androidwebview是什么
  • android设置控件宽度,android获取屏幕宽度和高度
  • android设置控件宽度,android获取屏幕宽度和高度,Android中获取控件宽高的4种方法集合
  • android蓝牙开发的基本流程,安卓蓝牙app开发教程
  • android蓝牙开发的基本流程,安卓蓝牙app开发教程,android蓝牙简单开发示例教程
  • android菜单栏,android菜单控件
  • 留言与评论(共有 条评论)
       
    验证码: