`
java-mans
  • 浏览: 11390245 次
文章分类
社区版块
存档分类
最新评论

Android开源代码解读の地图照片应用Panoramio的实现详解(四)

 
阅读更多

本文继续讲解Panoramio的实现,主要介绍ImageAdapter.java和ImageList.java这两个文件,这两个文件实现了如下所示的界面,左图是数据从网络加载过程中,有图是加载完成后的效果:


ImageAdapter继承自BaseAdapter类,实现图片适配器的功能,而ImageList则继承自ListActivity,用于以列表形式显示搜索到的图片信息。介绍之前,先来普及下DataSetObserver和DataSetObservable的知识。

从名字可以依稀猜到,DataSetObserver实现了观察者模式中的观察者角色(Observer)。当数据集发生变化或者变为无效时,DataSetObserver中的方法被回调,典型的数据集有Cursor和Adapter,当某个对象要添加到DataSetObservable中时,这个对象必须从DataSetObserver继承,DataSetObserver是一个抽象类,定义如下:

public abstract class DataSetObserver {
    /**
     * This method is called when the entire data set has changed,
     * most likely through a call to {@link Cursor#requery()} on a {@link Cursor}.
     */
    public void onChanged() {
        // Do nothing
    }

    /**
     * This method is called when the entire data becomes invalid,
     * most likely through a call to {@link Cursor#deactivate()} or {@link Cursor#close()} on a
     * {@link Cursor}.
     */
    public void onInvalidated() {
        // Do nothing
    }
}

而DataSetObservable实现了观察者模式中的对象角色(Subject),它是Observable的具体实现,提供了调用DataSetObserver中各种回调函数的方法,定义如下所示:

public class DataSetObservable extends Observable<DataSetObserver> {
    /**
     * Invokes onChanged on each observer. Called when the data set being observed has
     * changed, and which when read contains the new state of the data.
     */
    public void notifyChanged() {
        synchronized(mObservers) {
            for (DataSetObserver observer : mObservers) {
                observer.onChanged();
            }
        }
    }

    /**
     * Invokes onInvalidated on each observer. Called when the data set being monitored
     * has changed such that it is no longer valid.
     */
    public void notifyInvalidated() {
        synchronized (mObservers) {
            for (DataSetObserver observer : mObservers) {
                observer.onInvalidated();
            }
        }
    }
}

注意这里的Observable是定义在android.database包中的,而不是JDK中的Observable,它的定义如下:

package android.database;

import java.util.ArrayList;

/**
 * Provides methods for (un)registering arbitrary observers in an ArrayList.
 */
public abstract class Observable<T> {
    /**
     * The list of observers.  An observer can be in the list at most
     * once and will never be null.
     */
    protected final ArrayList<T> mObservers = new ArrayList<T>();

    /**
     * Adds an observer to the list. The observer cannot be null and it must not already
     * be registered.
     * @param observer the observer to register
     * @throws IllegalArgumentException the observer is null
     * @throws IllegalStateException the observer is already registered
     */
    public void registerObserver(T observer) {
        if (observer == null) {
            throw new IllegalArgumentException("The observer is null.");
        }
        synchronized(mObservers) {
            if (mObservers.contains(observer)) {
                throw new IllegalStateException("Observer " + observer + " is already registered.");
            }
            mObservers.add(observer);
        }
    }

    /**
     * Removes a previously registered observer. The observer must not be null and it
     * must already have been registered.
     * @param observer the observer to unregister
     * @throws IllegalArgumentException the observer is null
     * @throws IllegalStateException the observer is not yet registered
     */
    public void unregisterObserver(T observer) {
        if (observer == null) {
            throw new IllegalArgumentException("The observer is null.");
        }
        synchronized(mObservers) {
            int index = mObservers.indexOf(observer);
            if (index == -1) {
                throw new IllegalStateException("Observer " + observer + " was not registered.");
            }
            mObservers.remove(index);
        }
    }
    
    /**
     * Remove all registered observer
     */
    public void unregisterAll() {
        synchronized(mObservers) {
            mObservers.clear();
        }        
    }
}

对观察者模式的详细描述,可见这篇文章http://blog.csdn.net/ace1985/article/details/5753658。OK,言归正传,还是来看下我们的ImageAdapter.java,从上面的分析和代码里面的注释应该很好理解了:

package com.google.android.panoramio;

import android.content.Context;
import android.database.DataSetObserver;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;

/**
 * 用来给ImageList绑定图片资源的适配器
 */
public class ImageAdapter extends BaseAdapter {

    /**
     * Maintains the state of our data
     */
    private ImageManager mImageManager;

    private Context mContext;
    
    private MyDataSetObserver mObserver;

    /**
     * ImageManager扮演的是Subject的角色,这个类的实例将被添加到ImagManager类
     * 中的观察者列表中,当ImageList中的数据发生变化时(由ImageManager来检测)
     * ImageManager将通告MyDataSetObserver实例发生的变化
     */
    private class MyDataSetObserver extends DataSetObserver {
        @Override
        public void onChanged() {
        	//BaseAdapter维护了一个DataSetObservable对象mDataSetObservable
        	//这个函数用于通告mDataSetObservable的所有观察者数据发生变化
            notifyDataSetChanged(); 
        }

        @Override
        public void onInvalidated() {
        	//BaseAdapter维护了一个DataSetObservable对象mDataSetObservable
        	//这个函数用于通告mDataSetObservable的所有观察者数据变为无效
            notifyDataSetInvalidated();
        }
    }
    
    public ImageAdapter(Context c) {
        mImageManager = ImageManager.getInstance(c);
        mContext = c;
        mObserver = new MyDataSetObserver();
        
        mImageManager.addObserver(mObserver); //将mObserver设置为mImageManager的观察者
    }

    /**
     * 返回显示的图片的数目
     * 
     * @see android.widget.Adapter#getCount()
     */
    public int getCount() {
        return mImageManager.size();
    }

    /**
     * 返回指定索引的图片
     * 
     * @see android.widget.Adapter#getItem(int)
     */
    public Object getItem(int position) {
        return mImageManager.get(position);
    }

    /**
     * 返回指定索引的图片ID
     * 
     * @see android.widget.Adapter#getItemId(int)
     */
    public long getItemId(int position) {
        PanoramioItem s = mImageManager.get(position);
        return s.getId();
    }

    /**
     * 返回指定索引处用于显示图片的view
     * 
     * @param position 索引
     * @param convertView 可以重用的view,可能为null.
     * @param parent 返回的view的父view.
     * @return 用于显示指定索引处图片的view
     */
    public View getView(int position, View convertView, ViewGroup parent) {
        View view;
        if (convertView == null) {
            // 创建新的view
            LayoutInflater inflater = (LayoutInflater) mContext
                    .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            view = inflater.inflate(R.layout.image_item, null);
        } else {
            // 使用已经存在的view
            view = convertView;
        }
        PanoramioItem s = mImageManager.get(position);

        ImageView i = (ImageView) view.findViewById(R.id.image);
        i.setImageBitmap(s.getBitmap()); //将位图设置到view上
        i.setBackgroundResource(R.drawable.picture_frame); //设置ImageView的背景图片
        
        TextView t = (TextView) view.findViewById(R.id.title);
        t.setText(s.getTitle()); //设置图片名称
        
        t = (TextView) view.findViewById(R.id.owner);
        t.setText(s.getOwner()); //设置图片作者
        return view;
    }

}

同理,ImageList.java文件内容如下所示:

package com.google.android.panoramio;

import android.app.ListActivity;
import android.content.Context;
import android.content.Intent;
import android.database.DataSetObserver;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.Window;
import android.widget.ListView;

/**
 * 显示图片列表的Activity
 */
public class ImageList extends ListActivity {
    
    ImageManager mImageManager;
    
    private MyDataSetObserver mObserver = new MyDataSetObserver();

    /**
     * 保存用户在主界面选取搜索区域时所用的缩放级别
     */
    private int mZoom;

    /**
     * 保存用户在主界面选取的搜索区域的中心点纬度
     */
    private int mLatitudeE6;

    /**
     * 保存用户在主界面选取的搜索区域的中心点经度
     */
    private int mLongitudeE6;

    /**
     * 注册为ImageManager实例的观察者,用于当ImageManager结束图片下载时将ImageList界面上的加载进度显示关闭
     */
    private class MyDataSetObserver extends DataSetObserver {
        @Override
        public void onChanged() {
            if (!mImageManager.isLoading()) {
                getWindow().setFeatureInt(Window.FEATURE_INDETERMINATE_PROGRESS,
                        Window.PROGRESS_VISIBILITY_OFF);
            }
        }

        @Override
        public void onInvalidated() {
        }
    }
    
    @Override
    public void onCreate(Bundle savedInstanceState) {
        requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);//显示不确定进度
        super.onCreate(savedInstanceState);
        
        mImageManager = ImageManager.getInstance(this);
        
        //获取ListView,并在底部添加版权信息
        ListView listView = getListView();
        LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        View footer = inflater.inflate(R.layout.list_footer, listView, false);
        listView.addFooterView(footer, null, false);
        
        //将自定义的ImageAdapter设置给这个ListActivity
        setListAdapter(new ImageAdapter(this));

        //在AndroidManifest.xml文件中为我们的List设置了Theme.Light,这里将背景移除
        listView.setBackgroundDrawable(null);
        //当ImageManager还在下载资源时,显示进度条为忙,并注册观察者用于下载结束时隐藏进度条
        if (mImageManager.isLoading()) {
            getWindow().setFeatureInt(Window.FEATURE_INDETERMINATE_PROGRESS,
                    Window.PROGRESS_VISIBILITY_ON);
            mImageManager.addObserver(mObserver);
        }
        
        //保存从Panoramio主界面传过来的搜索区域相关信息
        Intent i = getIntent();
        mZoom = i.getIntExtra(ImageManager.ZOOM_EXTRA, Integer.MIN_VALUE);
        mLatitudeE6 = i.getIntExtra(ImageManager.LATITUDE_E6_EXTRA, Integer.MIN_VALUE);
        mLongitudeE6 = i.getIntExtra(ImageManager.LONGITUDE_E6_EXTRA, Integer.MIN_VALUE);
    }

    @Override
    protected void onListItemClick(ListView l, View v, int position, long id) {
        PanoramioItem item = mImageManager.get(position);   
        
        //创建Intent用于传递相关数据给ViewImage,用于显示单张图片信息
        Intent i = new Intent(this, ViewImage.class);
        i.putExtra(ImageManager.PANORAMIO_ITEM_EXTRA, item);
        i.putExtra(ImageManager.ZOOM_EXTRA, mZoom);
        i.putExtra(ImageManager.LATITUDE_E6_EXTRA, mLatitudeE6);
        i.putExtra(ImageManager.LONGITUDE_E6_EXTRA, mLongitudeE6);
        startActivity(i);
    }   
    
}


分享到:
评论

相关推荐

    Panoramio Android源码

    Android开源代码解读の地图照片应用Panoramio的实现详解系列的源代码(http://blog.csdn.net/ace1985/article/details/7289040)

    apps-for-android

    •Panoramio的:一个应用程序,显示你附近的照片和兴趣点。 •照片流:一个应用程序,让您从在线照片托管服务查看照片媒体。 •雷达:雷达式的相对位置显示视图,用于Panoramio的(谷歌照片分享服务)等。 •...

    Panoramio.zip_android开发_Java_

    Panoramio example integration project for android

    谷歌地图 delphi 封装库 2013 0.1.9 全面支持google maps api

    一个老外(西班牙)编写的控件,封装了全部google maps api ,使用在DELPHI中使用谷歌地图变得非常简单 GMLib - Google Maps Library Send suggestions to gmlib@cadetill.com Supported Delphi version: Delphi 6...

    Fishmap:带有捕鱼信息的伊利诺伊州湖泊混搭地图

    简而言之,它是 GoogleMaps、Flickr、Panoramio 以及我从我去过的地方和见过的鱼中收集的大量信息的混搭。 目前,Fishmap 包含的数据仅限于伊利诺伊州。 #快速开始如果你只是想看到它运行,你可以查看它: : 如果...

    quentinuk.github.com:网络资料

    网络资料。 可以具有颜色的参数(要显示颜色名称,请单击空白),例如 SVG图片 盖尔语:在给定的单词和页面上指向盖... 将所有给定用户和标签的照片放在地图上。 (Google现在已关闭Panoramio,因此不再起作用。)

    GoogleDesktopSetup

    GoogleDesktopSetup GoogleEarthPluginSetup.exe picasa3-setup.exe 世界照片:http://www.panoramio.com/

    GoogleEarth Pro 6.1.0.5001

    谷歌地图专业版 在“开始”----“运行”里输入: \WINDOWS\system32\drivers\etc 点确定。 后找到:“ hosts ”文件名, 双击打开 hosts , 选择打开方式“记事本”----确定。 在最下面添加复制粘贴内容: 74.125...

    谷歌地球打不开解决方法

    谷歌地球照片打不开解决方法: 开始-----运行----输入:C:WindowsSystem32driversetchosts,用记事本打开, 在里面最后一行添加:72.14.203.101 www.panoramio.com 然后保存。 好多人问,把此绝密方法贡献给大家。

    Wally-开源

    Wally是Qt4墙纸/背景更改器,使用文件,文件夹,FTP远程文件夹,Flickr,Panoramio,Ipernity,Photobucket,Buzznet,Picasa,Smugmug,Google,Vladstudio和deviantART图像等多种来源。

    python计算机视觉编程

    代码示例约定 第2章 局部图像描述子 2.1 harris角点检测器 2.2 sift(尺度不变特征变换) 2.2.1 兴趣点 2.2.2 描述子 2.2.3 检测兴趣点 2.2.4 匹配描述子 2.3 匹配地理标记图像 2.3.1 从...

    Google:trade_mark:的快捷方式「Shortcuts for Google:trade_mark:」-crx插件

     - android开发者控制台  主持人  - 产品的想法  - 公共数据浏览器  - 绿色  - 驾驶  - 应用程序和应用程序仪表板  - 玩店,玩杂志  - 联系人  - 谷歌设置  - 新闻档案  - 网络历史  - 货币换算  - ...

    Headphone-Jack-to-Arduino:通过耳机插Kong和 Arduino 从智能手机触发相机闪光灯

    如果您来这里是为了寻找从 Panoramio 和 Flickr 获取某个位置图片的代码,这是给您的: : 设置 使用 Javascript 和 Web Audio API,从手机上运行的网页发送 50 毫秒长的声音脉冲。 ATtiny85 微处理器正在监听来自...

    FreeImageZoom-crx插件

    这是原始开源HoverZoom扩展的分支。 此扩展名已被删除(它正在使用跟踪,收集用户数据等)。 此扩展程序不会以任何方式跟踪用户的操作。 它唯一需要的权限是访问所有网站上的数据(以提取完整图像),以及*可选*权限...

    iOS-Images-Slideshow:一个图片幻灯片,基于 UIImageView 子类

    iOS-图片-幻灯片基于 ...如何使用特性名称类型描述图片可变数组它表示将在幻灯片上显示的一组图像名称或远程图像 url(例如 google 图像、panoramio 等) 间隔整数幻灯片的计时器间隔(默认 5) 代表ID 类委托(见 L3...

Global site tag (gtag.js) - Google Analytics