Android 面試之常用開(kāi)源庫(kù)

本文出自 Eddy Wiki ,轉(zhuǎn)載請(qǐng)注明出處:http://eddy.wiki/interview-opensource.html

本文收集整理了 Android 中常用的一些開(kāi)源庫(kù)。

圖片加載開(kāi)源庫(kù)

參考:

  1. Android開(kāi)源項(xiàng)目推薦之「圖片加載到底哪家強(qiáng)」

網(wǎng)絡(luò)請(qǐng)求開(kāi)源庫(kù)

參考:

  1. Android開(kāi)源項(xiàng)目推薦之「網(wǎng)絡(luò)請(qǐng)求哪家強(qiáng)」

Volley 源碼解析

參考:

http://a.codekk.com/detail/Android/grumoon/Volley%20%E6%BA%90%E7%A0%81%E8%A7%A3%E6%9E%90

Volley的磁盤(pán)緩存

在面試的時(shí)候,聊到 Volley 請(qǐng)求到網(wǎng)絡(luò)的數(shù)據(jù)緩存。當(dāng)時(shí)說(shuō)到是 Volley 會(huì)將每次通過(guò)網(wǎng)絡(luò)請(qǐng)求到的數(shù)據(jù),采用FileOutputStream,寫(xiě)入到本地的文件中。
那么問(wèn)題來(lái)了:這個(gè)緩存文件,是聲明在一個(gè)SD卡文件夾中的(也可以是getCacheFile())。如果不停的請(qǐng)求網(wǎng)絡(luò)數(shù)據(jù),這個(gè)緩存文件夾將無(wú)限制的增大,最終達(dá)到SD卡容量時(shí),會(huì)發(fā)生無(wú)法寫(xiě)入的異常(因?yàn)榇鎯?chǔ)空間滿(mǎn)了)。
這個(gè)問(wèn)題的確以前沒(méi)有想到,當(dāng)時(shí)也沒(méi)說(shuō)出怎么回事。回家了趕緊又看了看代碼才知道,原來(lái) Volley 考慮過(guò)這個(gè)問(wèn)題(汗!想想也是)
翻看代碼DiskBasedCache#pruneIfNeeded()

private void pruneIfNeeded(int neededSpace) {
    if ((mTotalSize + neededSpace) < mMaxCacheSizeInBytes) {
        return;
    }
    
    long before = mTotalSize;
    int prunedFiles = 0;
    long startTime = SystemClock.elapsedRealtime();

    Iterator<Map.Entry<String, CacheHeader>> iterator = mEntries.entrySet().iterator();
    while (iterator.hasNext()) {
        Map.Entry<String, CacheHeader> entry = iterator.next();
        CacheHeader e = entry.getValue();
        boolean deleted = getFileForKey(e.key).delete();
        if (deleted) {
            mTotalSize -= e.size;
        } else {
    //print log
        }
        iterator.remove();
        prunedFiles++;
        if ((mTotalSize + neededSpace) < mMaxCacheSizeInBytes * HYSTERESIS_FACTOR) {
            break;
        }
    }
}

其中mMaxCacheSizeInBytes是構(gòu)造方法傳入的一個(gè)緩存文件夾的大小,如果不傳默認(rèn)是5M的大小。
通過(guò)這個(gè)方法可以發(fā)現(xiàn),每當(dāng)被調(diào)用時(shí)會(huì)傳入一個(gè)neededSpace,也就是需要申請(qǐng)的磁盤(pán)大小(即要新緩存的那個(gè)文件所需大小)。首先會(huì)判斷如果這個(gè)neededSpace申請(qǐng)成功以后是否會(huì)超過(guò)最大可用容量,如果會(huì)超過(guò),則通過(guò)遍歷本地已經(jīng)保存的緩存文件的header(header中包含了緩存文件的緩存有效期、占用大小等信息)去刪除文件,直到可用容量不大于聲明的緩存文件夾的大小。
其中HYSTERESIS_FACTOR是一個(gè)值為0.9的常量,應(yīng)該是為了防止誤差的存在吧(我猜的)。

Volley緩存命中率的優(yōu)化

如果讓你去設(shè)計(jì)Volley的緩存功能,你要如何增大它的命中率。
可惜了,如果上面的緩存功能是昨天看的,今天的面試這個(gè)問(wèn)題就能說(shuō)出來(lái)了。
還是上面的代碼,在緩存內(nèi)容可能超過(guò)緩存文件夾的大小時(shí),刪除的邏輯是直接遍歷header刪除。這個(gè)時(shí)候刪除的文件有可能是我們上一次請(qǐng)求時(shí)剛剛保存下來(lái)的,屁股都還沒(méi)坐穩(wěn)呢,現(xiàn)在立即刪掉,有點(diǎn)舍不得啊。
如果遍歷的時(shí)候,判斷一下,首先刪除超過(guò)緩存有效期的(過(guò)期緩存),其次按照LRU算法,刪除最久未使用的,豈不是更合適?

Volley緩存文件名的計(jì)算

這個(gè)是我一直沒(méi)弄懂的問(wèn)題。
如下代碼:

private String getFilenameForKey(String key) {
    int firstHalfLength = key.length() / 2;
    String localFilename = String.valueOf(key.substring(0, firstHalfLength).hashCode());
    localFilename += String.valueOf(key.substring(firstHalfLength).hashCode());
    return localFilename;
}

為什么會(huì)要把一個(gè)key分成兩部分,分別求hashCode,最后又做拼接。
這個(gè)問(wèn)題之前在stackoverflow上問(wèn)過(guò) #鏈接
原諒我,別人的回答我最初并沒(méi)有看懂。直到最近被問(wèn)到,如果讓你設(shè)計(jì)一個(gè)HashMap,如何避免value被覆蓋,我才想到原因。
先來(lái)看一下 String#hashCode() 的實(shí)現(xiàn):

@Override public int hashCode() {
    int hash = hashCode;
    if (hash == 0) {
        if (count == 0) {
            return 0;
        }
        final int end = count + offset;
        final char[] chars = value;
        for (int i = offset; i < end; ++i) {
            hash = 31*hash + chars[i];
        }
        hashCode = hash;
    }
    return hash;
}

從上面的實(shí)現(xiàn)可以看到,String的hashcode是根據(jù)字符數(shù)組中每個(gè)位置的字母的int值再加上上次hash值乘以31,這種算法求出來(lái)的,至于為什么是31,我也不清楚。
但是可以肯定一點(diǎn),hashcode并不是唯一的。不信你運(yùn)行下面這兩個(gè)輸出:

System.out.print("======" + "vFrKiaNHfF7t[9::E[XsX?L7xPp3DZSteIZvdRT8CX:w6d;v<_KZnhsM_^dqoppe".hashCode());
System.out.print("======" + "hI4pFxGOfS@suhVUd:mTo_begImJPB@Fl[6WJ?ai=RXfIx^=Aix@9M;;?Vdj_Zsi".hashCode());

這兩個(gè)字符串是根據(jù)hashcode的算法逆向出來(lái)的,他們的hashcode都是12345。逆向算法請(qǐng)見(jiàn)這里
再回到我們的問(wèn)題,為什么會(huì)要把一個(gè)key分成兩部分?,F(xiàn)在可以肯定的答出,目的是為了盡可能避免hashcode重復(fù)造成的文件名重復(fù)(求兩次hash兩次都與另一個(gè)url重復(fù)的概率總要比一次重復(fù)的概率小吧)。
順帶再提一點(diǎn),就像上面說(shuō)的,概率小并不代表不存在。但是Java計(jì)算hashcode的速度是很快的,應(yīng)該是在效率和安全性上取舍的結(jié)果吧。

Glide源碼解析

參考:

http://www.lightskystreet.com/2015/10/12/glide_source_analysis/

http://frodoking.github.io/2015/10/10/android-glide/

Retrofit源碼分析

參考:

Retrofit源碼分析

EventBus源碼分析

參考:

EventBus源碼分析

greenDAO

參考:

Android ORM 框架之 greenDAO 使用心得

RxJava

參考:

RxJava

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容