鏈?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();
}
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ě):
- 用單例的方式生成一個(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;
}
}
- 繼承線程池
繼承的目的是:我們需要在線程任務(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就到這了