@@ -0,0 +1,3560 @@
+/*%0A * Copyright 2017 huangjinfu%0A *%0A * Licensed under the Apache License, Version 2.0 (the %22License%22);%0A * you may not use this file except in compliance with the License.%0A * You may obtain a copy of the License at%0A *%0A *     http://www.apache.org/licenses/LICENSE-2.0%0A *%0A * Unless required by applicable law or agreed to in writing, software%0A * distributed under the License is distributed on an %22AS IS%22 BASIS,%0A * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.%0A * See the License for the specific language governing permissions and%0A * limitations under the License.%0A */%0A%0Apackage cn.hjf.downloader;%0A%0Aimport android.os.Handler;%0Aimport android.os.HandlerThread;%0A%0Aimport java.util.HashMap;%0Aimport java.util.Map;%0A%0A/**%0A * Provide fixed rate to update progress.%0A *%0A * @author huangjinfu%0A */%0A%0A@ThreadSafe%0Aclass ProgressUpdater extends HandlerThread %7B%0A%0A    /**%0A     * Update per second.%0A     */%0A    private static final int UPDATE_INTERVAL = 1000;%0A%0A    /**%0A     * Handler which attach to update message queue.%0A     */%0A    private Handler updateHandler;%0A%0A    /**%0A     * Evey %7B@link Target%7D have single %7B@link UpdateRunnable%7D instance.%0A     */%0A    private Map%3CTarget, Runnable%3E targetRunnableMap;%0A%0A    /**%0A     * If this field is true, it means that this updater is quited, and no more target can be submitted.%0A     */%0A    private boolean quit;%0A%0A    /**%0A     * A target which will update it's progress.%0A     */%0A    public interface Target %7B%0A        /**%0A         * Time to update progress.%0A         */%0A        void updateProgress();%0A    %7D%0A%0A    public ProgressUpdater() %7B%0A        super(%22MD-ProgressUpdater%22);%0A%0A        targetRunnableMap = new HashMap%3C%3E();%0A    %7D%0A%0A    /**%0A     * Start progress update service of a specific %7B@link Target%7D.%0A     *%0A     * @param target%0A     */%0A    public synchronized void startUpdateService(Target target) %7B%0A        if (!quit) %7B%0A            createHandlerIfNecessary();%0A%0A            UpdateRunnable updateRunnable = new UpdateRunnable(target);%0A%0A            targetRunnableMap.put(target, updateRunnable);%0A%0A            updateHandler.postDelayed(updateRunnable, UPDATE_INTERVAL);%0A        %7D%0A    %7D%0A%0A    /**%0A     * Stop progress update service of a specific target.%0A     *%0A     * @param target%0A     * @throws IllegalStateException No started service of this target be found.%0A     */%0A    public synchronized void stopUpdateService(Target target) %7B%0A        Runnable runnableOfTarget = targetRunnableMap.get(target);%0A        if (runnableOfTarget == null) %7B%0A            throw new IllegalStateException(%22No started service of this target be found, target:%22 + target);%0A        %7D%0A        updateHandler.removeCallbacks(runnableOfTarget);%0A    %7D%0A%0A    /**%0A     * Close this ProgressUpdater, also close all update service of targets.%0A     */%0A    public synchronized void close() %7B%0A        quit = true;%0A        for (Runnable r : targetRunnableMap.values()) %7B%0A            updateHandler.removeCallbacks(r);%0A        %7D%0A        quit();%0A    %7D%0A%0A    /**%0A     * Create update handler.%0A     */%0A    private void createHandlerIfNecessary() %7B%0A        if (updateHandler == null) %7B%0A            updateHandler = new Handler(getLooper());%0A        %7D%0A    %7D%0A%0A    /**%0A     * Update Runnable of specific target.%0A     */%0A    private class UpdateRunnable implements Runnable %7B%0A        private Target target;%0A%0A        public UpdateRunnable(Target target) %7B%0A            this.target = target;%0A        %7D%0A%0A        @Override%0A        public void run() %7B%0A            target.updateProgress();%0A            updateHandler.postDelayed(this, UPDATE_INTERVAL);%0A        %7D%0A    %7D%0A%0A%7D%0A

Add ProgressUpdater.