本文分析兩個類:程序中用到的數據類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