有过一定项目开发经验的人们都知道Android里的listView在项目里使用的很频繁。这样我们要定义各式各样重复工作的Adapter,这是很蛋疼的。于是重写Adapter是可以精简项目的代码。
传统的Adapter
主xml文件
<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" > <ListView android:layout_width="match_parent" android:layout_height="match_parent" android:id="@+id/listView"/> </RelativeLayout>
item.xml每个条目
<?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="match_parent" android:orientation="vertical" > <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="14dp" android:singleLine="true" android:id="@+id/idTitle" android:layout_gravity="center" /> <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:textSize="22dp" android:id="@+id/idDesc" /> <LinearLayout android:layout_width="fill_parent" android:layout_height="wrap_content" android:orientation="horizontal" ></LinearLayout> <TextView android:layout_weight="1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="14dp" android:singleLine="true" android:id="@+id/idTime" android:gravity="center" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="14dp" android:singleLine="true" android:id="@+id/idPhone" android:gravity="center" /> </LinearLayout>
java文件
public class Bean {//getset构造函数没写,自己加 String title; String desc; String time; String phone; }
自定义的Adapter
package com.lin.imoocbaseadapter; import java.util.List; import android.content.Context; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.TextView; import com.lin.adapter.bean.Bean; /** * 2015年9月19日下午5:42:02 * Administrator:Elliot */ public class MyAdapter extends BaseAdapter{ private LayoutInflater miInflater; private List<Bean> mDatas; /** * */ public MyAdapter(Context context,List<Bean> mDatas) { // TODO Auto-generated constructor stub miInflater=LayoutInflater.from(context); this.mDatas=mDatas; } @Override public int getCount() { // TODO Auto-generated method stub return mDatas.size(); } @Override public Object getItem(int arg0) { // TODO Auto-generated method stub return mDatas.get(arg0); } @Override public long getItemId(int arg0) { // TODO Auto-generated method stub return arg0; } @Override public View getView(int position, View convertView, ViewGroup parent) { // TODO Auto-generated method stub ViewHolder holder=null; if(convertView==null){//加载布局 convertView=miInflater.inflate(R.layout.item,parent,false ); holder=new ViewHolder(); // holder.mTitle=(TextView) convertView.findViewById(R.id.idTitle); holder.mDesc=(TextView) convertView.findViewById(R.id.idDesc); holder.mTime=(TextView) convertView.findViewById(R.id.idTime); holder.mPhone=(TextView) convertView.findViewById(R.id.idPhone); convertView.setTag(holder); }else{//不再新建holder了 holder=(ViewHolder) convertView.getTag(); } //完成了对holder的创建后,接下来就要给他的属性赋值了 holder.mTitle.setText(mDatas.get(position).getTitle()); holder.mDesc.setText(mDatas.get(position).getDesc()); holder.mTime.setText(mDatas.get(position).getTime()); holder.mPhone.setText(mDatas.get(position).getPhone()); return convertView; } private class ViewHolder{//管理getView()w的类 TextView mTitle; TextView mDesc; TextView mTime; TextView mPhone; } }
主要看getView()方法。当convertView为null时,就新建holder对象,并且setTag记住现在的holder,下次再getView()时就不需要new Holder了。然后在给holder里的属性被view控件赋值,弄后,给view赋值,注意为String类型,否则如果为int类型的话,Android系统会认为你在找R文件的id。
MainActivity
public class MainActivity extends Activity { private ListView listView; private List<Bean> mDatas; private MyAdapter myAdapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initView(); initDatas(); myAdapter=new MyAdapter(this, mDatas); listView.setAdapter(myAdapter); } private void initDatas() { // TODO Auto-generated method stub mDatas=new ArrayList<Bean>(); for(int i=0;i<10;i++){ mDatas.add(new Bean("android学习"+i,"android的路上永无止境"+i,"2015-09-21","13888888888")); } } private void initView() { // TODO Auto-generated method stub listView=(ListView) findViewById(R.id.listView); } }
2、以上就是传统的写法,是不是觉得很不爽,一个项目有多少个实体类啊,要自定义这么多的Adapter,冗余的代码太多了,
《1》、adpter里的控件持有者的内部类Viewholder,可以抽取出来。然后在Adapter里轻松的一句话引用就可以了:(注意:这样做效率和传统的一样,只是为了满足面向对象程序设计的原则:高内聚,低耦合)
难点;怎么抽取了?这是个问题
a、必须要有一个键值对的Map,提供一个整型的id,得到一个view控件。从效率上讲,使用Android提供的
SparseArray<T>来代替。还需要BaseAdapter的getView方法形参的参数,如position,和convertview
代码如下
/** * 2015年9月19日下午6:21:45 * Administrator:Elliot */ public class ViewHolder { private SparseArray<View> mViews; private int mPosition; private View mConvertView; public ViewHolder(Context context,ViewGroup parent,int layoutid,int position) { // TODO Auto-generated constructor stub mPosition=position; mConvertView=LayoutInflater.from(context).inflate(layoutid, parent,false); mConvertView.setTag(this); } //需要一个入口方法,viewHolder是通过构造方法new出来的,还是通过getTag方法得到的 public static ViewHolder get(Context context, View convertView, ViewGroup parent, int layoutid, int position) { if(convertView==null){ return new ViewHolder(context, parent, layoutid, position); }else{ ViewHolder viewHolder=(ViewHolder) convertView.getTag(); viewHolder.mPosition=position; return viewHolder; } } /** * @return the mConvertView,对外提供 */ public View getmConvertView() { return mConvertView; } // public <T extends View> T getView(int viewId){ View view=mViews.get(viewId); if(view==null){ view=mConvertView.findViewById(viewId); mViews.put(viewId, view); } return (T) view; } }
此时的Adapter可以简化一下getView()方法
public View getView(int position, View convertView, ViewGroup parent) { // TODO Auto-generated method stub //精简了 ViewHolder holder=ViewHolder.get(mContext, convertView, parent, R.layout.item, position); //完成了对holder的创建后,接下来就要给他的属性赋值了 TextView tv=holder.getView(R.id.idTitle); TextView tv1=holder.getView(R.id.idDesc); TextView tv2=holder.getView(R.id.idTime); TextView tv3=holder.getView(R.id.idPhone); Bean bean=mDatas.get(position); tv.setText(bean.getTitle()); tv1.setText(bean.getDesc()); tv2.setText(bean.getTime()); tv3.setText(bean.getPhone()); return holder.getmConvertView(); }
是不是简化了一点。把三行代码简化到只有一行了。
但是还不爽,我现在还是BaseAdapter的抽象方法里除了getView()方法之外其它的三个方法,还有构造方法完全可以抽取出来吗。。。
于是呼:我们定义一个抽象类
/** * 2015年9月19日下午6:51:59 * Administrator:Elliot */ public abstract class CommonAdapter<T> extends BaseAdapter { protected Context mContext; protected List<T> mDatas; protected LayoutInflater mInflater; public CommonAdapter(Context mContext,List<T> datas) { // TODO Auto-generated constructor stub this.mContext=mContext; this.mDatas=datas; mInflater=LayoutInflater.from(mContext); } @Override public int getCount() { // TODO Auto-generated method stub return mDatas.size(); } @Override public Object getItem(int position) { // TODO Auto-generated method stub return mDatas.get(position); } @Override public long getItemId(int position) { // TODO Auto-generated method stub return position; } @Override public abstract View getView(int position, View convertView, ViewGroup parent); }
实现了一些抽象的方法,并且通过泛型来传递bean的不同。以后的Adapter不需要继承BaseAdapter了,都继承BaseAdapter的还在CommonAdapter<T>.是不是很酷。。。
结合对Viewholder和BaseAdapter了继承,我们最终的代码如下:
/** * 2015年9月19日下午7:08:16 * Administrator:Elliot */ public class MyAdapterCommon2 extends CommonAdapter<Bean> { /** * @param mContext * @param datas */ public MyAdapterCommon2(Context mContext, List<Bean> datas) { super(mContext, datas); // TODO Auto-generated constructor stub } @Override public View getView(int position, View convertView, ViewGroup parent) { // TODO Auto-generated method stub //精简了 ViewHolder holder=ViewHolder.get(mContext, convertView, parent, R.layout.item, position); //完成了对holder的创建后,接下来就要给他的属性赋值了 TextView tv=holder.getView(R.id.idTitle); TextView tv1=holder.getView(R.id.idDesc); TextView tv2=holder.getView(R.id.idTime); TextView tv3=holder.getView(R.id.idPhone); Bean bean=mDatas.get(position); tv.setText(bean.getTitle()); tv1.setText(bean.getDesc()); tv2.setText(bean.getTime()); tv3.setText(bean.getPhone()); return holder.getmConvertView(); } }
通过这个案例,我们在写代码时一定要具备面向对象编程的思想,灵活地应用。封装继承这些面向对象的优势,写出高质量的代码,可能有时候确实想不到这些特别爽的代码,但是还是要慢慢地向这个方向发展,生活不易,且行且珍惜吧。。。
相关推荐
在Android开发中,ListView是展示大量数据常用的组件之一。它具有高效的滚动性能,可以通过复用View来节省内存。为了使ListView能够正确显示各种不同的数据,我们需要编写一个适配器(Adapter)。本文将深入探讨如何...
在Android开发中,适配器(Adapter)是一个关键组件,它起到了数据源和视图之间的桥梁作用,使得数据显示在ListView、GridView、RecyclerView等组件上。本篇将详细讲解如何构建一个“万能适配器”,以提高代码复用性...
在Android开发中,ListView和GridView是两种常用的列表控件,用于展示大量的数据。它们的核心功能是通过适配器(Adapter)来实现数据与视图之间的绑定。本篇将深入探讨如何打造一个万能的适配器,使得ListView和...
在Android开发中,RecyclerView是一个非常重要的组件,它用于展示可滚动的数据列表,具有高效和灵活的特性。本教程将深入讲解如何为RecyclerView构建一个万能适配器,实现点击事件和点击效果,包括Android 5.0及以上...
在Android开发中,ListView是广泛使用的控件,用于展示大量数据列表。为了提高ListView的性能和用户体验,开发者通常会采用`ViewHolder`模式和自定义`Adapter`,如`CommonAdapter`。本文将深入探讨如何利用这两种...
本文将深入探讨如何使用RecyclerView打造一个万能适配器,以实现自定义类型、ListView效果、GroupView效果,以及如何处理RecyclerView的嵌套问题。 一、RecyclerView基础知识 RecyclerView是一个可滚动的视图网格,...
总结来说,`RecyclerView`万能适配器结合`Databinding`,是Android开发中的高效解决方案,它简化了适配器的实现,使我们能更好地处理复杂的数据展示需求。通过合理利用`Databinding`的特性,我们可以创建出既强大又...
在Android开发中,Adapter是一个非常重要的组件,它用于在数据源和UI组件之间建立桥梁,使得数据能够正确地展示在ListView、GridView等视图控件上。"万能Adapter"通常指的是一个高度可复用、灵活多变的Adapter实现,...
总结起来,“万能的刷新加载控件”是Android开发中一个非常实用的工具,它简化了在多种组件中实现下拉刷新和上拉加载的功能,提高了开发效率,同时也提升了用户体验。通过深入理解其工作原理和使用方法,开发者可以...
在Android开发中,构建一个功能完备的万能播放器是一项复杂但充满挑战的任务,涉及到多媒体处理、用户界面设计以及各种交互功能。本篇文章主要探讨如何利用Vitamio库和Android的UI组件,如Fragment、ViewPager,来...
在Android应用开发中,构建一个万能播放器是常见的需求,尤其当涉及到在线视频播放时。Vitamio是一个强大的库,它为Android提供了多媒体播放的功能支持,包括在线播放和播放列表管理。本文将深入探讨如何利用Vitamio...