频道栏目
首页 > 程序开发 > 移动开发 > Android > 正文
Android开源代码解读の地图照片应用Panoramio的实现详解(二)
2012-02-24 10:24:26           
收藏   我要投稿

本文分析两个类:程序中用到的数据类PanoramioItem,以及工具类BitmapUtils。
 
1)Parcelable接口和PanoramioItem类
 
任何类如果希望自己的实例能够写入到Parcel中或者从Parcel中恢复出来,都必须实现Parcelable接口,实现这个接口的类除了要重写接口中定义的函数,还需要定义一个名为CREATOR的静态域,而CREATOR是实现Parcelable.Creator接口的对象,说了这么多,下面看下Parcelable的代码就一目了然了:
 
 
[java]
 public interface Parcelable {
     /**
      * Flag for use with {@link #writeToParcel}: the object being written
      * is a return value, that is the result of a function such as
      * "<code>Parcelable someFunction()</code>",
      * "<code>void someFunction(out Parcelable)</code>", or
      * "<code>void someFunction(inout Parcelable)</code>".  Some implementations
      * may want to release resources at this point.
      */
     public static final int PARCELABLE_WRITE_RETURN_VALUE = 0x0001;
     
     /**
      * Bit masks for use with {@link #describeContents}: each bit represents a
      * kind of object considered to have potential special significance when
      * marshalled.
      */
     public static final int CONTENTS_FILE_DESCRIPTOR = 0x0001;
     
     /**
      * Describe the kinds of special objects contained in this Parcelable's
      * marshalled representation.
      * 
      * @return a bitmask indicating the set of special object types marshalled
      * by the Parcelable.
      */
     public int describeContents();
     
     /**
      * Flatten this object in to a Parcel.
      *
      * @param dest The Parcel in which the object should be written.
      * @param flags Additional flags about how the object should be written.
      * May be 0 or {@link #PARCELABLE_WRITE_RETURN_VALUE}.
      */
     public void writeToParcel(Parcel dest, int flags);
 
     /**
      * Interface that must be implemented and provided as a public CREATOR
      * field that generates instances of your Parcelable class from a Parcel.
      */
     public interface Creator<T> {
         /**
          * Create a new instance of the Parcelable class, instantiating it
          * from the given Parcel whose data had previously been written by
          * {@link Parcelable#writeToParcel Parcelable.writeToParcel()}.
          *
          * @param source The Parcel to read the object's data from.
          * @return Returns a new instance of the Parcelable class.
          */
         public T createFromParcel(Parcel source);
         
         /**
          * Create a new array of the Parcelable class.
          *
          * @param size Size of the array.
          * @return Returns an array of the Parcelable class, with every entry
          * initialized to null.
          */
         public T[] newArray(int size);
     }
 }
 public interface Parcelable {
     /**
      * Flag for use with {@link #writeToParcel}: the object being written
      * is a return value, that is the result of a function such as
      * "<code>Parcelable someFunction()</code>",
      * "<code>void someFunction(out Parcelable)</code>", or
      * "<code>void someFunction(inout Parcelable)</code>".  Some implementations
      * may want to release resources at this point.
      */
     public static final int PARCELABLE_WRITE_RETURN_VALUE = 0x0001;
   
     /**
      * Bit masks for use with {@link #describeContents}: each bit represents a
      * kind of object considered to have potential special significance when
      * marshalled.
      */
     public static final int CONTENTS_FILE_DESCRIPTOR = 0x0001;
   
     /**
      * Describe the kinds of special objects contained in this Parcelable's
      * marshalled representation.
      *
      * @return a bitmask indicating the set of special object types marshalled
      * by the Parcelable.
      */
     public int describeContents();
   
     /**
      * Flatten this object in to a Parcel.
      *
      * @param dest The Parcel in which the object should be written.
      * @param flags Additional flags about how the object should be written.
      * May be 0 or {@link #PARCELABLE_WRITE_RETURN_VALUE}.
      */
     public void writeToParcel(Parcel dest, int flags);
 
    /**
      * Interface that must be implemented and provided as a public CREATOR
      * field that generates instances of your Parcelable class from a Parcel.
      */
     public interface Creator<T> {
         /**
          * Create a new instance of the Parcelable class, instantiating it
          * from the given Parcel whose data had previously been written by
          * {@link Parcelable#writeToParcel Parcelable.writeToParcel()}.
          *
          * @param source The Parcel to read the object's data from.
          * @return Returns a new instance of the Parcelable class.
          */
         public T createFromParcel(Parcel source);
       
         /**
          * Create a new array of the Parcelable class.
          *
          * @param size Size of the array.
          * @return Returns an array of the Parcelable class, with every entry
          * initialized to null.
          */
         public T[] newArray(int size);
     }
 }
 
接口中的注释已经明确说明各项的作用,下面就是实现了该接口的PanoramioItem类(位于PanoramioItem.java文件中):
 
[java]
 package com.google.android.panoramio;
 
 import com.google.android.maps.GeoPoint;
 
 import android.graphics.Bitmap;
 import android.os.Parcel;
 import android.os.Parcelable;
 
 /**
  * 这个类用于存储从Panoramio服务器返回的数据,包括一个位图和其他相关元数据
  *
  */
 public class PanoramioItem implements Parcelable {
     
     private long mId;       //id标识 
     private Bitmap mBitmap; //位图数据 
     private GeoPoint mLocation; //经纬度 
     private String mTitle; //照片的标题 
     private String mOwner; //照片的作者 
     private String mThumbUrl; //照片缩略图的Url 
     private String mOwnerUrl; //作者信息的Url 
     private String mPhotoUrl; //照片的Url 
     
     public PanoramioItem(Parcel in) {
         mId = in.readLong();
         mBitmap = Bitmap.CREATOR.createFromParcel(in); //位图读取的特殊性 
         mLocation = new GeoPoint(in.readInt(), in.readInt());
         mTitle = in.readString();
         mOwner = in.readString();
         mThumbUrl = in.readString();
         mOwnerUrl = in.readString();
         mPhotoUrl = in.readString();
     }
     
     public PanoramioItem(long id, String thumbUrl, Bitmap b, int latitudeE6, int longitudeE6,
             String title, String owner, String ownerUrl, String photoUrl) {
         mBitmap = b;
         mLocation = new GeoPoint(latitudeE6, longitudeE6);
         mTitle = title;
         mOwner = owner;
         mThumbUrl = thumbUrl;
         mOwnerUrl = ownerUrl;
         mPhotoUrl = photoUrl;
     }
     
     public long getId() {
         return mId;
     }
     
     public Bitmap getBitmap() {
         return mBitmap;
     }
 
     public GeoPoint getLocation() {
         return mLocation;
     }
     
     public String getTitle() {
         return mTitle;
     }
     
     public String getOwner() {
         return mOwner;
     }
     
     public String getThumbUrl() {
         return mThumbUrl;
     }
 
     public String getOwnerUrl() {
         return mOwnerUrl;
     }
 
     public String getPhotoUrl() {
         return mPhotoUrl;
     }
 
     //实现Parcelable接口必须实现的静态变量CREATOR 
     public static final Parcelable.Creator<PanoramioItem> CREATOR =
         new Parcelable.Creator<PanoramioItem>() {
         
         //从Parcel读取数据的顺序和writeToParcel函数写入Parcel的顺序保持一致 
         //此处读取数据在PanoramioItem构造函数中进行 
         public PanoramioItem createFromParcel(Parcel in) {
             return new PanoramioItem(in);
         }
 
         public PanoramioItem[] newArray(int size) {
             return new PanoramioItem[size];
         }
     };
 
     //实现Parcelable接口中的函数 
     public int describeContents() {
         return 0;
     }
 
     //实现Parcelable接口中的函数 
     public void writeToParcel(Parcel parcel, int flags) {
         parcel.writeLong(mId);
         mBitmap.writeToParcel(parcel, 0);
         parcel.writeInt(mLocation.getLatitudeE6());
         parcel.writeInt(mLocation.getLongitudeE6());
         parcel.writeString(mTitle);
         parcel.writeString(mOwner);
         parcel.writeString(mThumbUrl);
         parcel.writeString(mOwnerUrl);
         parcel.writeString(mPhotoUrl);
    }
 }
 package com.google.android.panoramio;
 
import com.google.android.maps.GeoPoint;
 
import android.graphics.Bitmap;
 import android.os.Parcel;
 import android.os.Parcelable;
 
/**
  * 这个类用于存储从Panoramio服务器返回的数据,包括一个位图和其他相关元数据
  *
  */
 public class PanoramioItem implements Parcelable {
   
     private long mId;       //id标识
     private Bitmap mBitmap; //位图数据
     private GeoPoint mLocation; //经纬度
     private String mTitle; //照片的标题
     private String mOwner; //照片的作者
     private String mThumbUrl; //照片缩略图的Url
     private String mOwnerUrl; //作者信息的Url
     private String mPhotoUrl; //照片的Url
   
     public PanoramioItem(Parcel in) {
         mId = in.readLong();
         mBitmap = Bitmap.CREATOR.createFromParcel(in); //位图读取的特殊性
         mLocation = new GeoPoint(in.readInt(), in.readInt());
         mTitle = in.readString();
         mOwner = in.readString();
         mThumbUrl = in.readString();
         mOwnerUrl = in.readString();
         mPhotoUrl = in.readString();
     }
   
     public PanoramioItem(long id, String thumbUrl, Bitmap b, int latitudeE6, int longitudeE6,
             String title, String owner, String ownerUrl, String photoUrl) {
         mBitmap = b;
         mLocation = new GeoPoint(latitudeE6, longitudeE6);
         mTitle = title;
         mOwner = owner;
         mThumbUrl = thumbUrl;
         mOwnerUrl = ownerUrl;
         mPhotoUrl = photoUrl;
     }
   
     public long getId() {
         return mId;
     }
   
     public Bitmap getBitmap() {
         return mBitmap;
     }
 
    public GeoPoint getLocation() {
         return mLocation;
     }
   
     public String getTitle() {
         return mTitle;
     }
   
     public String getOwner() {
         return mOwner;
     }
   
     public String getThumbUrl() {
         return mThumbUrl;
     }
 
    public String getOwnerUrl() {
         return mOwnerUrl;
     }
 
    public String getPhotoUrl() {
         return mPhotoUrl;
     }
 
    //实现Parcelable接口必须实现的静态变量CREATOR
     public static final Parcelable.Creator<PanoramioItem> CREATOR =
         new Parcelable.Creator<PanoramioItem>() {
     
      //从Parcel读取数据的顺序和writeToParcel函数写入Parcel的顺序保持一致
      //此处读取数据在PanoramioItem构造函数中进行
         public PanoramioItem createFromParcel(Parcel in) {
             return new PanoramioItem(in);
         }
 
        public PanoramioItem[] newArray(int size) {
             return new PanoramioItem[size];
         }
     };
 
    //实现Parcelable接口中的函数
     public int describeContents() {
         return 0;
     }
 
    //实现Parcelable接口中的函数
     public void writeToParcel(Parcel parcel, int flags) {
         parcel.writeLong(mId);
         mBitmap.writeToParcel(parcel, 0);
         parcel.writeInt(mLocation.getLatitudeE6());
         parcel.writeInt(mLocation.getLongitudeE6());
         parcel.writeString(mTitle);
         parcel.writeString(mOwner);
         parcel.writeString(mThumbUrl);
         parcel.writeString(mOwnerUrl);
         parcel.writeString(mPhotoUrl);
    }
 }
 
2)BitmapFactory和工具类BitmapUtils
 
BitmapFactory类中提供的生成位图的函数不少,分别从不同数据源获取数据并解码成位图,这些函数的代码如下所示,权当没事多看看:
 
[java]
 /**
  * 从指定字节数组中解码出位图
  */
 public static Bitmap decodeByteArray(byte[] data, int offset, int length, Options opts) {
     if ((offset | length) < 0 || data.length < offset + length) {
         throw new ArrayIndexOutOfBoundsException();
     }
     return nativeDecodeByteArray(data, offset, length, opts);
 }
 
 /**
  * 从指定字节数组中解码出位图
  */
 public static Bitmap decodeByteArray(byte[] data, int offset, int length) {
     return decodeByteArray(data, offset, length, null);
 }
 
 /**
  * 从指定文件路径中解码出位图,如果文件名不存在,则函数返回null
  */
 public static Bitmap decodeFile(String pathName, Options opts) {
     Bitmap bm = null;
     InputStream stream = null;
     try {
         stream = new FileInputStream(pathName);
         bm = decodeStream(stream, null, opts);
     } catch (Exception e) {
         /*  do nothing.
             If the exception happened on open, bm will be null.
         */
     } finally {
         if (stream != null) {
             try {
                 stream.close();
             } catch (IOException e) {
                 // do nothing here 
             }
         }
     }
     return bm;
 }
 
 /**
  * 从指定文件路径中解码出位图,如果文件名不存在,则函数返回null
  */
 public static Bitmap decodeFile(String pathName) {
     return decodeFile(pathName, null);
 }
 
 /**
  * 从指定的文件描述符中解码出位图,失败时函数返回null
  * 当这个函数返回时,文件描述符中的指针位置不会受到影响,因此可以照常使用
  */
 public static Bitmap decodeFileDescriptor(FileDescriptor fd, Rect outPadding, Options opts) {
     try {
         if (MemoryFile.isMemoryFile(fd)) {
             int mappedlength = MemoryFile.getSize(fd);
             MemoryFile file = new MemoryFile(fd, mappedlength, "r");
             InputStream is = file.getInputStream();
             Bitmap bm = decodeStream(is, outPadding, opts);
             return finishDecode(bm, outPadding, opts);
         }
     } catch (IOException ex) {
         // invalid filedescriptor, no need to call nativeDecodeFileDescriptor() 
         return null;
     }
     Bitmap bm = nativeDecodeFileDescriptor(fd, outPadding, opts);
     return finishDecode(bm, outPadding, opts);
 }
 
 /**
  * 从指定的文件描述符中解码出位图,失败时函数返回null
  * 当这个函数返回时,文件描述符中的指针位置不会受到影响,因此可以照常使用
  */
 public static Bitmap decodeFileDescriptor(FileDescriptor fd) {
     return decodeFileDescriptor(fd, null, null);
 }
 
 /**
  * 从指定Resources中解码出位图
  */
 public static Bitmap decodeResource(Resources res, int id, Options opts) {
     Bitmap bm = null;
     InputStream is = null; 
     
     try {
         final TypedValue value = new TypedValue();
         is = res.openRawResource(id, value);
 
         bm = decodeResourceStream(res, value, is, null, opts);
     } catch (Exception e) {
         /*  do nothing.
             If the exception happened on open, bm will be null.
             If it happened on close, bm is still valid.
         */
     } finally {
         try {
             if (is != null) is.close();
         } catch (IOException e) {
             // Ignore 
         }
     }
 
     return bm;
 }
 
 /**
  * 从指定Resources中解码出位图
  */
 public static Bitmap decodeResource(Resources res, int id) {
     return decodeResource(res, id, null);
 }
 
 /**
  * 从InputStream中解码出位图,这个InputStream是从Resources中获取的
  * 仍然将Resources作为参数传入是为了根据Resources信息缩放位图
  */
 public static Bitmap decodeResourceStream(Resources res, TypedValue value,
         InputStream is, Rect pad, Options opts) {
 
     if (opts == null) {
         opts = new Options();
     }
 
     if (opts.inDensity == 0 && value != null) {
         final int density = value.density;
         if (density == TypedValue.DENSITY_DEFAULT) {
             opts.inDensity = DisplayMetrics.DENSITY_DEFAULT;
         } else if (density != TypedValue.DENSITY_NONE) {
             opts.inDensity = density;
         }
     }
     
     if (opts.inTargetDensity == 0 && res != null) {
         opts.inTargetDensity = res.getDisplayMetrics().densityDpi;
     }
     
     return decodeStream(is, pad, opts);
 }
 
 /**
  * 将InputStream解码成位图,如果InputStream是null或者不能用来生成一个位图
  * 则函数返回null,InputStream中流的位置不会受到这个函数的任何影响
  */
 public static Bitmap decodeStream(InputStream is, Rect outPadding, Options opts) {
     // we don't throw in this case, thus allowing the caller to only check 
     // the cache, and not force the image to be decoded. 
     if (is == null) {
         return null;
     }
 
     // we need mark/reset to work properly 
 
     if (!is.markSupported()) {
         is = new BufferedInputStream(is, 16 * 1024);
     }
 
     // so we can call reset() if a given codec gives up after reading up to 
     // this many bytes. FIXME: need to find out from the codecs what this 
     // value should be. 
     is.mark(1024);
 
     Bitmap  bm;
 
     if (is instanceof AssetManager.AssetInputStream) {
         bm = nativeDecodeAsset(((AssetManager.AssetInputStream) is).getAssetInt(),
                 outPadding, opts);
     } else {
         // pass some temp storage down to the native code. 1024 is made up, 
         // but should be large enough to avoid too many small calls back 
         // into is.read(...) This number is not related to the value passed 
         // to mark(...) above. 
         byte [] tempStorage = null;
         if (opts != null) tempStorage = opts.inTempStorage;
         if (tempStorage == null) tempStorage = new byte[16 * 1024];
         bm = nativeDecodeStream(is, tempStorage, outPadding, opts);
     }
 
     return finishDecode(bm, outPadding, opts);
 }
 
 /**
  * 将InputStream解码成位图,如果InputStream是null或者不能用来生成一个位图
  * 则函数返回null,InputStream中流的位置不会受到这个函数的任何影响
  */
 public static Bitmap decodeStream(InputStream is) {
     return decodeStream(is, null, null);
 }
 /**
  * 从指定字节数组中解码出位图
  */
 public static Bitmap decodeByteArray(byte[] data, int offset, int length, Options opts) {
     if ((offset | length) < 0 || data.length < offset + length) {
         throw new ArrayIndexOutOfBoundsException();
     }
     return nativeDecodeByteArray(data, offset, length, opts);
 }
 
/**
  * 从指定字节数组中解码出位图
  */
 public static Bitmap decodeByteArray(byte[] data, int offset, int length) {
     return decodeByteArray(data, offset, length, null);
 }
 
/**
  * 从指定文件路径中解码出位图,如果文件名不存在,则函数返回null
  */
 public static Bitmap decodeFile(String pathName, Options opts) {
     Bitmap bm = null;
     InputStream stream = null;
     try {
         stream = new FileInputStream(pathName);
         bm = decodeStream(stream, null, opts);
     } catch (Exception e) {
         /*  do nothing.
             If the exception happened on open, bm will be null.
         */
     } finally {
         if (stream != null) {
             try {
                 stream.close();
             } catch (IOException e) {
                 // do nothing here
             }
         }
     }
     return bm;
 }
 
/**
  * 从指定文件路径中解码出位图,如果文件名不存在,则函数返回null
  */
 public static Bitmap decodeFile(String pathName) {
     return decodeFile(pathName, null);
 }
 
/**
  * 从指定的文件描述符中解码出位图,失败时函数返回null
  * 当这个函数返回时,文件描述符中的指针位置不会受到影响,因此可以照常使用
  */
 public static Bitmap decodeFileDescriptor(FileDescriptor fd, Rect outPadding, Options opts) {
     try {
         if (MemoryFile.isMemoryFile(fd)) {
             int mappedlength = MemoryFile.getSize(fd);
             MemoryFile file = new MemoryFile(fd, mappedlength, "r");
             InputStream is = file.getInputStream();
             Bitmap bm = decodeStream(is, outPadding, opts);
             return finishDecode(bm, outPadding, opts);
         }
     } catch (IOException ex) {
         // invalid filedescriptor, no need to call nativeDecodeFileDescriptor()
         return null;
     }
     Bitmap bm = nativeDecodeFileDescriptor(fd, outPadding, opts);
     return finishDecode(bm, outPadding, opts);
 }
 
/**
  * 从指定的文件描述符中解码出位图,失败时函数返回null
  * 当这个函数返回时,文件描述符中的指针位置不会受到影响,因此可以照常使用
  */
 public static Bitmap decodeFileDescriptor(FileDescriptor fd) {
     return decodeFileDescriptor(fd, null, null);
 }
 
/**
  * 从指定Resources中解码出位图
  */
 public static Bitmap decodeResource(Resources res, int id, Options opts) {
     Bitmap bm = null;
     InputStream is = null;
   
     try {
         final TypedValue value = new TypedValue();
         is = res.openRawResource(id, value);
 
        bm = decodeResourceStream(res, value, is, null, opts);
     } catch (Exception e) {
         /*  do nothing.
             If the exception happened on open, bm will be null.
             If it happened on close, bm is still valid.
         */
     } finally {
         try {
             if (is != null) is.close();
         } catch (IOException e) {
             // Ignore
         }
     }
 
    return bm;
 }
 
/**
  * 从指定Resources中解码出位图
  */
 public static Bitmap decodeResource(Resources res, int id) {
     return decodeResource(res, id, null);
 }
 
/**
  * 从InputStream中解码出位图,这个InputStream是从Resources中获取的
  * 仍然将Resources作为参数传入是为了根据Resources信息缩放位图
  */
 public static Bitmap decodeResourceStream(Resources res, TypedValue value,
         InputStream is, Rect pad, Options opts) {
 
    if (opts == null) {
         opts = new Options();
     }
 
    if (opts.inDensity == 0 && value != null) {
         final int density = value.density;
         if (density == TypedValue.DENSITY_DEFAULT) {
             opts.inDensity = DisplayMetrics.DENSITY_DEFAULT;
         } else if (density != TypedValue.DENSITY_NONE) {
             opts.inDensity = density;
         }
     }
   
     if (opts.inTargetDensity == 0 && res != null) {
         opts.inTargetDensity = res.getDisplayMetrics().densityDpi;
     }
   
     return decodeStream(is, pad, opts);
 }
 
/**
  * 将InputStream解码成位图,如果InputStream是null或者不能用来生成一个位图
  * 则函数返回null,InputStream中流的位置不会受到这个函数的任何影响
  */
 public static Bitmap decodeStream(InputStream is, Rect outPadding, Options opts) {
     // we don't throw in this case, thus allowing the caller to only check
     // the cache, and not force the image to be decoded.
     if (is == null) {
         return null;
     }
 
    // we need mark/reset to work properly
 
    if (!is.markSupported()) {
         is = new BufferedInputStream(is, 16 * 1024);
     }
 
    // so we can call reset() if a given codec gives up after reading up to
     // this many bytes. FIXME: need to find out from the codecs what this
     // value should be.
     is.mark(1024);
 
    Bitmap  bm;
 
    if (is instanceof AssetManager.AssetInputStream) {
         bm = nativeDecodeAsset(((AssetManager.AssetInputStream) is).getAssetInt(),
                 outPadding, opts);
     } else {
         // pass some temp storage down to the native code. 1024 is made up,
         // but should be large enough to avoid too many small calls back
         // into is.read(...) This number is not related to the value passed
         // to mark(...) above.
         byte [] tempStorage = null;
         if (opts != null) tempStorage = opts.inTempStorage;
         if (tempStorage == null) tempStorage = new byte[16 * 1024];
         bm = nativeDecodeStream(is, tempStorage, outPadding, opts);
     }
 
    return finishDecode(bm, outPadding, opts);
 }
 
/**
  * 将InputStream解码成位图,如果InputStream是null或者不能用来生成一个位图
  * 则函数返回null,InputStream中流的位置不会受到这个函数的任何影响
  */
 public static Bitmap decodeStream(InputStream is) {
     return decodeStream(is, null, null);
 }我们的位图工具类BitmapUtils其实只用到了BitmapFactory.decodeByteArray(...)函数,如下所示,代码比较简单,主要涉及Java IO操作和BitmapFactory的使用(位于文件BitmapUtils.java中)
 
 
[java]
 package com.google.android.panoramio;
 
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
 import android.util.Log;
 
 import java.io.BufferedInputStream;
 import java.io.BufferedOutputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.Closeable;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
 import java.net.URL;
 
 /**
  *  从指定URL加载位图的工具类
  *
  */
 public class BitmapUtils {
     
     private static final String TAG = "Panoramio";
     
     private static final int IO_BUFFER_SIZE = 4 * 1024;
     
     /**
      * 从指定的url加载位图,这将会持续一段时间,因此不应该从UI线程中调用
      */
     public static Bitmap loadBitmap(String url) {
         Bitmap bitmap = null;
         InputStream in = null;
         BufferedOutputStream out = null;
 
         try {
             in = new BufferedInputStream(new URL(url).openStream(), IO_BUFFER_SIZE);
 
             final ByteArrayOutputStream dataStream = new ByteArrayOutputStream();
             out = new BufferedOutputStream(dataStream, IO_BUFFER_SIZE);
             copy(in, out);
             out.flush();
 
             final byte[] data = dataStream.toByteArray();
             //调用BitmapFactory类的函数从字节数组中解码出位图 
             bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
         } catch (IOException e) {
             Log.e(TAG, "Could not load Bitmap from: " + url);
         } finally {
             closeStream(in);
             closeStream(out);
         }
 
         return bitmap;
     }
 
     /**
      * 关闭指定的数据流
      */
     private static void closeStream(Closeable stream) {
         if (stream != null) {
             try {
                 stream.close();
             } catch (IOException e) {
                 android.util.Log.e(TAG, "Could not close stream", e);
             }
         }
     }
 
     /**
      * 使用临时的字节数组缓存将InputStream中的数据拷贝到OutputStream
      */
     private static void copy(InputStream in, OutputStream out) throws IOException {
         byte[] b = new byte[IO_BUFFER_SIZE];
         int read;
         while ((read = in.read(b)) != -1) {
             out.write(b, 0, read);
         }
     }
 
 }
 package com.google.android.panoramio;
 
import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
 import android.util.Log;
 
import java.io.BufferedInputStream;
 import java.io.BufferedOutputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.Closeable;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
 import java.net.URL;
 
/**
  *  从指定URL加载位图的工具类
  *
  */
 public class BitmapUtils {
   
     private static final String TAG = "Panoramio";
   
     private static final int IO_BUFFER_SIZE = 4 * 1024;
   
     /**
      * 从指定的url加载位图,这将会持续一段时间,因此不应该从UI线程中调用
      */
     public static Bitmap loadBitmap(String url) {
         Bitmap bitmap = null;
         InputStream in = null;
         BufferedOutputStream out = null;
 
        try {
             in = new BufferedInputStream(new URL(url).openStream(), IO_BUFFER_SIZE);
 
            final ByteArrayOutputStream dataStream = new ByteArrayOutputStream();
             out = new BufferedOutputStream(dataStream, IO_BUFFER_SIZE);
             copy(in, out);
             out.flush();
 
            final byte[] data = dataStream.toByteArray();
             //调用BitmapFactory类的函数从字节数组中解码出位图
             bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
         } catch (IOException e) {
             Log.e(TAG, "Could not load Bitmap from: " + url);
         } finally {
             closeStream(in);
             closeStream(out);
         }
 
        return bitmap;
     }
 
    /**
      * 关闭指定的数据流
      */
     private static void closeStream(Closeable stream) {
         if (stream != null) {
             try {
                 stream.close();
             } catch (IOException e) {
                 android.util.Log.e(TAG, "Could not close stream", e);
             }
         }
     }
 
    /**
      * 使用临时的字节数组缓存将InputStream中的数据拷贝到OutputStream
      */
     private static void copy(InputStream in, OutputStream out) throws IOException {
         byte[] b = new byte[IO_BUFFER_SIZE];
         int read;
         while ((read = in.read(b)) != -1) {
             out.write(b, 0, read);
         }
     }
 
}==============================碎裂吧 镜花水月===============================
 
 摘自ASCE1885

点击复制链接 与好友分享!回本站首页
相关TAG标签 代码 地图 照片
上一篇:Android开源代码解读の地图照片应用Panoramio的实现详解(一)
下一篇:Android开源代码解读の地图照片应用Panoramio的实现详解(三)
相关文章
图文推荐
点击排行

关于我们 | 联系我们 | 广告服务 | 投资合作 | 版权申明 | 在线帮助 | 网站地图 | 作品发布 | Vip技术培训 | 举报中心

版权所有: 红黑联盟--致力于做实用的IT技术学习网站