/* * Copyright (C) 2016 Peng fei Pan <sky@xiaopan.me> * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package me.xiaopan.sketch.feature.large; import android.content.Context; import android.graphics.Bitmap; import android.os.Build; import android.os.HandlerThread; import android.os.Looper; import java.util.concurrent.atomic.AtomicInteger; import me.xiaopan.sketch.SLogType; import me.xiaopan.sketch.SLog; import me.xiaopan.sketch.util.KeyCounter; /** * 碎片解码执行器,负责初始化解码器以及管理解码线程 */ class TileExecutor { private static final String NAME = "TileExecutor"; private static final AtomicInteger THREAD_NUMBER = new AtomicInteger(); private final Object handlerThreadLock = new Object(); Callback callback; private HandlerThread handlerThread; private InitHandler initHandler; MainHandler mainHandler; private DecodeHandler decodeHandler; public TileExecutor(Callback callback) { this.callback = callback; this.mainHandler = new MainHandler(Looper.getMainLooper(), this); } /** * 安装解码线程 */ private void installHandlerThread() { if (handlerThread == null) { synchronized (handlerThreadLock) { if (handlerThread == null) { if (THREAD_NUMBER.get() >= Integer.MAX_VALUE) { THREAD_NUMBER.set(0); } handlerThread = new HandlerThread("ImageRegionDecodeThread" + THREAD_NUMBER.addAndGet(1)); handlerThread.start(); SLog.i(SLogType.LARGE, NAME, "image region decode thread %s started", handlerThread.getName()); decodeHandler = new DecodeHandler(handlerThread.getLooper(), this); initHandler = new InitHandler(handlerThread.getLooper(), this); mainHandler.postDelayRecycleDecodeThread(); } } } } /** * 初始化解码器,初始化结果会通过Callback的onInitCompleted()或onInitError(Exception)方法回调 */ public void submitInit(String imageUri, KeyCounter keyCounter, boolean correctImageOrientation) { installHandlerThread(); initHandler.postInit(imageUri, correctImageOrientation, keyCounter.getKey(), keyCounter); } /** * 提交一个解码请求 */ public void submitDecodeTile(int key, Tile tile) { installHandlerThread(); decodeHandler.postDecode(key, tile); } /** * 取消所有的解码任务 */ public void cleanDecode(String why) { if (decodeHandler != null) { decodeHandler.clean(why); } } /** * 回收所有资源 */ public void recycle(String why) { if (initHandler != null) { initHandler.clean(why); } if (decodeHandler != null) { decodeHandler.clean(why); } recycleDecodeThread(); } void recycleDecodeThread() { if (initHandler != null) { initHandler.clean("recycleDecodeThread"); } if (decodeHandler != null) { decodeHandler.clean("recycleDecodeThread"); } synchronized (handlerThreadLock) { if (handlerThread != null) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) { handlerThread.quitSafely(); } else { handlerThread.quit(); } SLog.w(SLogType.LARGE, NAME, "image region decode thread %s quit", handlerThread.getName()); handlerThread = null; } } } public interface Callback { Context getContext(); void onInitCompleted(String imageUri, ImageRegionDecoder decoder); void onInitError(String imageUri, Exception e); void onDecodeCompleted(Tile tile, Bitmap bitmap, int useTime); void onDecodeError(Tile tile, DecodeHandler.DecodeErrorException exception); } }