從Foursquare看手機端程式設計(1)

derekzhan發表於2010-12-06

外國人真具有共產主義精神,Foursquare都拿出開源了,不像國內某些公司。Foursquare下載地址主頁地址http://code.google.com/p/foursquared/ 。下載方式hg clone https://foursquared.googlecode.com/hg/ foursquared ,在linux下用hg命令可以直接下載。Foursquare在程式碼組織方面當然是相當不錯的,層次邏輯規劃的相當好,在解決網路讀寫時的介面阻塞,以及圖片載入等耗時操作方面採用的方式值得借鑑。下面以傳輸協議,圖片載入,網路讀取方面介紹。

一.協議層

Foursquare採用http協議傳輸資料。目前如Foursquaretwitter都採用如手機+瀏覽器+iPad等諸多裝置,為了伺服器的統一,採用http協議。

Foursquare中的基類HttpApi定義了Http協議的一些介面doHttpRequest,及doHttpPostAbstractHttpApi則實現了上述方法。Foursquare與伺服器交換資料的格式採用XML格式。Foursquare客戶端要獲取資料時首先構造好http請求,通過http層的doHttpRequest,及doHttpPost層傳送http請求,伺服器解析http請求,把結果儲存為XML格式返回給客戶端。以City類來解釋XML解析過程,過程中涉及四個類,AbstractParser解析基類,主要使用者構造解析器基類,提供解析方法,CityParser繼承自AbstractParser,用於解析一條協議,FoursqureType介面無函式定義,用於表示是一個Foursqure型別,City繼承於FoursqureType表示一個解析結果。

解析方式中採用了設計模式中的模板模式定義一個操作中的演算法骨架,而將進一步實現延遲到子類中,子類不改變一個演算法的結構即可中定義改演算法的某些特定步驟,達到複用程式碼的目的。

AbstractParser類中定義瞭解析演算法的模板,並且定義了抽象方法abstract protected T parseInner()用於解析一個具體的協議。我們來看模板方法:

public final T parse(XmlPullParser parser) throws FoursquareParseException, FoursquareError {

///演算法模板

try {

if (parser.getEventType() == XmlPullParser.START_DOCUMENT) {

parser.nextTag();

if (parser.getName().equals("error")) {

throw new FoursquareError(parser.nextText());

}

}

return parseInner(parser); //呼叫子類具體實現

} catch (IOException e) {

if (DEBUG) LOG.log(Level.FINE, "IOException", e);

throw new FoursquareParseException(e.getMessage());

} catch (XmlPullParserException e) {

if (DEBUG) LOG.log(Level.FINE, "XmlPullParserException", e);

throw new FoursquareParseException(e.getMessage());

}

}

 

 

再看下CityParser 子類具體解析的過程:

伺服器返回的結果

<?xml version=”1.0”?>

<city>

< geolat ></ geolat >

< geolong ></ geolong >

< id ></ id >

< name ></ name >

< shortname ></ shortname >

< timezone ></ timezone >

< cityid ></ cityid >

</city>


CityParser中的parseInner解析過程

parser.require(XmlPullParser.START_TAG, null, null);

City city = new City();               //解析結果

while (parser.nextTag() == XmlPullParser.START_TAG) {

String name = parser.getName();

if ("geolat".equals(name)) {

city.setGeolat(parser.nextText());

} else if ("geolong".equals(name)) {

city.setGeolong(parser.nextText());

} else if ("id".equals(name)) {

city.setId(parser.nextText());

} else if ("name".equals(name)) {

city.setName(parser.nextText());

} else if ("shortname".equals(name)) {

city.setShortname(parser.nextText());

} else if ("timezone".equals(name)) {

city.setTimezone(parser.nextText());

} else if ("cityid".equals(name)) {

city.setId(parser.nextText());

} else {

skipSubTree(parser);

}

}

return city

 

 

Foursquare中要新新增一條協議的時候只要繼承AbstractParser並實現其中的parseInner方法,實現FoursqureType定義一個新的型別就可以了。採用模板方法,無疑提高了系統的可擴充套件性,以及清晰地程式碼結構,容易維護,這就是採用物件導向思想帶來的好處。

二.圖示讀取優化 延遲載入+快取+多執行緒讀取+執行緒池技術

考慮到手機頻寬的限制,以及提升效能,快取是必不可少的元件。在手機端快取,主要使用者快取一些常用的不易改變的圖片,如:地點,使用者,朋友頭像等。來分析下快取的具體實現。快取實現主要在BaseDiskCache類中。

//用於存放一個圖片到快取中

 

public void store(String key, InputStream is) {

        if (DEBUG) Log.d(TAG, "store: " + key);

        is = new BufferedInputStream(is);

        try {

          OutputStream os = new BufferedOutputStream(new FileOutputStream(getFile(key)));//獲取存放路徑


            byte[] b = new byte[2048];

            int count;

            int total = 0;


            while ((count = is.read(b)) > 0) {

                os.write(b, 0, count);

                total += count;

            }

            os.close();

            if (DEBUG) Log.d(TAG, "store complete: " + key);

        } catch (IOException e) {

            if (DEBUG) Log.d(TAG, "store failed to store: " + key, e);

            return;

        }

}

//獲取路徑

public File getFile(String hash) {

        return new File(mStorageDirectory.toString() + File.separator + hash); //存放路徑

}

 

 

相關文章