diff --git a/easyimageprovider/src/main/java/com/example/zane/easyimageprovider/download/execute/BitmapCallback.java b/easyimageprovider/src/main/java/com/example/zane/easyimageprovider/download/execute/BitmapCallback.java index b4f393a..989c03d 100644 --- a/easyimageprovider/src/main/java/com/example/zane/easyimageprovider/download/execute/BitmapCallback.java +++ b/easyimageprovider/src/main/java/com/example/zane/easyimageprovider/download/execute/BitmapCallback.java @@ -79,4 +79,12 @@ public int getPolicy() { Log.i("BitmapCallback", request.ID+" ID"); return request.ID; } + + /** + * 提供task的url + * @return + */ + public String getTaskUrl(){ + return request.uri; + } } diff --git a/easyimageprovider/src/main/java/com/example/zane/easyimageprovider/download/execute/ContainerDrawable.java b/easyimageprovider/src/main/java/com/example/zane/easyimageprovider/download/execute/ContainerDrawable.java index 3f6bdbd..26896c9 100644 --- a/easyimageprovider/src/main/java/com/example/zane/easyimageprovider/download/execute/ContainerDrawable.java +++ b/easyimageprovider/src/main/java/com/example/zane/easyimageprovider/download/execute/ContainerDrawable.java @@ -1,5 +1,7 @@ package com.example.zane.easyimageprovider.download.execute; +import android.content.res.Resources; +import android.graphics.Bitmap; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; @@ -20,13 +22,14 @@ public class ContainerDrawable extends BitmapDrawable{ - private Reference> container; + private Reference> container; - public ContainerDrawable(Map containerMap){ - container = new WeakReference>(containerMap); + public ContainerDrawable(Resources resources, Bitmap bitmap, Map containerMap){ + super(resources, bitmap); + container = new WeakReference>(containerMap); } - public Map getContainerMap(){ + public Map getContainerMap(){ return container.get(); } } diff --git a/easyimageprovider/src/main/java/com/example/zane/easyimageprovider/download/loader/LocalLoader.java b/easyimageprovider/src/main/java/com/example/zane/easyimageprovider/download/loader/LocalLoader.java index 0549f52..f3261c2 100644 --- a/easyimageprovider/src/main/java/com/example/zane/easyimageprovider/download/loader/LocalLoader.java +++ b/easyimageprovider/src/main/java/com/example/zane/easyimageprovider/download/loader/LocalLoader.java @@ -22,7 +22,7 @@ public class LocalLoader implements ImageLoader{ public void loadImage(BitmapRequest request) { loader = new UIImageViewLoader(request); - loader.showLoading(request.placeHolderId); + loader.showLoading(null, request.placeHolderId); final String imagePath = Uri.parse(request.uri).getPath(); final File imgFile = new File(imagePath); if (!imgFile.exists()) { diff --git a/easyimageprovider/src/main/java/com/example/zane/easyimageprovider/download/loader/NetLoader.java b/easyimageprovider/src/main/java/com/example/zane/easyimageprovider/download/loader/NetLoader.java index b2d2cc1..c3e0d15 100644 --- a/easyimageprovider/src/main/java/com/example/zane/easyimageprovider/download/loader/NetLoader.java +++ b/easyimageprovider/src/main/java/com/example/zane/easyimageprovider/download/loader/NetLoader.java @@ -1,15 +1,23 @@ package com.example.zane.easyimageprovider.download.loader; import android.graphics.Bitmap; +import android.graphics.drawable.Drawable; +import android.telecom.Call; import android.util.Log; +import android.widget.ImageView; import android.widget.Toast; import com.example.zane.easyimageprovider.download.execute.BitmapCallback; +import com.example.zane.easyimageprovider.download.execute.ContainerDrawable; import com.example.zane.easyimageprovider.download.execute.LoadTask; import com.example.zane.easyimageprovider.download.execute.LoadThreadPoolExecutor; import com.example.zane.easyimageprovider.download.request.BitmapRequest; import com.example.zane.easyimageprovider.utils.BitmapDecode; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.concurrent.Callable; import java.util.concurrent.CancellationException; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; @@ -30,9 +38,11 @@ public class NetLoader implements ImageLoader{ private UIImageViewLoader loader; private Thread startLoader; + private Map container; public NetLoader(ThreadPoolExecutor executorService){ executor = executorService; + container = new HashMap<>(); } @Override @@ -42,52 +52,92 @@ public void loadImage(final BitmapRequest request) { } private void startTask(final BitmapRequest request) { - if (loader.beforeLoad()) { - callback = new BitmapCallback(request); - future = executor.submit(callback); - loader.showLoading(request.placeHolderId); - - startLoader = new Thread(new Runnable() { - @Override - public void run() { - try { - if (!Thread.currentThread().isInterrupted()){ - bitmap = future.get(); + if (cancelBeforeTask(request.uri, request.getImageView())){ + if (loader.beforeLoad()) { + callback = new BitmapCallback(request); + future = executor.submit(callback); + container.put(callback, future); + + loader.showLoading(container, request.placeHolderId); + + startLoader = new Thread(new Runnable() { + @Override + public void run() { + try { + if (!Thread.currentThread().isInterrupted()){ + bitmap = future.get(); + } + } catch (InterruptedException e){ + Log.i("NetLoader", "thread intrrupt"); + Thread.currentThread().interrupt(); + } catch (CancellationException e){ + Log.i("NetLoader", "cancle computation"); + Thread.currentThread().interrupt(); + } catch (ExecutionException e){ + Log.i("NetLoader", "computation error"); } - } catch (InterruptedException e){ - Log.i("NetLoader", "thread intrrupt"); - Thread.currentThread().interrupt(); - } catch (CancellationException e){ - Log.i("NetLoader", "cancle computation"); - Thread.currentThread().interrupt(); - } catch (ExecutionException e){ - Log.i("NetLoader", "computation error"); - } - Log.i("NetLoader", bitmap + " getBitmap " + request.ID); - if (request.getImageView() != null){ - if (bitmap != null && !request.getImageView().getTag().equals(request.uri)){ - //注意,这里的bitmap已经是压缩了的 - loader.loadImageView(bitmap); - } else { - Log.i("NetLoader", "error " + request.getImageView().getTag().equals(request.uri)); - if (Thread.currentThread().isInterrupted()){ - Log.i("NetLoader", "error by thread intrrupted"); + Log.i("NetLoader", bitmap + " getBitmap " + request.ID); + if (request.getImageView() != null){ + if (bitmap != null){ + //注意,这里的bitmap已经是压缩了的 + loader.loadImageView(bitmap); } else { - loader.showError(request.errorId); + Log.i("NetLoader", "error " + request.getImageView().getTag().equals(request.uri)); + if (Thread.currentThread().isInterrupted()){ + Log.i("NetLoader", "error by thread intrrupted"); + } else { + loader.showError(request.errorId); + } } + } else { + Log.i("NetLoader", "imageview reference is null!"); } - } else { - Log.i("NetLoader", "imageview reference is null!"); } - } - }); + }); + startLoader.start(); + } else { + Log.i("NetLoaderTest", "load by cache"); + loader.loadImageViewInCache(); + } + } + } - startLoader.start(); + /** + * 根据传入的ImageView来获取callable来判断uri是否相同,防止RecycleView加载错位 + * @param url + * @param imageView + * @return + */ + private boolean cancelBeforeTask(String url, ImageView imageView){ + Map container = getContainer(imageView); + if (container != null){ + Iterator it = container.keySet().iterator(); + BitmapCallback callback = it.next(); + if (callback != null){ + if (callback.getTaskUrl().equals(url)){ + return false; + } else { + container.get(callback).cancel(true); + return true; + } + } + } + return true; + } - } else { - loader.loadImageViewInCache(); + /** + * 如果Task已经完成,那么setBitmap之后,ImageView的drawable会被重新赋值一个Drawable(非ContainerDrawable) + * @param imageview + * @return null 需要重新开始Load, not null传入container去给cancelBeforeTask()函数判断url是否相同 + */ + private Map getContainer(ImageView imageview){ + Drawable drawable = imageview.getDrawable(); + if (drawable instanceof ContainerDrawable){ + Map container = ((ContainerDrawable) drawable).getContainerMap(); + return container; } + return null; } /** diff --git a/easyimageprovider/src/main/java/com/example/zane/easyimageprovider/download/loader/ResourceLoader.java b/easyimageprovider/src/main/java/com/example/zane/easyimageprovider/download/loader/ResourceLoader.java index 2624331..2017ec7 100644 --- a/easyimageprovider/src/main/java/com/example/zane/easyimageprovider/download/loader/ResourceLoader.java +++ b/easyimageprovider/src/main/java/com/example/zane/easyimageprovider/download/loader/ResourceLoader.java @@ -18,7 +18,7 @@ public class ResourceLoader implements ImageLoader{ @Override public void loadImage(BitmapRequest request) { loader = new UIImageViewLoader(request); - loader.showLoading(request.placeHolderId); + loader.showLoading(null, request.placeHolderId); final Context context = EasyImageLoadConfiguration.getInstance().getmApplicationContext(); if (request.uri != null){ diff --git a/easyimageprovider/src/main/java/com/example/zane/easyimageprovider/download/loader/UIImageViewLoader.java b/easyimageprovider/src/main/java/com/example/zane/easyimageprovider/download/loader/UIImageViewLoader.java index e5ef08c..47d415b 100644 --- a/easyimageprovider/src/main/java/com/example/zane/easyimageprovider/download/loader/UIImageViewLoader.java +++ b/easyimageprovider/src/main/java/com/example/zane/easyimageprovider/download/loader/UIImageViewLoader.java @@ -1,6 +1,9 @@ package com.example.zane.easyimageprovider.download.loader; import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.icu.text.LocaleDisplayNames; +import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.os.Message; @@ -8,12 +11,20 @@ import android.util.Log; import android.widget.ImageView; +import com.example.zane.easyimageprovider.download.EasyImageLoadConfiguration; import com.example.zane.easyimageprovider.download.cache.ImageCache; +import com.example.zane.easyimageprovider.download.execute.BitmapCallback; +import com.example.zane.easyimageprovider.download.execute.ContainerDrawable; import com.example.zane.easyimageprovider.download.request.BitmapRequest; +import java.io.Serializable; import java.lang.ref.Reference; import java.lang.ref.SoftReference; import java.lang.ref.WeakReference; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.Callable; +import java.util.concurrent.Future; /** * Created by Zane on 16/9/25. @@ -32,6 +43,9 @@ public class UIImageViewLoader { private static final int ERROR = 3; private static final int LOAD_CACHE = 4; + private static final String LOADING_ID = "loading_id"; + private static final String LOADING_CONTAINER = "loading_container"; + protected UIImageViewLoader(BitmapRequest request) { this.request = request; this.cache = request.cache; @@ -93,10 +107,13 @@ protected void loadImageViewInCache(){ * 加载过程中调用,显示占位图 * @param id */ - protected void showLoading(int id){ + protected void showLoading(Map container, int id){ final Message message = new Message(); + Bundle bundle = new Bundle(); message.what = LOADING; - message.obj = id; + bundle.putInt(LOADING_ID, id); + bundle.putSerializable(LOADING_CONTAINER, (Serializable) container); + message.setData(bundle); handler.sendMessage(message); } @@ -115,16 +132,17 @@ protected void showError(int id){ private final static class LoadHandler extends Handler{ private ImageView imageView; - private SoftReference reference; + private WeakReference reference; private String url; public LoadHandler(BitmapRequest request){ super(Looper.getMainLooper()); - reference = new SoftReference(request); + reference = new WeakReference(request); imageView = reference.get().getImageView(); url = reference.get().uri; } + //loading的时候,将map注入到loading的Drawable里面去 @Override public void handleMessage(Message msg) { if (reference.get() != null){ @@ -134,7 +152,16 @@ public void handleMessage(Message msg) { imageView.setImageBitmap((Bitmap)msg.obj); break; case LOADING: - imageView.setImageResource((int)msg.obj); + Bundle bundle = msg.getData(); + Map container = (HashMap) bundle.getSerializable(LOADING_CONTAINER); + int id = bundle.getInt(LOADING_ID); + if (container != null){ + Bitmap bitmap = BitmapFactory.decodeResource(EasyImageLoadConfiguration.getInstance().getmApplicationContext().getResources(), id); + ContainerDrawable drawable = new ContainerDrawable(EasyImageLoadConfiguration.getInstance().getmApplicationContext().getResources(), bitmap, container); + imageView.setImageDrawable(drawable); + } else { + imageView.setImageResource(id); + } break; case ERROR: imageView.setImageResource((int)msg.obj);