如何寫(xiě)圖片壓縮框架

鏈?zhǔn)骄幊?/h4>
try {
    final InputStream is = getResources().getAssets().open("test-6.jpg");
    final BitmapFactory.Options options = new BitmapFactory.Options();
    options.inPreferredConfig = mConfig;
    Bitmap originBitmap = BitmapFactory.decodeStream(is, null, options);
    //上面代碼就是通過(guò)流得到Bitmap對(duì)象
    KmoCompress.FileCompressOptions compressOptions = new KmoCompress.FileCompressOptions();//設(shè)置自己的配置對(duì)象
    compressOptions.config = mConfig;
    KmoCompress.getInstance().source(originBitmap).asFile().withOptions(compressOptions).compress(new FileWithBitmapCallback() {
        @Override
        public void callback(boolean isSuccess, Bitmap bitmap, String outfile, Throwable t) {
            if (!isSuccess) {
                Logger.e("error: " + t.getMessage());
                mCompressTv.setText("compress file failed!");
                return;
            }
            File file = new File(outfile);
            setupCompressInfo(bitmap, outfile, file.length());
        }
    });
    is.close();
} catch (Exception e) {
    e.printStackTrace();
}

看到KmoCompress.getInstance().source(originBitmap).asFile().XXX這段就是鏈?zhǔn)骄幊獭?/p>

首先由一個(gè)單例發(fā)出何鸡,單例里面有source這個(gè)方法

public synchronized CompressEngine source(Bitmap bitmap) {
    return new CompressEngine().source(bitmap);
}

這個(gè)方法很簡(jiǎn)單揖庄,就是new 一個(gè)對(duì)象調(diào)用該對(duì)象的source先慷,這樣就把業(yè)務(wù)轉(zhuǎn)移到了CompressEngine這個(gè)對(duì)象身上。

public CompressEngine source(Bitmap bitmap) {
    mSourceType = SourceType.BITMAP;
    mSource = bitmap;
    return this;
}

這個(gè)對(duì)象的source方法就是存儲(chǔ)一些東西判导。

所以我們小結(jié)如下:

鏈?zhǔn)骄幊淘?號(hào)后面無(wú)非就是兩種情況:

  • new 對(duì)象然后將業(yè)務(wù)轉(zhuǎn)移到該對(duì)象身上嫉父。
  • this 就是當(dāng)前對(duì)象實(shí)現(xiàn)業(yè)務(wù)
/**
 * @return  文件處理引擎,里面包含了圖片源和圖片類(lèi)型
 */
public FileCompressEngine asFile() {
    return CompressEngineFactory.buildFileCompressEngine(mSource, mSourceType);
}
/**
 * @param options 配置文件
 * @return
 */
public FileCompressEngine withOptions(KmoCompress.FileCompressOptions options) {
    options.config = CompressUtils.filterConfig(options.config);//對(duì)config轉(zhuǎn)化骡楼,如果是ARGB_8888,ARGB_4444,ALPHA_8都對(duì)應(yīng)成8888熔号,RGB_565就是RGB_565
    mCompressOptions = options;//并將配置保存
    return this;
}

此時(shí)鏈?zhǔn)骄幊桃呀?jīng)傳遞到withOptions方法,他返回的是FileCompressEngine對(duì)象本身鸟整,那也就是說(shuō)后面的compress方法也在該對(duì)象內(nèi)部實(shí)現(xiàn)引镊。

我們目前來(lái)看結(jié)果,上面代碼到withOptions都是處理參數(shù)的保存篮条,真正的壓縮還沒(méi)有執(zhí)行弟头。我們想一個(gè)問(wèn)題哈,就是壓縮是需要時(shí)間的涉茧,在Android里面耗時(shí)的操作不要 給主線程放赴恨,那么應(yīng)該怎么讓compress去通過(guò)我們傳遞進(jìn)來(lái)的數(shù)據(jù)源在子線程中壓縮數(shù)據(jù)呢?同時(shí)我們是需要返回結(jié)果的傳統(tǒng)的new Thread(){run()}.start();已經(jīng)不能滿足我們伴栓,因?yàn)槲覀円獙⒔Y(jié)果刷入主線程中伦连,我們?cè)趺醋瞿兀?/p>

線程池+任務(wù)

根據(jù)上面所以這里就對(duì)應(yīng)一個(gè)問(wèn)題模型:數(shù)據(jù)源我們現(xiàn)在處理了雨饺,也傳遞到此時(shí)的處理類(lèi)中,但是由于處理數(shù)據(jù)比較耗時(shí)惑淳,而且我們需要處理結(jié)果在主線程中额港,怎么辦?

先看怎么寫(xiě):

  1. 用單例的方式生成一個(gè)線程池
public class CompressExecutor {

    private CompressExecutor() {
        throw new RuntimeException("can not be a instance");
    }

    private static final ThreadPoolExecutor DEFAULT_COMPRESS_EXECUTOR;

    static {
        int nThreads = Runtime.getRuntime().availableProcessors() + 1;
        DEFAULT_COMPRESS_EXECUTOR = new CompressThreadPool(
                nThreads,
                nThreads,
                0L,
                TimeUnit.MILLISECONDS,
                new LinkedBlockingQueue<Runnable>(),
                new CompressThreadFactory()
        );
    }

    public static ThreadPoolExecutor getExecutor() {
        return DEFAULT_COMPRESS_EXECUTOR;
    }

}
  1. 繼承線程池

繼承的目的是:我們需要在線程任務(wù)執(zhí)行完成之后打印一些信息

public class CompressThreadPool extends ThreadPoolExecutor {

    public CompressThreadPool(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
    }

    public CompressThreadPool(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, RejectedExecutionHandler handler) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, handler);
    }

    public CompressThreadPool(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory);
    }

    public CompressThreadPool(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, handler);
    }

    /**
     * Method invoked prior to executing the given Runnable in the given thread.
     *
     * @param t
     * @param r
     */
    @Override
    protected void beforeExecute(Thread t, Runnable r) {
        super.beforeExecute(t, r);
        //ignore...
    }

    /**
     * Method invoked upon completion of execution of the given Runnable.
     *
     * @param r
     * @param t
     */
    @Override
    protected void afterExecute(Runnable r, Throwable t) {
        super.afterExecute(r, t);
        KmoCompressUtil.printExceptionMessage(t);
    }

    /**
     * Method invoked when the Executor has terminated.
     */
    @Override
    protected void terminated() {
        super.terminated();
        //ignore...
    }
}
public class FileCompressEngine extends CompressEngine {
    ...
    Bitmap bitmap = (Bitmap) mSource;
    CompressExecutor.getExecutor()
            .execute(new CompressFutureTask<CompressResult>(new FileCompressCallableTasks.BitmapAsFileCallable(mCompressOptions, shouldReturnBitmap, bitmap)
                    , new DefaultCallbackDispatcher<CompressResult>(callback)
            ));
    ...
}

我們觀察一下new CompressFutureTask的繼承結(jié)構(gòu):

public class CompressFutureTask<T> extends FutureTask<T> {

這下就和我們上一次的博客吻合歧焦,在線程任務(wù)執(zhí)行過(guò)程中移斩,work包裝了我們的線程,最終調(diào)用了run方法绢馍,我們?cè)贔utureTask中看看向瓷,最終的run方法。

public void run() {
    if (state != NEW ||
        !U.compareAndSwapObject(this, RUNNER, null, Thread.currentThread()))
        return;
    try {
        Callable<V> c = callable;
        if (c != null && state == NEW) {
            V result;
            boolean ran;
            try {
                result = c.call();
                ran = true;
            } catch (Throwable ex) {
                result = null;
                ran = false;
                setException(ex);
            }
            if (ran)
                set(result);
        }
    } finally {
        runner = null;
        int s = state;
        if (s >= INTERRUPTING)
            handlePossibleCancellationInterrupt(s);
    }
}

看到是調(diào)用call和set方法舰涌。

所以我們的業(yè)務(wù)核心在call方法上

call方法是外界塞給FutureTask的對(duì)應(yīng)接口猖任。

  public static final class FileAsFileCallable extends BaseFileCompressCallable {
        private File mFile;

        public FileAsFileCallable(KmoCompress.FileCompressOptions options, boolean withBitmap, File file) {
            super(options, withBitmap);
            mFile = file;
        }

        @Override
        public CompressResult call() throws Exception {
            CompressResult result = null;
            FileInputStream fis = null;
            try {
                if (mCompressOptions != null && mCompressOptions.overrideSource)
                    mCompressOptions.outfile = mFile.getAbsolutePath();
                fis = new FileInputStream(mFile);
                result = new FileCompressor().compress(CompressUtils.transformToByteArray(fis), mCompressOptions, shouldReturnBitmap, true);
            } finally {
                try {
                    if (fis != null)
                        fis.close();
                } catch (IOException e) {
                    //ignore...
                }
            }
            return result;
        }
    }

所以call是壓縮的核心那后面就不多說(shuō),主要是一些壓縮比例轉(zhuǎn)化等等問(wèn)題以后我們?cè)谡f(shuō)壓縮如何壓縮舵稠。這個(gè)就直接偏向應(yīng)用層超升,不需要架構(gòu)的概念入宦,我們今天只討論架構(gòu)的東西哺徊。OK就到這了

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市乾闰,隨后出現(xiàn)的幾起案子落追,更是在濱河造成了極大的恐慌,老刑警劉巖涯肩,帶你破解...
    沈念sama閱讀 211,042評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件轿钠,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡病苗,警方通過(guò)查閱死者的電腦和手機(jī)疗垛,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,996評(píng)論 2 384
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)硫朦,“玉大人贷腕,你說(shuō)我怎么就攤上這事∫д梗” “怎么了泽裳?”我有些...
    開(kāi)封第一講書(shū)人閱讀 156,674評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)破婆。 經(jīng)常有香客問(wèn)我涮总,道長(zhǎng),這世上最難降的妖魔是什么祷舀? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,340評(píng)論 1 283
  • 正文 為了忘掉前任瀑梗,我火速辦了婚禮烹笔,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘抛丽。我一直安慰自己箕宙,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,404評(píng)論 5 384
  • 文/花漫 我一把揭開(kāi)白布铺纽。 她就那樣靜靜地躺著柬帕,像睡著了一般。 火紅的嫁衣襯著肌膚如雪狡门。 梳的紋絲不亂的頭發(fā)上陷寝,一...
    開(kāi)封第一講書(shū)人閱讀 49,749評(píng)論 1 289
  • 那天,我揣著相機(jī)與錄音其馏,去河邊找鬼凤跑。 笑死,一個(gè)胖子當(dāng)著我的面吹牛叛复,可吹牛的內(nèi)容都是我干的仔引。 我是一名探鬼主播,決...
    沈念sama閱讀 38,902評(píng)論 3 405
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼褐奥,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼咖耘!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起撬码,我...
    開(kāi)封第一講書(shū)人閱讀 37,662評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤儿倒,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后呜笑,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體夫否,經(jīng)...
    沈念sama閱讀 44,110評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,451評(píng)論 2 325
  • 正文 我和宋清朗相戀三年叫胁,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了凰慈。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,577評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡驼鹅,死狀恐怖微谓,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情谤民,我是刑警寧澤堰酿,帶...
    沈念sama閱讀 34,258評(píng)論 4 328
  • 正文 年R本政府宣布,位于F島的核電站张足,受9級(jí)特大地震影響触创,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜为牍,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,848評(píng)論 3 312
  • 文/蒙蒙 一哼绑、第九天 我趴在偏房一處隱蔽的房頂上張望岩馍。 院中可真熱鬧,春花似錦抖韩、人聲如沸蛀恩。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,726評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)双谆。三九已至,卻和暖如春席揽,著一層夾襖步出監(jiān)牢的瞬間顽馋,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,952評(píng)論 1 264
  • 我被黑心中介騙來(lái)泰國(guó)打工幌羞, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留寸谜,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,271評(píng)論 2 360
  • 正文 我出身青樓属桦,卻偏偏與公主長(zhǎng)得像熊痴,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子聂宾,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,452評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 171,737評(píng)論 25 707
  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理果善,服務(wù)發(fā)現(xiàn),斷路器亏吝,智...
    卡卡羅2017閱讀 134,628評(píng)論 18 139
  • 一 潮水褪走了 風(fēng)還沒(méi)來(lái) 燈塔的余光淹沒(méi) 寄居蟹的腳印 水鳥(niǎo)土氩海靠在港口 成為唯一的證人 用一捧水 澆灌游魚(yú)的夢(mèng) 把...
    雨子1983閱讀 160評(píng)論 2 2
  • 一葉知秋落海堤,蕭瑟昏夕蔚鸥,渫雨凄迷。天開(kāi)陰?kù)V夢(mèng)依稀许赃,鴻雁輕啼止喷,望斷云低。 殘熱猶威汗染衣混聊,茶飲神移...
    海1619閱讀 242評(píng)論 2 7
  • 《遇見(jiàn)一棵花樹(shù)》 ……………………………………………… 每次讀席慕容的詩(shī)弹谁,那些柔軟清麗的句子,猶如微風(fēng)般輕輕拂來(lái)…...
    女俠K的解憂年畫(huà)鋪閱讀 522評(píng)論 0 0