/* * Copyright (C) 2010 Cyril Mottier (http://www.cyrilmottier.com) * * 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 com.cyrilmottier.android.remotedrawable; import java.io.InputStream; import java.net.URL; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import android.graphics.drawable.Drawable; import android.os.Handler; import android.util.Log; import com.cyrilmottier.android.remotedrawable.util.Config; /** * The DrawableDownloader takes care of downloading Drawable according to a * given URL. It includes a cache that prevent downloading previously downloaded * Drawables. * * @author Cyril Mottier */ public class DrawableDownloader { static interface Callback { void onDrawableLoaded(String urlString, Drawable drawable); void onDrawableLoadingFailed(String urlString); } private static final boolean DEBUG_LOGS_FILE_ENABLED = true; private static final boolean DEBUG_LOGS_ENABLED = DEBUG_LOGS_FILE_ENABLED && Config.DEBUG_LOGS_PROJECT_ENABLED; private static final String LOG_TAG = DrawableDownloader.class.getSimpleName(); private static final int POOL_THREAD_NUMBER = 3; private static DrawableDownloader sInstance; private final ExecutorService mPool; private final BasicDrawableCache mCache; private final Handler mHandler = new Handler(); private DrawableDownloader() { mPool = Executors.newFixedThreadPool(POOL_THREAD_NUMBER); mCache = new BasicDrawableCache(); } public static DrawableDownloader getInstance() { if (sInstance == null) { sInstance = new DrawableDownloader(); } return sInstance; } public Drawable getDrawable(final String urlString, final Callback callback) { final Drawable d = mCache.get(urlString); if (d != null) { return d; } // TODO cyril: The following code has been written for a demo purpose // only. It doesn't work properly when device orientation is changing // for instance. Here, we should first be sure, the urlString is not a // pending or running task to prevent downloading useless drawables. // Unfortunatly, doing so implies using or own thread pool (in which // each queued task is known) - which is not the purpose of this // demonstration. // TODO cyril: Nothing is done to handle timeouts or network // connectivity problem ... Is the "catch" bloc a sufficient code for // that? mPool.execute(new Runnable() { public void run() { try { if (DEBUG_LOGS_ENABLED) { Log.d(LOG_TAG, "Starting to download at " + urlString); } URL url = new URL(urlString); InputStream is = (InputStream) url.getContent(); final Drawable drawable = Drawable.createFromStream(is, null); mCache.put(urlString, drawable); if (DEBUG_LOGS_ENABLED) { Log.d(LOG_TAG, "Download completed at " + urlString); } mHandler.post(new Runnable() { public void run() { // TODO cyril: Actually we should call the callback // here on ALL RemoteDrawable that asked for the // given url. (In case two different Drawable asked // for the same URL and a pending/running URL hasn't // been re-downloaded - cf previous TODO) callback.onDrawableLoaded(urlString, drawable); } }); } catch (Exception e) { e.printStackTrace(); mHandler.post(new Runnable() { public void run() { callback.onDrawableLoadingFailed(urlString); } }); } } }); // Here null is returned to indicate the Drawable is not ready return null; } }