Android開原始碼解讀の地圖照片應用Panoramio的實現詳解(二)

來源:互聯網
上載者:User

本文分析兩個類:程式中用到的資料類PanoramioItem,以及工具類BitmapUtils。

1)Parcelable介面和PanoramioItem類

任何類如果希望自己的執行個體能夠寫入到Parcel中或者從Parcel中恢複出來,都必須實現Parcelable介面,實現這個介面的類除了要重寫介面中定義的函數,還需要定義一個名為CREATOR的靜態域,而CREATOR是實現Parcelable.Creator介面的對象,說了這麼多,下面看下Parcelable的代碼就一目瞭然了:

public interface Parcelable {<br /> /**<br /> * Flag for use with {@link #writeToParcel}: the object being written<br /> * is a return value, that is the result of a function such as<br /> * "<code>Parcelable someFunction()</code>",<br /> * "<code>void someFunction(out Parcelable)</code>", or<br /> * "<code>void someFunction(inout Parcelable)</code>". Some implementations<br /> * may want to release resources at this point.<br /> */<br /> public static final int PARCELABLE_WRITE_RETURN_VALUE = 0x0001;</p><p> /**<br /> * Bit masks for use with {@link #describeContents}: each bit represents a<br /> * kind of object considered to have potential special significance when<br /> * marshalled.<br /> */<br /> public static final int CONTENTS_FILE_DESCRIPTOR = 0x0001;</p><p> /**<br /> * Describe the kinds of special objects contained in this Parcelable's<br /> * marshalled representation.<br /> *<br /> * @return a bitmask indicating the set of special object types marshalled<br /> * by the Parcelable.<br /> */<br /> public int describeContents();</p><p> /**<br /> * Flatten this object in to a Parcel.<br /> *<br /> * @param dest The Parcel in which the object should be written.<br /> * @param flags Additional flags about how the object should be written.<br /> * May be 0 or {@link #PARCELABLE_WRITE_RETURN_VALUE}.<br /> */<br /> public void writeToParcel(Parcel dest, int flags);</p><p> /**<br /> * Interface that must be implemented and provided as a public CREATOR<br /> * field that generates instances of your Parcelable class from a Parcel.<br /> */<br /> public interface Creator<T> {<br /> /**<br /> * Create a new instance of the Parcelable class, instantiating it<br /> * from the given Parcel whose data had previously been written by<br /> * {@link Parcelable#writeToParcel Parcelable.writeToParcel()}.<br /> *<br /> * @param source The Parcel to read the object's data from.<br /> * @return Returns a new instance of the Parcelable class.<br /> */<br /> public T createFromParcel(Parcel source);</p><p> /**<br /> * Create a new array of the Parcelable class.<br /> *<br /> * @param size Size of the array.<br /> * @return Returns an array of the Parcelable class, with every entry<br /> * initialized to null.<br /> */<br /> public T[] newArray(int size);<br /> }<br />}

介面中的注釋已經明確說明各項的作用,下面就是實現了該介面的PanoramioItem類(位於PanoramioItem.java檔案中):

package com.google.android.panoramio;</p><p>import com.google.android.maps.GeoPoint;</p><p>import android.graphics.Bitmap;<br />import android.os.Parcel;<br />import android.os.Parcelable;</p><p>/**<br /> * 這個類用於儲存從Panoramio伺服器返回的資料,包括一個位元影像和其他相關中繼資料<br /> *<br /> */<br />public class PanoramioItem implements Parcelable {</p><p> private long mId; //id標識<br /> private Bitmap mBitmap; //位元影像資料<br /> private GeoPoint mLocation; //經緯度<br /> private String mTitle; //照片的標題<br /> private String mOwner; //照片的作者<br /> private String mThumbUrl; //照片縮圖的Url<br /> private String mOwnerUrl; //作者資訊的Url<br /> private String mPhotoUrl; //照片的Url</p><p> public PanoramioItem(Parcel in) {<br /> mId = in.readLong();<br /> mBitmap = Bitmap.CREATOR.createFromParcel(in); //位元影像讀取的特殊性<br /> mLocation = new GeoPoint(in.readInt(), in.readInt());<br /> mTitle = in.readString();<br /> mOwner = in.readString();<br /> mThumbUrl = in.readString();<br /> mOwnerUrl = in.readString();<br /> mPhotoUrl = in.readString();<br /> }</p><p> public PanoramioItem(long id, String thumbUrl, Bitmap b, int latitudeE6, int longitudeE6,<br /> String title, String owner, String ownerUrl, String photoUrl) {<br /> mBitmap = b;<br /> mLocation = new GeoPoint(latitudeE6, longitudeE6);<br /> mTitle = title;<br /> mOwner = owner;<br /> mThumbUrl = thumbUrl;<br /> mOwnerUrl = ownerUrl;<br /> mPhotoUrl = photoUrl;<br /> }</p><p> public long getId() {<br /> return mId;<br /> }</p><p> public Bitmap getBitmap() {<br /> return mBitmap;<br /> }</p><p> public GeoPoint getLocation() {<br /> return mLocation;<br /> }</p><p> public String getTitle() {<br /> return mTitle;<br /> }</p><p> public String getOwner() {<br /> return mOwner;<br /> }</p><p> public String getThumbUrl() {<br /> return mThumbUrl;<br /> }</p><p> public String getOwnerUrl() {<br /> return mOwnerUrl;<br /> }</p><p> public String getPhotoUrl() {<br /> return mPhotoUrl;<br /> }</p><p> //實現Parcelable介面必須實現的靜態變數CREATOR<br /> public static final Parcelable.Creator<PanoramioItem> CREATOR =<br /> new Parcelable.Creator<PanoramioItem>() {</p><p> //從Parcel讀取資料的順序和writeToParcel函數寫入Parcel的順序保持一致<br /> //此處讀取資料在PanoramioItem建構函式中進行<br /> public PanoramioItem createFromParcel(Parcel in) {<br /> return new PanoramioItem(in);<br /> }</p><p> public PanoramioItem[] newArray(int size) {<br /> return new PanoramioItem[size];<br /> }<br /> };</p><p> //實現Parcelable介面中的函數<br /> public int describeContents() {<br /> return 0;<br /> }</p><p> //實現Parcelable介面中的函數<br /> public void writeToParcel(Parcel parcel, int flags) {<br /> parcel.writeLong(mId);<br /> mBitmap.writeToParcel(parcel, 0);<br /> parcel.writeInt(mLocation.getLatitudeE6());<br /> parcel.writeInt(mLocation.getLongitudeE6());<br /> parcel.writeString(mTitle);<br /> parcel.writeString(mOwner);<br /> parcel.writeString(mThumbUrl);<br /> parcel.writeString(mOwnerUrl);<br /> parcel.writeString(mPhotoUrl);<br /> }<br />}

2)BitmapFactory和工具類BitmapUtils

BitmapFactory類中提供的產生位元影像的函數不少,分別從不同資料來源擷取資料並解碼成位元影像,這些函數的代碼如下所示,權當沒事多看看:

/**<br /> * 從指定位元組數組中解碼出位元影像<br /> */<br />public static Bitmap decodeByteArray(byte[] data, int offset, int length, Options opts) {<br /> if ((offset | length) < 0 || data.length < offset + length) {<br /> throw new ArrayIndexOutOfBoundsException();<br /> }<br /> return nativeDecodeByteArray(data, offset, length, opts);<br />}</p><p>/**<br /> * 從指定位元組數組中解碼出位元影像<br /> */<br />public static Bitmap decodeByteArray(byte[] data, int offset, int length) {<br /> return decodeByteArray(data, offset, length, null);<br />}</p><p>/**<br /> * 從指定檔案路徑中解碼出位元影像,如果檔案名稱不存在,則函數返回null<br /> */<br />public static Bitmap decodeFile(String pathName, Options opts) {<br /> Bitmap bm = null;<br /> InputStream stream = null;<br /> try {<br /> stream = new FileInputStream(pathName);<br /> bm = decodeStream(stream, null, opts);<br /> } catch (Exception e) {<br /> /* do nothing.<br /> If the exception happened on open, bm will be null.<br /> */<br /> } finally {<br /> if (stream != null) {<br /> try {<br /> stream.close();<br /> } catch (IOException e) {<br /> // do nothing here<br /> }<br /> }<br /> }<br /> return bm;<br />}</p><p>/**<br /> * 從指定檔案路徑中解碼出位元影像,如果檔案名稱不存在,則函數返回null<br /> */<br />public static Bitmap decodeFile(String pathName) {<br /> return decodeFile(pathName, null);<br />}</p><p>/**<br /> * 從指定的檔案描述符中解碼出位元影像,失敗時函數返回null<br /> * 當這個函數返回時,檔案描述符中的指標位置不會受到影響,因此可以照常使用<br /> */<br />public static Bitmap decodeFileDescriptor(FileDescriptor fd, Rect outPadding, Options opts) {<br /> try {<br /> if (MemoryFile.isMemoryFile(fd)) {<br /> int mappedlength = MemoryFile.getSize(fd);<br /> MemoryFile file = new MemoryFile(fd, mappedlength, "r");<br /> InputStream is = file.getInputStream();<br /> Bitmap bm = decodeStream(is, outPadding, opts);<br /> return finishDecode(bm, outPadding, opts);<br /> }<br /> } catch (IOException ex) {<br /> // invalid filedescriptor, no need to call nativeDecodeFileDescriptor()<br /> return null;<br /> }<br /> Bitmap bm = nativeDecodeFileDescriptor(fd, outPadding, opts);<br /> return finishDecode(bm, outPadding, opts);<br />}</p><p>/**<br /> * 從指定的檔案描述符中解碼出位元影像,失敗時函數返回null<br /> * 當這個函數返回時,檔案描述符中的指標位置不會受到影響,因此可以照常使用<br /> */<br />public static Bitmap decodeFileDescriptor(FileDescriptor fd) {<br /> return decodeFileDescriptor(fd, null, null);<br />}</p><p>/**<br /> * 從指定Resources中解碼出位元影像<br /> */<br />public static Bitmap decodeResource(Resources res, int id, Options opts) {<br /> Bitmap bm = null;<br /> InputStream is = null; </p><p> try {<br /> final TypedValue value = new TypedValue();<br /> is = res.openRawResource(id, value);</p><p> bm = decodeResourceStream(res, value, is, null, opts);<br /> } catch (Exception e) {<br /> /* do nothing.<br /> If the exception happened on open, bm will be null.<br /> If it happened on close, bm is still valid.<br /> */<br /> } finally {<br /> try {<br /> if (is != null) is.close();<br /> } catch (IOException e) {<br /> // Ignore<br /> }<br /> }</p><p> return bm;<br />}</p><p>/**<br /> * 從指定Resources中解碼出位元影像<br /> */<br />public static Bitmap decodeResource(Resources res, int id) {<br /> return decodeResource(res, id, null);<br />}</p><p>/**<br /> * 從InputStream中解碼出位元影像,這個InputStream是從Resources中擷取的<br /> * 仍然將Resources作為參數傳入是為了根據Resources資訊縮放位元影像<br /> */<br />public static Bitmap decodeResourceStream(Resources res, TypedValue value,<br /> InputStream is, Rect pad, Options opts) {</p><p> if (opts == null) {<br /> opts = new Options();<br /> }</p><p> if (opts.inDensity == 0 && value != null) {<br /> final int density = value.density;<br /> if (density == TypedValue.DENSITY_DEFAULT) {<br /> opts.inDensity = DisplayMetrics.DENSITY_DEFAULT;<br /> } else if (density != TypedValue.DENSITY_NONE) {<br /> opts.inDensity = density;<br /> }<br /> }</p><p> if (opts.inTargetDensity == 0 && res != null) {<br /> opts.inTargetDensity = res.getDisplayMetrics().densityDpi;<br /> }</p><p> return decodeStream(is, pad, opts);<br />}</p><p>/**<br /> * 將InputStream解碼成位元影像,如果InputStream是null或者不能用來產生一個位元影像<br /> * 則函數返回null,InputStream中流的位置不會受到這個函數的任何影響<br /> */<br />public static Bitmap decodeStream(InputStream is, Rect outPadding, Options opts) {<br /> // we don't throw in this case, thus allowing the caller to only check<br /> // the cache, and not force the image to be decoded.<br /> if (is == null) {<br /> return null;<br /> }</p><p> // we need mark/reset to work properly</p><p> if (!is.markSupported()) {<br /> is = new BufferedInputStream(is, 16 * 1024);<br /> }</p><p> // so we can call reset() if a given codec gives up after reading up to<br /> // this many bytes. FIXME: need to find out from the codecs what this<br /> // value should be.<br /> is.mark(1024);</p><p> Bitmap bm;</p><p> if (is instanceof AssetManager.AssetInputStream) {<br /> bm = nativeDecodeAsset(((AssetManager.AssetInputStream) is).getAssetInt(),<br /> outPadding, opts);<br /> } else {<br /> // pass some temp storage down to the native code. 1024 is made up,<br /> // but should be large enough to avoid too many small calls back<br /> // into is.read(...) This number is not related to the value passed<br /> // to mark(...) above.<br /> byte [] tempStorage = null;<br /> if (opts != null) tempStorage = opts.inTempStorage;<br /> if (tempStorage == null) tempStorage = new byte[16 * 1024];<br /> bm = nativeDecodeStream(is, tempStorage, outPadding, opts);<br /> }</p><p> return finishDecode(bm, outPadding, opts);<br />}</p><p>/**<br /> * 將InputStream解碼成位元影像,如果InputStream是null或者不能用來產生一個位元影像<br /> * 則函數返回null,InputStream中流的位置不會受到這個函數的任何影響<br /> */<br />public static Bitmap decodeStream(InputStream is) {<br /> return decodeStream(is, null, null);<br />}我們的位元影像工具類BitmapUtils其實只用到了BitmapFactory.decodeByteArray(...)函數,如下所示,代碼比較簡單,主要涉及Java IO操作和BitmapFactory的使用(位於檔案BitmapUtils.java中)

package com.google.android.panoramio;</p><p>import android.graphics.Bitmap;<br />import android.graphics.BitmapFactory;<br />import android.util.Log;</p><p>import java.io.BufferedInputStream;<br />import java.io.BufferedOutputStream;<br />import java.io.ByteArrayOutputStream;<br />import java.io.Closeable;<br />import java.io.IOException;<br />import java.io.InputStream;<br />import java.io.OutputStream;<br />import java.net.URL;</p><p>/**<br /> * 從指定URL載入位元影像的工具類<br /> *<br /> */<br />public class BitmapUtils {</p><p> private static final String TAG = "Panoramio";</p><p> private static final int IO_BUFFER_SIZE = 4 * 1024;</p><p> /**<br /> * 從指定的url載入位元影像,這將會持續一段時間,因此不應該從UI線程中調用<br /> */<br /> public static Bitmap loadBitmap(String url) {<br /> Bitmap bitmap = null;<br /> InputStream in = null;<br /> BufferedOutputStream out = null;</p><p> try {<br /> in = new BufferedInputStream(new URL(url).openStream(), IO_BUFFER_SIZE);</p><p> final ByteArrayOutputStream dataStream = new ByteArrayOutputStream();<br /> out = new BufferedOutputStream(dataStream, IO_BUFFER_SIZE);<br /> copy(in, out);<br /> out.flush();</p><p> final byte[] data = dataStream.toByteArray();<br /> //調用BitmapFactory類的函數從位元組數組中解碼出位元影像<br /> bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);<br /> } catch (IOException e) {<br /> Log.e(TAG, "Could not load Bitmap from: " + url);<br /> } finally {<br /> closeStream(in);<br /> closeStream(out);<br /> }</p><p> return bitmap;<br /> }</p><p> /**<br /> * 關閉指定的資料流<br /> */<br /> private static void closeStream(Closeable stream) {<br /> if (stream != null) {<br /> try {<br /> stream.close();<br /> } catch (IOException e) {<br /> android.util.Log.e(TAG, "Could not close stream", e);<br /> }<br /> }<br /> }</p><p> /**<br /> * 使用臨時的位元組數組緩衝將InputStream中的資料拷貝到OutputStream<br /> */<br /> private static void copy(InputStream in, OutputStream out) throws IOException {<br /> byte[] b = new byte[IO_BUFFER_SIZE];<br /> int read;<br /> while ((read = in.read(b)) != -1) {<br /> out.write(b, 0, read);<br /> }<br /> }</p><p>}==============================碎裂吧 鏡花水月===============================

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.