package com.jasonchen.microlang.workers; import android.annotation.SuppressLint; import android.app.Activity; import android.graphics.Bitmap; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.os.Handler; import android.os.Looper; import android.support.v4.app.Fragment; import android.text.TextUtils; import android.view.View; import android.view.animation.Animation; import android.widget.ImageView; import android.widget.RelativeLayout; import com.jasonchen.microlang.R; import com.jasonchen.microlang.beans.MessageBean; import com.jasonchen.microlang.beans.UserBean; import com.jasonchen.microlang.debug.AppLogger; import com.jasonchen.microlang.interfaces.IPictureWorker; import com.jasonchen.microlang.interfaces.ISimRayDrawable; import com.jasonchen.microlang.settings.SettingUtility; import com.jasonchen.microlang.tasks.MyAsyncTask; import com.jasonchen.microlang.utils.GlobalContext; import com.jasonchen.microlang.utils.TaskCache; import com.jasonchen.microlang.utils.Utility; import com.jasonchen.microlang.utils.file.FileDownloaderHttpHelper; import com.jasonchen.microlang.utils.file.FileLocationMethod; import com.jasonchen.microlang.utils.file.FileManager; import com.jasonchen.microlang.utils.image.ImageUtility; import com.jasonchen.microlang.view.TimeLineImageView; import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.List; /** * jasonchen * 2015/04/10 */ public class TimeLineBitmapDownloader { private int defaultPictureResId; private Handler handler; static volatile boolean pauseDownloadWork = false; static final Object pauseDownloadWorkLock = new Object(); static volatile boolean pauseReadWork = false; static final Object pauseReadWorkLock = new Object(); private static final Object lock = new Object(); private static TimeLineBitmapDownloader instance; private TimeLineBitmapDownloader(Handler handler) { this.handler = handler; this.defaultPictureResId = R.drawable.timeline_image_loading; } public static TimeLineBitmapDownloader getInstance() { synchronized (lock) { if (instance == null) { instance = new TimeLineBitmapDownloader(new Handler( Looper.getMainLooper())); } } return instance; } public static void refreshThemePictureBackground() { synchronized (lock) { instance = new TimeLineBitmapDownloader(new Handler( Looper.getMainLooper())); } } /** * Pause any ongoing background work. This can be used as a temporary * measure to improve performance. For example background work could be * paused when a ListView or GridView is being scrolled using a * {@link android.widget.AbsListView.OnScrollListener} to keep scrolling * smooth. * <p/> * If work is paused, be sure setPauseDownloadWork(false) is called again * before your fragment or activity is destroyed (for example during * {@link android.app.Activity#onPause()}), or there is a risk the * background thread will never finish. */ public void setPauseDownloadWork(boolean pauseWork) { synchronized (pauseDownloadWorkLock) { TimeLineBitmapDownloader.pauseDownloadWork = pauseWork; if (!TimeLineBitmapDownloader.pauseDownloadWork) { pauseDownloadWorkLock.notifyAll(); } } } public void setPauseReadWork(boolean pauseWork) { synchronized (pauseReadWorkLock) { TimeLineBitmapDownloader.pauseReadWork = pauseWork; if (!TimeLineBitmapDownloader.pauseReadWork) { pauseReadWorkLock.notifyAll(); } } } protected Bitmap getBitmapFromMemCache(String key) { if (TextUtils.isEmpty(key)) { return null; } else { return GlobalContext.getInstance().getBitmapCache().get(key); } } public void downloadAvatar(ImageView view, UserBean user) { downloadAvatar(view, user, false); } public void downloadAvatar(ImageView view, UserBean user, Fragment fragment) { // boolean isFling = fragment.isListViewFling(); downloadAvatar(view, user, false); } public void downloadAvatar(ImageView view, UserBean user, boolean isFling) { if (user == null) { view.setImageResource(defaultPictureResId); return; } String url; FileLocationMethod method; if (SettingUtility.getEnableBigAvatar()) { url = user.getAvatar_large(); method = FileLocationMethod.avatar_large; } else { url = user.getProfile_image_url(); method = FileLocationMethod.avatar_small; } displayImageView(view, url, method, isFling, false); } public void downContentPic(ImageView view, MessageBean msg, Fragment fragment) { String picUrl; // boolean isFling = fragment.isListViewFling(); if (SettingUtility.getEnableBigPic()) { picUrl = msg.getOriginal_pic(); displayImageView(view, picUrl, FileLocationMethod.picture_large, false, false); } else { picUrl = msg.getThumbnail_pic(); displayImageView(view, picUrl, FileLocationMethod.picture_thumbnail, false, false); } } public void displayMultiPicture(ISimRayDrawable view, String picUrl, FileLocationMethod method, boolean isFling) { // boolean isFling = fragment.isListViewFling(); display(view, picUrl, method, isFling, true); } public void displayMultiPicture(ISimRayDrawable view, String picUrl, FileLocationMethod method) { display(view, picUrl, method, false, true); } public void downContentPic(TimeLineImageView view, MessageBean msg, Boolean isFling) { String picUrl; // boolean isFling = fragment.isListViewFling(); if (SettingUtility.getEnableBigPic()) { picUrl = msg.getOriginal_pic(); displayContentPic(view, picUrl, FileLocationMethod.picture_large, isFling, false); } else { picUrl = msg.getThumbnail_pic(); displayContentPic(view, picUrl, FileLocationMethod.picture_thumbnail, isFling, false); } } /** * when user open weibo detail, the activity will setResult to previous * Activity, timeline will refresh at the time user press back button to * display the latest repost count and comment count. But sometimes, weibo * detail's pictures are very large that bitmap memory cache has cleared * those timeline bitmap to save memory, app have to read bitmap from sd * card again, then app play annoying animation , this method will check * whether we should read again or not. */ /* **/ private boolean shouldReloadPicture(ImageView view, String urlKey) { if (urlKey.equals(view.getTag()) && view.getDrawable() != null && view.getDrawable() instanceof BitmapDrawable && ((BitmapDrawable) view.getDrawable() != null && ((BitmapDrawable) view .getDrawable()).getBitmap() != null)) { // AppLogger.d("shouldReloadPicture=false"); return false; } else { view.setTag(null); // AppLogger.d("shouldReloadPicture=true"); return true; } } private void displayImageView(final ImageView view, final String urlKey, final FileLocationMethod method, boolean isFling, boolean isMultiPictures) { view.clearAnimation(); if (!shouldReloadPicture(view, urlKey)) { return; } final Bitmap bitmap = getBitmapFromMemCache(urlKey); if (bitmap != null) { view.setImageBitmap(bitmap); view.setTag(urlKey); if (view.getAlpha() != 1.0f) { view.setAlpha(1.0f); } cancelPotentialDownload(urlKey, view); } else { if (isFling) { view.setImageResource(defaultPictureResId); return; } if (!cancelPotentialDownload(urlKey, view)) { return; } final LocalOrNetworkChooseWorker newTask = new LocalOrNetworkChooseWorker( view, urlKey, method, isMultiPictures); PictureBitmapDrawable downloadedDrawable = new PictureBitmapDrawable( newTask); view.setImageDrawable(downloadedDrawable); // listview fast scroll performance handler.postDelayed(new Runnable() { @Override public void run() { if (getBitmapDownloaderTask(view) == newTask) { newTask.executeOnNormal(); } return; } }, 400); } } private void displayContentPic(final TimeLineImageView view, final String urlKey, final FileLocationMethod method, boolean isFling, boolean isMultiPictures) { view.getImageView().clearAnimation(); if (!shouldReloadPicture(view.getImageView(), urlKey)) { return; } final Bitmap bitmap = getBitmapFromMemCache(urlKey); if (bitmap != null) { System.out.println("从缓存读取图片中..."); float realHeight = bitmap.getHeight(); float realWidth = bitmap.getWidth(); List<Float> result = Utility.calculateWidthAndHeight(realWidth, realHeight); RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) view.getLayoutParams(); params.height = result.get(1).intValue(); params.width = result.get(0).intValue(); float mResult = result.get(1) / result.get(0); AppLogger.e("高宽比:" + mResult); if (mResult >= 5.0) { params.height = Utility.dip2px(157); params.width = Utility.dip2px(157) / 2; view.setLayoutParams(params); view.requestLayout(); view.getImageView().setScaleType(ImageView.ScaleType.CENTER_CROP); AppLogger.e("宽度::"+params.width); }else{ view.setLayoutParams(params); view.requestLayout(); System.out.println("view params height:" + params.height + "width:" + params.width); view.getImageView().setScaleType(ImageView.ScaleType.FIT_XY); } view.setImageBitmap(bitmap); view.getImageView().setTag(urlKey); if (view.getProgressBar() != null) { view.getProgressBar().setVisibility(View.INVISIBLE); } if (view.getImageView().getAlpha() != 1.0f) { view.getImageView().setAlpha(1.0f); } view.setGifFlag(ImageUtility.isThisPictureGif(urlKey)); cancelPotentialDownload(urlKey, view.getImageView()); } else { if (isFling) { view.getImageView().setImageResource(defaultPictureResId); if (view.getProgressBar() != null) { view.getProgressBar().setVisibility(View.INVISIBLE); } view.setGifFlag(ImageUtility.isThisPictureGif(urlKey)); // return; } if (!cancelPotentialDownload(urlKey, view.getImageView())) { return; } final SyncSizeLocalOrNetworkChooseWorker newTask = new SyncSizeLocalOrNetworkChooseWorker( view, urlKey, method, isMultiPictures); PictureBitmapDrawable downloadedDrawable = new PictureBitmapDrawable( newTask); view.setImageDrawable(downloadedDrawable); // listview fast scroll performance handler.postDelayed(new Runnable() { @Override public void run() { if (getBitmapDownloaderTask(view.getImageView()) == newTask) { newTask.executeOnNormal(); } return; } }, 400); } } private void display(final ISimRayDrawable view, final String urlKey, final FileLocationMethod method, boolean isFling, boolean isMultiPictures) { view.getImageView().clearAnimation(); if (!shouldReloadPicture(view.getImageView(), urlKey)) { return; } final Bitmap bitmap = getBitmapFromMemCache(urlKey); if (bitmap != null) { view.setImageBitmap(bitmap); view.getImageView().setTag(urlKey); if (view.getProgressBar() != null) { view.getProgressBar().setVisibility(View.INVISIBLE); } if (view.getImageView().getAlpha() != 1.0f) { view.getImageView().setAlpha(1.0f); } view.setGifFlag(ImageUtility.isThisPictureGif(urlKey)); cancelPotentialDownload(urlKey, view.getImageView()); } else { if (isFling) { view.getImageView().setImageResource(defaultPictureResId); if (view.getProgressBar() != null) { view.getProgressBar().setVisibility(View.INVISIBLE); } view.setGifFlag(ImageUtility.isThisPictureGif(urlKey)); // return; } if (!cancelPotentialDownload(urlKey, view.getImageView())) { return; } final LocalOrNetworkChooseWorker newTask = new LocalOrNetworkChooseWorker( view, urlKey, method, isMultiPictures); PictureBitmapDrawable downloadedDrawable = new PictureBitmapDrawable( newTask); view.setImageDrawable(downloadedDrawable); // listview fast scroll performance handler.postDelayed(new Runnable() { @Override public void run() { if (getBitmapDownloaderTask(view.getImageView()) == newTask) { newTask.executeOnNormal(); } return; } }, 400); } } public void totalStopLoadPicture() { } private static boolean cancelPotentialDownload(String url, ImageView imageView) { IPictureWorker bitmapDownloaderTask = getBitmapDownloaderTask(imageView); if (bitmapDownloaderTask != null) { String bitmapUrl = bitmapDownloaderTask.getUrl(); if ((bitmapUrl == null) || (!bitmapUrl.equals(url))) { if (bitmapDownloaderTask instanceof MyAsyncTask) { ((MyAsyncTask) bitmapDownloaderTask).cancel(true); } } else { return false; } } return true; } private static IPictureWorker getBitmapDownloaderTask(ImageView imageView) { if (imageView != null) { Drawable drawable = imageView.getDrawable(); if (drawable instanceof PictureBitmapDrawable) { PictureBitmapDrawable downloadedDrawable = (PictureBitmapDrawable) drawable; return downloadedDrawable.getBitmapDownloaderTask(); } } return null; } public void display(final ImageView imageView, final int width, final int height, final String url, final FileLocationMethod method, boolean isFling) { ArrayList<ImageView> imageViewArrayList = new ArrayList<ImageView>(); imageViewArrayList.add(imageView); display(imageViewArrayList, width, height, url, method, null, isFling); } public void displayRoundAvatar(final ImageView imageView, final int width, final int height, final String url, final FileLocationMethod method, boolean isFling) { //displayImageView(imageView, url, method, isFling, false); displayReoundAvatar(imageView, width, height, url, method, null, isFling); } public void displayReoundAvatar(final ImageView view, final int width, final int height, final String url, final FileLocationMethod method, final ArrayList<Animation> animations, boolean isFling) { if (TextUtils.isEmpty(url)) { return; } if (!shouldReloadPicture(view, url)) { return; } final Bitmap bitmap = getBitmapFromMemCache(url); if (bitmap != null) { view.setImageBitmap(bitmap); view.setTag(url); if (view.getAlpha() != 1.0f) { view.setAlpha(1.0f); } cancelPotentialDownload(url, view); return; } if (isFling) { view.setImageResource(defaultPictureResId); } new MyAsyncTask<Void, Bitmap, Bitmap>() { @Override protected Bitmap doInBackground(Void... params) { Bitmap bitmap = null; String path = FileManager.getFilePathFromUrl(url, method); if (!(ImageUtility.isThisBitmapCanRead(path) && TaskCache .isThisUrlTaskFinished(url))) { boolean downloaded = TaskCache.waitForPictureDownload(url, null, FileManager.generateDownloadFileName(url), method); if (downloaded) { path = FileManager.getFilePathFromUrl(url, method); } } if (!TextUtils.isEmpty(path)) { bitmap = ImageUtility.readNormalPic(path, width, height); } return bitmap; } @Override protected void onPostExecute(Bitmap bitmap) { super.onPostExecute(bitmap); if (bitmap != null) { GlobalContext.getInstance().getBitmapCache() .put(url, bitmap); view.setImageDrawable(new BitmapDrawable(GlobalContext .getInstance().getResources(), bitmap)); view.setTag(url); // Animation animation = animations.get(0); // view.startAnimation(animation); } } }.executeOnExecutor(MyAsyncTask.THREAD_POOL_EXECUTOR); } public void display(final ArrayList<ImageView> imageView, final int width, final int height, final String url, final FileLocationMethod method, final ArrayList<Animation> animations, boolean isFling) { if (TextUtils.isEmpty(url)) { return; } final Bitmap bitmap = getBitmapFromMemCache(url); if (bitmap != null && bitmap.getHeight() == height && bitmap.getWidth() == width) { for (int i = 0; i < imageView.size(); i++) { ImageView imageView1 = imageView.get(i); imageView1.setImageDrawable(new BitmapDrawable(GlobalContext .getInstance().getResources(), bitmap)); if (animations != null && animations.size() > i) { Animation animation = animations.get(i); imageView1.startAnimation(animation); } } return; } new MyAsyncTask<Void, Bitmap, Bitmap>() { @Override protected Bitmap doInBackground(Void... params) { Bitmap bitmap = null; String path = FileManager.getFilePathFromUrl(url, method); if (!(ImageUtility.isThisBitmapCanRead(path) && TaskCache .isThisUrlTaskFinished(url))) { boolean downloaded = TaskCache.waitForPictureDownload(url, null, FileManager.generateDownloadFileName(url), method); if (downloaded) { path = FileManager.getFilePathFromUrl(url, method); } } if (!TextUtils.isEmpty(path)) { bitmap = ImageUtility.readNormalPic(path, width, height); } return bitmap; } @Override protected void onPostExecute(Bitmap bitmap) { super.onPostExecute(bitmap); if (bitmap != null) { GlobalContext.getInstance().getBitmapCache() .put(url, bitmap); for (int i = 0; i < imageView.size(); i++) { ImageView imageView1 = imageView.get(i); imageView1.setImageDrawable(new BitmapDrawable( GlobalContext.getInstance().getResources(), bitmap)); if (animations != null && animations.size() > i) { Animation animation = animations.get(i); imageView1.startAnimation(animation); } } } } }.executeOnExecutor(MyAsyncTask.THREAD_POOL_EXECUTOR); } public static class DownloadCallback { public void onSubmitJobButNotBegin() { } public void onSubmitJobButAlreadyBegin() { } public void onBegin() { } public void onUpdate(int value, int max) { } public void onComplete(String localPath) { } } public void download(final Activity activity, final String url, final FileLocationMethod method, final DownloadCallback callback) { downloadInner(activity, url, method, callback); } public void download(final Fragment fragment, final String url, final FileLocationMethod method, final DownloadCallback callback) { downloadInner(fragment, url, method, callback); } @SuppressLint("NewApi") private void downloadInner(final Object object, final String url, final FileLocationMethod method, final DownloadCallback callback) { if (TextUtils.isEmpty(url)) { return; } if (TaskCache.isThisUrlTaskFinished(url)) { callback.onSubmitJobButNotBegin(); } else { callback.onSubmitJobButAlreadyBegin(); } new MyAsyncTask<Void, Integer, String>() { WeakReference<Object> activityRef; @Override protected void onPreExecute() { super.onPreExecute(); activityRef = new WeakReference<Object>(object); callback.onBegin(); } @Override protected String doInBackground(Void... params) { String path = FileManager.getFilePathFromUrl(url, method); if (!(ImageUtility.isThisBitmapCanRead(path) && TaskCache .isThisUrlTaskFinished(url))) { boolean downloaded = TaskCache.waitForPictureDownload(url, new FileDownloaderHttpHelper.DownloadListener() { @Override public void pushProgress(final int progress, final int max) { handler.post(new Runnable() { @Override public void run() { onProgressUpdate(progress, max); } }); } @Override public void completed() { } @Override public void cancel() { } }, FileManager.getFilePathFromUrl(url, method), method); if (downloaded) { path = FileManager.getFilePathFromUrl(url, method); } } return path; } @Override protected void onProgressUpdate(Integer... values) { super.onProgressUpdate(values); if (!isComponentLifeCycleFinished()) { int progress = values[0]; int max = values[1]; callback.onUpdate(progress, max); } } @Override protected void onPostExecute(String value) { super.onPostExecute(value); if (!isComponentLifeCycleFinished()) { callback.onComplete(value); } } boolean isComponentLifeCycleFinished() { Object object = activityRef.get(); if (object == null) { return true; } if (object instanceof Fragment) { Fragment fragment = (Fragment) object; if (fragment.getActivity() == null) { return true; } } else if (object instanceof Activity) { Activity activity = (Activity) object; if (activity.isDestroyed()) { return true; } } return false; } }.executeOnExecutor(MyAsyncTask.THREAD_POOL_EXECUTOR); } }