Skip to content

Commit

Permalink
解决RecycleView加载错位的bug
Browse files Browse the repository at this point in the history
  • Loading branch information
Zane96 committed Oct 17, 2016
1 parent 39c963a commit afd5417
Show file tree
Hide file tree
Showing 6 changed files with 136 additions and 48 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}
Original file line number Diff line number Diff line change
@@ -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;

Expand All @@ -20,13 +22,14 @@

public class ContainerDrawable extends BitmapDrawable{

private Reference<Map<Callable, Future>> container;
private Reference<Map<BitmapCallback, Future>> container;

public ContainerDrawable(Map<Callable, Future> containerMap){
container = new WeakReference<Map<Callable, Future>>(containerMap);
public ContainerDrawable(Resources resources, Bitmap bitmap, Map<BitmapCallback, Future> containerMap){
super(resources, bitmap);
container = new WeakReference<Map<BitmapCallback, Future>>(containerMap);
}

public Map<Callable, Future> getContainerMap(){
public Map<BitmapCallback, Future> getContainerMap(){
return container.get();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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()) {
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -30,9 +38,11 @@ public class NetLoader implements ImageLoader{
private UIImageViewLoader loader;

private Thread startLoader;
private Map<BitmapCallback, Future> container;

public NetLoader(ThreadPoolExecutor executorService){
executor = executorService;
container = new HashMap<>();
}

@Override
Expand All @@ -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<BitmapCallback, Future> container = getContainer(imageView);
if (container != null){
Iterator<BitmapCallback> 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<BitmapCallback, Future> getContainer(ImageView imageview){
Drawable drawable = imageview.getDrawable();
if (drawable instanceof ContainerDrawable){
Map<BitmapCallback, Future> container = ((ContainerDrawable) drawable).getContainerMap();
return container;
}
return null;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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){
Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,30 @@
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;
import android.support.annotation.MainThread;
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.
Expand All @@ -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;
Expand Down Expand Up @@ -93,10 +107,13 @@ protected void loadImageViewInCache(){
* 加载过程中调用,显示占位图
* @param id
*/
protected void showLoading(int id){
protected void showLoading(Map<BitmapCallback, Future> 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);
}

Expand All @@ -115,16 +132,17 @@ protected void showError(int id){
private final static class LoadHandler extends Handler{

private ImageView imageView;
private SoftReference<BitmapRequest> reference;
private WeakReference<BitmapRequest> reference;
private String url;

public LoadHandler(BitmapRequest request){
super(Looper.getMainLooper());
reference = new SoftReference<BitmapRequest>(request);
reference = new WeakReference<BitmapRequest>(request);
imageView = reference.get().getImageView();
url = reference.get().uri;
}

//loading的时候,将map<Callable, Future>注入到loading的Drawable里面去
@Override
public void handleMessage(Message msg) {
if (reference.get() != null){
Expand All @@ -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<BitmapCallback, Future> container = (HashMap<BitmapCallback, Future>) 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);
Expand Down

0 comments on commit afd5417

Please sign in to comment.