Jamendo中大量使用了Adaper,Adaper的继承关系如下图所示:
为了解其设计的过程,将分别沿几条线路分析。
(一) HomeActivity中TitleBar(ImageAdapter)的加载过程,涉及相关Adapter如下图所示:
从服务端获取数据之后,将数据给Gallery,代码如下:
- public void onPostExecute(Album[] albums) {
- if(albums != null && albums.length > 0){
- mViewFlipper.setDisplayedChild(1);
- ImageAdapter albumsAdapter = new ImageAdapter(HomeActivity.this);
- albumsAdapter.setList(albums);
- mGallery.setAdapter(albumsAdapter);
- mGallery.setOnItemClickListener(mGalleryListener);
- mGallery.setSelection(albums.length/2, true); // animate to center
- } else {
- mViewFlipper.setDisplayedChild(2);
- mFailureBar.setOnRetryListener(new OnClickListener(){
- @Override
- public void onClick(View v) {
- new NewsTask().execute((Void)null);
- }
- });
- mFailureBar.setText(R.string.connection_fail);
- }
- super.onPostExecute(albums);
- }
1, 单击setList(),进入ArrayListAdapter中,代码如下:
- public void setList(T[] list){
- ArrayList<T> arrayList = new ArrayList<T>(list.length);
- for (T t : list) {
- arrayList.add(t);
- }
- setList(arrayList);
- }
A,使用了泛型,扩大了此类的使用范围,其继承类复用很多代码。
B, setList()方法重载,先将解析封装好的T[]传进来,再将T[]中每一个元素存入ArrayList中。代码如下:
- public void setList(ArrayList<T> list){
- this.mList = list;
- notifyDataSetChanged();//刷新ui
- }
C, 定义了抽象方法getView()。继承类中只需要实现其即可。经常写adapter就回知道,继承BaseAdapter需要implements四个方法,其中最主要的code内容在getView()方法中完成。在ArrayListAdapter中写一个抽象方法,继承类只需要实现getView方法,并完成其内部的代码即可。如上面的adpter tree diagram所示,ArrayListAdapter有六个子类,简化了代码。
- @Override
- abstract public View getView(int position, View convertView, ViewGroup parent);//抽象方法
D,设置数据之后,即notifyDataSetChanged()刷新。显然是在重新封装成arrayList之后。
- public void setList(ArrayList<T> list){
- this.mList = list;
- notifyDataSetChanged();//刷新ui
- }
E, 此setListView()方法,暂时还没发现有什么用。如果以后遇到,再补充。
2, ImageAdapter的item其实很简单。就一个图片。继承AlbumAdapter,直接重载getView()方法。在内部写实现代码。仅在于简化代码。两者关系并不密切。AlbumAdapter仅比ImageAdapter复杂一点,ImageAdapter中getView()代码如下:
- @Override
- public View getView(int position, View convertView, ViewGroup parent) {
- RemoteImageView i;
- if (convertView == null) {
- i = new RemoteImageView(mContext);
- i.setScaleType(RemoteImageView.ScaleType.FIT_CENTER);
- i.setLayoutParams(new Gallery.LayoutParams(mIconSize, mIconSize));
- } else {
- i = (RemoteImageView) convertView;
- }
- i.setDefaultImage(R.drawable.no_cd);
- i.setImageUrl(mList.get(position).getImage());
- return i;
- }
3, 显然2中,Jamendo自定义了一个RemoteImageView,用来实现图片的下载和显示。
setImageUrl()的代码如下:
- public void setImageUrl(String url){
- // Log.d("img_url", "img_url is :" + url);
- if (mUrl != null && mUrl.equals(url) && (mCurrentlyGrabbedUrl == null ||//1:url赋给全局变量mUrl,两者相等且都为空,但是未执行,所以mCurrentlyGrabbedUrl为空
- (mCurrentlyGrabbedUrl != null && !mCurrentlyGrabbedUrl.equals(url)))) {//2:第n(n>1)次执行时,并未完成downloadTask
- mFailure++;
- if(mFailure > MAX_FAILURES){//超过指定重连次数
- Log.e(JamendoApplication.TAG, "Failed to download "+url+", falling back to default image");
- loadDefaultImage();
- return;
- }
- } else {
- mUrl = url;
- mFailure = 0;
- }
- updateCacheSize();
- if (mCacheSize>0 && (url.contains(ALBUMS) || url.contains(RADIOS))) {//只有两类路径图片需要缓存
- String fileName = convertUrlToFileName(url);
- String dir = getDirectory(fileName);
- Log.d("img_url", "dir is :" + dir);
- String pathFileName = dir + "/" + fileName;
- Log.d("img_url", "pathFileName is :" + pathFileName);
- Bitmap tbmp = BitmapFactory.decodeFile(pathFileName);//从指定文件保存路径解码处图片
- if (tbmp == null) {
- Log.d(JamendoApplication.TAG, "Image is not present, try to download");
- try{
- new DownloadTask().execute(url);
- } catch (RejectedExecutionException e) {
- // do nothing, just don't crash
- }
- } else {
- Log.i(JamendoApplication.TAG, "Loading album cover from file");
- this.setImageBitmap(tbmp);
- updateFileTime(dir,fileName );
- }
- removeAlbumCoversCache(dir, fileName);//对专辑图片的缓存处理:比较大120k
- removeRadioCoversCache(dir, fileName);//对广播图片的缓存处理:比较小8k
- }
- else {
- Log.i(JamendoApplication.TAG, "File not cached supported" + url);
- ImageCache imageCache = JamendoApplication.getInstance()
- .getImageCache();
- if (imageCache.isCached(url)) {
- this.setImageBitmap(imageCache.get(url));
- } else {
- try {
- Log.i(JamendoApplication.TAG, "Image is not present, try to download");
- new DownloadTask().execute(url);
- } catch (RejectedExecutionException e) {
- // do nothing, just don't crash
- }
- }
- }
- }
依照顺序,分析如下:
1st. 重连的判断
指定重连次数,不断请求,大于重连次数,设置为默认图片
2nd. 更新设置中的缓存大小
updateCacheSize();
3rd. 设置图片(先从缓存中找,没有再找SDCard,最后再下载)
缓存的问题将单独写一篇文章
至此:TitleBar的相关Adapter解析完毕。给人印象最深的仍然是面向对象的思想。A: 继承BaseAdapter所实现的4个方法中,3个都基本一样,所以构建父类 ArrayListAdapter。子类.
B: 封装RemoteImageView,可移植性增强。
Adapter的分析先到这里,后面如果发现比较特殊的adpter,会继续补充。