读书人

Android开源项目-Jamendo音乐播放器研

发布时间: 2012-08-28 12:37:01 作者: rapoo

Android开源项目-Jamendo音乐播放器研究与优化-Adapter相关

【休止符是音乐中无声的节奏进行,恰似此时无声胜有声;而音符是音乐中有声的进行,是唱奏出来的,但相对应的几分音符与几分休止符的时值是相同的】

--- 《五线谱基础教程》


一 自定义Adapter的抽象基类

当Android项目开发中经常会用到ListView、GridView等需要和Adapter配合使用的控件,对于界面界面较多,且用到多个不同布局的ListView等时,自然而然的就会面临需要定义多个Adapter类的情况。

一般为了提高灵活性,我们都会让自定义的Adapter继承自BaseAdapter,并重写其中的四个抽象函数,典型的类结构如下:

public class MyBaseAdapter extends BaseAdapter {@Overridepublic int getCount() {return 0;}@Overridepublic Object getItem(int position) {return null;}@Overridepublic long getItemId(int position) {return 0;}@Overridepublic View getView(int position, View convertView, ViewGroup parent) {return null;}}

但仅用上面的代码是不能实现所需功能的,因为Adapter的本意就是给View提供数据的,因此,需要在上面的代码基础上进一步完善,首先由于数据的类型千变万化,因此采用泛型表示类型;其次,数据一般都会有很多条,因此,需要一个容器来存储数据,这里采用常见的ArrayList;最后,Adapter还需要维护一个到View的引用,并且有可能需要用到Android的上下文Context,在Jamendo这个项目中,View类对应的是ListView,Context就使用ListView所在的Activity,因此,得出下面通用的封装了BaseAdapter的抽象类,其中getView函数留给子类来实现。

public abstract class ArrayListAdapter<T> extends BaseAdapter {protected ArrayList<T> mList; // 数据容器protected Activity mContext; // Android上下文环境protected ListView mListView; // 使用这个Adapter的ListViewpublic ArrayListAdapter(Activity context) {mContext = context;}@Overridepublic int getCount() {if (mList != null) {return mList.size();} else {return 0;}}@Overridepublic Object getItem(int position) {return mList == null ? null : mList.get(position);}@Overridepublic long getItemId(int position) {return position;}// 留给子类实现,因为不同ListView的ListItem布局不一样@Overrideabstract public View getView(int position, View convertView,ViewGroup parent);// 改变了Adapter中的数据,需要刷新ListViewpublic void setList(ArrayList<T> list) {this.mList = list;notifyDataSetChanged();}public void setList(T[] list) {ArrayList<T> arrayList = new ArrayList<T>(list.length);for (T t : list) {arrayList.add(t);}setList(arrayList);}public ArrayList<T> getList() {return mList;}public ListView getListView() {return mListView;}public void setListView(ListView listView) {mListView = listView;}}


二 Jamendo中Adapter的体系及实现


Android开源项目-Jamendo音乐播放器研究与优化-Adapter有关


ArrayListAdapter的子类都是用于ListView的,各个子类实现父类的抽象函数getView,在该函数中实现列表项的布局,并返回列表项对应的视图。本文就不细讲每个Adapter对应的视图,后面分析各个界面时会涉及到,这里只以DownloadJobAdapter作为例子说明ArrayListAdapter的子类的通用实现方式。

如下图所示是下载管理页面,列表中第一项是下载完成后的视图,第二项是正在下载视图,从中可以看出我们的DownloadJobAdapter的getView函数返回的View中起码包含:显示歌曲名称的TextView、显示专辑名称的TextView、表示下载进度的TextView以及一个进度条。


Android开源项目-Jamendo音乐播放器研究与优化-Adapter有关


看DownloadJobAdapter类中定义的静态内部类ViewHolder可以看出,下载页面的列表项确实就是上述四个控件组成:

static class ViewHolder {TextView songName;TextView songArtistAlbum;TextView songProgressText;ProgressBar progressBar;}

getView函数一般都会使用ViewHolder模式来优化性能,避免进行不必要的重复工作。由于Android为我们缓存了convertView,所以首先判断入参ConvertView是否为空,为空说明从来没有创建过,需要创建这个View;否则说明这个是之前构建的View的缓存,由于布局资源不变,对应的控件资源可以复用。而这些控件资源就是使用ViewHolder来存储的,方便使用convertView的setTag函数将它作为一个整体存储在convertView中。

可以注意到,setTag函数还有一个重载的函数,这两个函数定义如下:

public void setTag(final Object tag) {    mTag = tag;}public void setTag(int key, final Object tag) {    // If the package id is 0x00 or 0x01, it's either an undefined package    // or a framework id    if ((key >>> 24) < 2) {        throw new IllegalArgumentException("The key must be an application-specific "                + "resource id.");    }    setTagInternal(this, key, tag);}private static void setTagInternal(View view, int key, Object tag) {    SparseArray<Object> tags = null;    synchronized (sTagsLock) {        if (sTags == null) {            sTags = new WeakHashMap<View, SparseArray<Object>>();        } else {            tags = sTags.get(view);        }    }    if (tags == null) {        tags = new SparseArray<Object>(2);        synchronized (sTagsLock) {            sTags.put(view, tags);        }    }    tags.put(key, tag);}

可以看到,setTag(Object)将对象存在在View类的成员变量mTag中;而setTag(int, Object)则使用WeakHashMap来建立View和要存储的对象之间的弱引用关系。如果需要在View中存放多个对象时,可以使用第二个重载函数,需要注意一点时,setTag(int, Object)中的int类型的参数必须定义在res/values/strings.xml文件中,格式如下:

<resources>    <item type="id" name="wen" />   <item type="id" name="asce" /></resources>

在代码中引用如下:

// 设置tag时convertView.setTag(R.id.wen, "wen1885");convertView.setTag(R.id.asce, "asce1885");...// 获取tag时String wen = convertView.getTag(R.id.wen);String asce = convertView.getTag(R.id.asce);

最后,看下DownloadJobAdapter类的getView函数关键代码如下:

ViewHolder holder = null;if (convertView == null) {LayoutInflater inflater = mContext.getLayoutInflater();convertView = inflater.inflate(R.layout.download_row, null);holder = new ViewHolder();holder.songName = (TextView) convertView.findViewById(R.id.TrackRowName);holder.songArtistAlbum = (TextView) convertView.findViewById(R.id.TrackRowArtistAlbum);holder.songProgressText = (TextView) convertView.findViewById(R.id.TrackRowProgress);holder.progressBar = (ProgressBar) convertView.findViewById(R.id.ProgressBar);// 将控件资源作为整体存放在convertView中convertView.setTag(holder);mContext.registerForContextMenu(convertView);} else {holder = (ViewHolder) convertView.getTag();}



读书人网 >开源软件

热点推荐