下载图像和更新 listView 时出现问题
Issue in Downloading the Image and Updating the listView
我在下载图像和更新 ImageView 时遇到问题,我正在使用 ExecutorServices 下载图像,但我面临的问题是,就场景而言,我正在使用基本适配器在list.Image 已下载,但两张图片仅在 firstImage View 中更新。
所以位图在同一个图像视图中得到更新,有没有人遇到过类似的问题
例如,我正在下载 2 个图像,它正在创建 2 个 ImageDownloader 实例,所有 运行 都很好,直到 class 行中的 运行()在下载部分之前,一旦下载了图像,我得到了第一个图像下载器 class 的 ImageView 的对象引用,我不确定为什么?我认为它与列表视图或适配器无关,它更多与 Executor 和 运行nable Implementation 相关,
public class ImageLoader {
ExecutorService mExecutorService = null;
static ImageLoader mLoader = null;
Handler mImageHandler = null ;
DisplayMetrics mDisplayMetrics = null;
int mRequiredWidth =0 , mRequiredHeight = 0;
Map<String,ImageView> mToLoadObjects = Collections.synchronizedMap(
new WeakHashMap<String, ImageView>());
ArrayList<String> toloadURL = new ArrayList<String>();
protected Resources mResources = null;
MyImageCache mMemoryCache;
Activity activity;
public static final String LOGGER = "ImageLoader";
public ImageLoader(Activity context){
mExecutorService = Executors.newFixedThreadPool(5);
mImageHandler = new Handler();
mResources = context.getResources();
activity = context;
mMemoryCache = new MyImageCache();
mDisplayMetrics = context.getResources().getDisplayMetrics();
mRequiredWidth = mDisplayMetrics.widthPixels;
mRequiredHeight = mDisplayMetrics.heightPixels;
}
public void loadImage (String url,ImageView imageView){
try {
if (imageView != null) {
if (!toloadURL.contains(url)) {
toloadURL.add(url);
mExecutorService.execute(new ImageDownloader(url,imageView));
}
}
}catch (Exception e){
Log.v("Exception Occurs>>",""+e.getMessage());
}
}
class ImageDownloader implements Runnable{
String imageUrl;
ImageView downloadableImageView;
ImageDownloader loader;
ImageDownloader(String url,ImageView view){
Log.v(LOGGER,"Within ImageDownloader "+url +"this>>>"+this);
loader = this;
imageUrl = url;
downloadableImageView = view;
Log.v(LOGGER,"Within ImageDownloader "+downloadableImageView.getTag()+"this>>>"+this);
}
@Override
public void run() {
Log.v(LOGGER, "run" + downloadableImageView.getTag()+"this>>>>>"+this);
Bitmap tempBitmap = null;
tempBitmap = (mMemoryCache.getBitmapFromMemCache(imageUrl));
try{
if(tempBitmap!=null){
Log.v(LOGGER,"ImageBitmap Wid>>>>>>"+downloadableImageView.getTag()+"this>>>>"+this+""+tempBitmap.getWidth());
Log.v(LOGGER,"ImageBitmap Ht>>>>>>"+downloadableImageView.getTag()+ "this>>>>"+this+""+tempBitmap.getHeight());
downloadableImageView.setImageBitmap(tempBitmap);
}else{
Log.v(LOGGER, "else to download Tag is" + downloadableImageView.getTag()+"this>>>>>"+this);//Works till this point
final Bitmap tempBitmap1 = getBitmap(imageUrl);
Log.v(LOGGER, "else to download Tag is " + downloadableImageView.getTag() + "After Download>>>" + tempBitmap1.getWidth() + "this>>>>>" + this);//Issue happens here
mMemoryCache.addBitmapToMemoryCache(imageUrl, tempBitmap1);
Log.v("LOGGER, else to download Tag is "+downloadableImageView.getTag()+"After Cache>>>", "" + downloadableImageView.getTag()+"this>>>>"+this);
if(tempBitmap1!=null){
activity.runOnUiThread(new Runnable() {
@Override
public void run() {
Log.v("LOGGER, else to download Tag is "+downloadableImageView.getTag()+"RunOnUIThread>>>", "" + downloadableImageView.getTag()+"this>>>>"+loader);
downloadableImageView.setImageBitmap(tempBitmap1);
downloadableImageView.requestLayout();
}
});
}
}
}catch(Exception e){
Log.v("ExceptionBitmap",""+e.getMessage());
}
}
public Bitmap getBitmap(String imageUrl){
Bitmap bitmap=null;
try {
Log.v("Within getBitmap ","run");
URL uri = new URL(imageUrl);
HttpURLConnection connection = (HttpURLConnection)uri.openConnection();
connection.setInstanceFollowRedirects(true);
//bitmap = BitmapFactory.decodeStream(connection.getInputStream());
bitmap = decodeSampledBitmapFromInputStream(connection.getInputStream(), mRequiredWidth, mRequiredHeight);
} catch (Exception e) {
Log.v("ExceptionLoad",""+e.getMessage());
}
return bitmap;
}
}
public Bitmap decodeSampledBitmapFromInputStream(InputStream in
, int reqWidth, int reqHeight) {
InputStream copyiInputStream1 = null;
InputStream copyiInputStream2 = null;
try {
byte[] data = InputStreamTOByte(in);
copyiInputStream1 = byteTOInputStream(data);
copyiInputStream2 = byteTOInputStream(data);
} catch (Exception e) {
e.printStackTrace();
}
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeStream(copyiInputStream1, null, options);
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
return BitmapFactory.decodeStream(copyiInputStream2, null, options);
}
public static int calculateInSampleSize(
BitmapFactory.Options options, int reqWidth, int reqHeight) {
// Raw height and width of image
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
final int halfHeight = height / 2;
final int halfWidth = width / 2;
// Calculate the largest inSampleSize value that is a power of 2 and keeps both
// height and width larger than the requested height and width.
while ((halfHeight / inSampleSize) > reqHeight
&& (halfWidth / inSampleSize) > reqWidth) {
inSampleSize *= 2;
}
}
return inSampleSize;
}
public InputStream byteTOInputStream(byte[] in) throws Exception{
ByteArrayInputStream is = new ByteArrayInputStream(in);
return is;
}
public byte[] InputStreamTOByte(InputStream in) throws IOException {
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
byte[] data = new byte[1024*16];
int count = -1;
while((count = in.read(data,0,1024*16)) != -1)
outStream.write(data, 0, count);
data = null;
return outStream.toByteArray();
}
class BitmapUpdater implements Runnable
{
Bitmap bitmap;
ImageView imageView;
public BitmapUpdater(Bitmap bitmap, ImageView imageView){
bitmap=bitmap;
imageView =imageView;
}
public void run()
{
// Show bitmap on UI
if(bitmap!=null){
activity.runOnUiThread(new Runnable() {
@Override
public void run() {
imageView.setImageBitmap(bitmap);
}
});
}
else
imageView.setImageResource(R.drawable.account_photo_book_detail2);
}
}
}
我附上日志供参考,请帮忙解决这个问题
Image Tag(0,1)--> I applied Tag for ImageView to sort out the Image View instance
线程 1:(ImageDownloader1 线程对象)
04-06 17:05:57.662 20053-20053/com.xxx.xxxxmobileapp V/ImageLoader﹕ImageDownloader内https://lh6.googleusercontent.com/-8HO-4vIFnlw/URquZnsFgtI/AAAAAAAAAbs/WT8jViTF7vw/s1024/Antelope%252520Hallway.jpgthis>>>com.xxx.xxxxmobileapp.Imagebook.network. ImageLoader$ImageDownloader@435058b0
04-06 17:05:57.662 20053-20053/com.xxx.xxxxmobileapp V/ImageLoader﹕ImageDownloader内0(imageViewObjectTag)this>>>com.xxx.xxxxmobileapp.Imagebook.network.ImageLoader$ImageDownloader@
04-06 17:05:57.664 20053-20130/com.xxx.xxxxmobileapp V/ImageLoader:else要下载的Tag是0(imageViewObjectTag)this>>>>>com.xxx.xxxxmobileapp。 Imagebook.network.ImageLoader$ImageDownloader@435058b0
线程 2:((ImageDownloader2 线程对象))
04-06 17:05:57.666 20053-20053/com.xxx.xxxxmobileapp V/ImageLoader﹕ImageDownloader内https://lh5.googleusercontent.com/-7qZeDtRKFKc/URquWZT1gOI/AAAAAAAAAbs/hqWgteyNXsg/s1024/Another%252520Rockaway%252520Sunset.jpgthis>>>com.xxx.xxxxmobileapp.Imagebook.network.图片加载器$ImageDownloader@431a5d58
04-06 17:05:57.666 20053-20053/com.xxx.xxxxmobileapp V/ImageLoader﹕ImageDownloader内1(imageView)this>>>com.xxx.xxxxmobileapp.Imagebook.network.ImageLoader$ImageDownloader@431a5d58
线程 1 和 2 运行 ():
20053-20130/com.xxx.xxxxmobileapp V/ImageLoader﹕ 运行 0(imageViewObjectTag)这个>>>>>com.xxx.xxxxmobileapp.Imagebook.network.ImageLoader$ImageDownloader@435058b0
20053-20131/com.xxx.xxxxmobileapp V/ImageLoader﹕运行 1(imageViewObjectTag)这个>>>>>com.xxx.xxxxmobileapp.Imagebook.network.ImageLoader$ImageDownloader@431a5d58
其他下载标签是1this>>>>>com.xxx.xxxxmobileapp.Imagebook.network.ImageLoader$ImageDownloader@431a5d58
((ImageDownloader1 线程对象)) 下载后:
else to download Tag is 0(imageViewObjectTag)After Download>>>1024this>>>>>com.xxx.xxxxmobileapp.Imagebook.network.ImageLoader$ImageDownloader@435058b0//(ImageDownloader1 Object))
else to download Tag is 0(imageViewObjectTag)After Cache>>>: 0this>>>>com.xxx.xxxxmobileapp.Imagebook.network.ImageLoader$ImageDownloader@435058b0//(ImageDownloader1 Object))
else to download Tag is 0(imageViewObjectTag)运行OnUIThread>>>: 0this>>>>com.xxx.xxxxmobileapp.Imagebook.network.ImageLoader$ImageDownloader@435058b0//(ImageDownloader1 Object))
一切都好到此为止
((ImageDownloader2 线程对象))下载后:
else to download Tag is 0(imageViewObjectTag)After Download>>>1024this>>>>>com.xxx.xxxxmobileapp.Imagebook.network.ImageLoader$ImageDownloader@431a5d58//(ImageDownloader2 Object with ImageView tag coming as 0 不同,应该是 tag1))
else to download Tag is 0(imageViewObjectTag)After Cache>>>: 0this>>>>com.xxx.xxxxmobileapp.Imagebook.network.ImageLoader$ImageDownloader@431a5d58 //(ImageDownloader2 Object with ImageView tag coming as 0 different which should be标签 1))
else to download Tag is 0(imageViewObjectTag)运行OnUIThread>>>: 0this>>>>com.xxx.xxxxmobileapp.Imagebook.network.ImageLoader$ImageDownloader@431a5d58//(ImageDownloader2 Object with ImageView tag coming as 0不同,应该是 tag1))
我认为这是一个回收问题,问题在于下载完成后最初的ImageView
可能代表列表中的另一个位置。您看到问题发生在 getBitmap(imageUrl)
调用之后,但理论上,它也可能更早发生。我不确定你的代码中是否使用了BitmapUpdater
,但乍一看,它与你的情况无关。
因此,为了解决这个问题,您需要实施一种机制来避免 ImageView
被更新为 "old" 位图。您可以使用 ImageView
的 tag
属性 来保存实际需要显示的 URL。如果图片的 tag
中的 URL 与实际用于下载的不同,则缓存图片即可。你可以做类似
的事情
public void loadImage (String url,ImageView imageView){
if(imageView != null) imageView.setTag(url);
[...]
}
和
if(tempBitmap1!=null){
activity.runOnUiThread(new Runnable() {
@Override
public void run() {
Log.v("LOGGER, else to download Tag is " + downloadableImageView.getTag()+"RunOnUIThread>>>", "" + downloadableImageView.getTag()+"this>>>>"+loader);
if(downloadableImageView.getTag().equals(imageUrl) {
downloadableImageView.setImageBitmap(tempBitmap1);
}
else Log.v(LOGGER, "the image no longer wants this URL, ignoring");
//downloadableImageView.requestLayout();
}
});
}
此外,我建议避免 downloadableImageView.requestLayout();
,因为它会导致测量整个布局,而在您的情况下,则不需要。
图片下载为什么不用Glide库?
它在一行中完成所有事情。
这是它的语法
Glide.with(context).load(URL).into(Imageview);
是的,最后我通过我的朋友解决了这个问题arunkumar
向他致敬:)
我尝试了两件事,
1) 找出问题出在列表视图或执行程序服务 implementation.To 发现我用线性布局替换了列表视图并添加为成功工作的视图,这确认问题出在列表视图而不是执行器服务实现。
2) 图像在第一个图像中更新的真正问题是因为视图 ID(ImageView.getID()) 相同,
我设置了 ID 而不是设置标签,我将 ID 传递给图像加载器 class,我通过 findViewById(SetID) 检索了图像,这有效
我正在添加一些有用的代码
用于在适配器中设置 ID class:
final ImageView imageView = holder.jobImageView;
holder.jobImageView.setId(position);
loader.loadImage(object.getlargeImageUrl(),holder.jobImageView,position);
获取适配器中的 ID class:
final Bitmap tempBitmap1 = getBitmap(imageUrl);
Log.v(LOGGER, "else to download Tag is " +imageViewId + "After Download>>>" + tempBitmap1.getWidth() + "this>>>>>" + this);
mMemoryCache.addBitmapToMemoryCache(imageUrl, tempBitmap1);
downloadableImageView = (ImageView)activity.findViewById(imageViewId);
Log.v("LOGGER, else to download Tag is "+downloadableImageView.getTag()+"After Cache>>>", "" + downloadableImageView.getTag()+"this>>>>"+this);
if(tempBitmap1!=null){
activity.runOnUiThread(new Runnable() {
@Override
public void run() {
Log.v("LOGGER, else to download Tag is " + downloadableImageView.getTag() + "RunOnUIThread>>>", "" + downloadableImageView.getTag() + "this>>>>" + loader);
downloadableImageView.setImageBitmap(tempBitmap1);
//downloadableImageView.requestLayout();
}
});
}
可以使用毕加索图片加载库
Link 用于 Picasso
的文档
像解码本地存储或在线流中的大位图这样繁重的工作,我们必须在工作线程中完成,问题是解码完成后,imageview 已被回收。解决它:
// In your adapter (onCreateView)
bitmap = yourBitmapCache.get(position);
if (bitmap != null)
yourImageView.setImageBitmap(bitmap);
else if (imageLoaderManager.isLoading.get(position) == false){
imagerLoaderManager.load(position, url);
}
// Create Callback interface
interface Callback {
void onFinishLoad(int position, Bitmap bm);
}
// Create inner class ImageLoaderManager
class ImageLoaderManager {
Hasmap<Integer, Boolean> isLoading = new Hasmap<>();
Callback callback = new Callback() {
@Override
void onFinishLoad(int position, Bitmap bitmap){
isLoading.put(position, false);
if (bitmap != null) {
yourBitmapCache.put(position, bitmap)
activity.runOnUiThread(new Runnable() {
@Override
public void run(){
notifyDataSetInvalidated();
// If you use recycler view adapter: notifyItemChanged(position)
}
});
}
}
};
public void load(int position, String url){
isLoading.put(position, true);
newYourImageLoader(url, position, callback).start();
// when loader finish job,
// it's must call back using callback.onFinishLoad(given position, bitmap result);
}
}
无需在我的解决方案中保留 ImageView
引用。请记住 position
并要求适配器在解码任务完成后重新加载此位置的项目视图,现在位图已经存在于 yourBitmapCache
.
我在下载图像和更新 ImageView 时遇到问题,我正在使用 ExecutorServices 下载图像,但我面临的问题是,就场景而言,我正在使用基本适配器在list.Image 已下载,但两张图片仅在 firstImage View 中更新。
所以位图在同一个图像视图中得到更新,有没有人遇到过类似的问题
例如,我正在下载 2 个图像,它正在创建 2 个 ImageDownloader 实例,所有 运行 都很好,直到 class 行中的 运行()在下载部分之前,一旦下载了图像,我得到了第一个图像下载器 class 的 ImageView 的对象引用,我不确定为什么?我认为它与列表视图或适配器无关,它更多与 Executor 和 运行nable Implementation 相关,
public class ImageLoader {
ExecutorService mExecutorService = null;
static ImageLoader mLoader = null;
Handler mImageHandler = null ;
DisplayMetrics mDisplayMetrics = null;
int mRequiredWidth =0 , mRequiredHeight = 0;
Map<String,ImageView> mToLoadObjects = Collections.synchronizedMap(
new WeakHashMap<String, ImageView>());
ArrayList<String> toloadURL = new ArrayList<String>();
protected Resources mResources = null;
MyImageCache mMemoryCache;
Activity activity;
public static final String LOGGER = "ImageLoader";
public ImageLoader(Activity context){
mExecutorService = Executors.newFixedThreadPool(5);
mImageHandler = new Handler();
mResources = context.getResources();
activity = context;
mMemoryCache = new MyImageCache();
mDisplayMetrics = context.getResources().getDisplayMetrics();
mRequiredWidth = mDisplayMetrics.widthPixels;
mRequiredHeight = mDisplayMetrics.heightPixels;
}
public void loadImage (String url,ImageView imageView){
try {
if (imageView != null) {
if (!toloadURL.contains(url)) {
toloadURL.add(url);
mExecutorService.execute(new ImageDownloader(url,imageView));
}
}
}catch (Exception e){
Log.v("Exception Occurs>>",""+e.getMessage());
}
}
class ImageDownloader implements Runnable{
String imageUrl;
ImageView downloadableImageView;
ImageDownloader loader;
ImageDownloader(String url,ImageView view){
Log.v(LOGGER,"Within ImageDownloader "+url +"this>>>"+this);
loader = this;
imageUrl = url;
downloadableImageView = view;
Log.v(LOGGER,"Within ImageDownloader "+downloadableImageView.getTag()+"this>>>"+this);
}
@Override
public void run() {
Log.v(LOGGER, "run" + downloadableImageView.getTag()+"this>>>>>"+this);
Bitmap tempBitmap = null;
tempBitmap = (mMemoryCache.getBitmapFromMemCache(imageUrl));
try{
if(tempBitmap!=null){
Log.v(LOGGER,"ImageBitmap Wid>>>>>>"+downloadableImageView.getTag()+"this>>>>"+this+""+tempBitmap.getWidth());
Log.v(LOGGER,"ImageBitmap Ht>>>>>>"+downloadableImageView.getTag()+ "this>>>>"+this+""+tempBitmap.getHeight());
downloadableImageView.setImageBitmap(tempBitmap);
}else{
Log.v(LOGGER, "else to download Tag is" + downloadableImageView.getTag()+"this>>>>>"+this);//Works till this point
final Bitmap tempBitmap1 = getBitmap(imageUrl);
Log.v(LOGGER, "else to download Tag is " + downloadableImageView.getTag() + "After Download>>>" + tempBitmap1.getWidth() + "this>>>>>" + this);//Issue happens here
mMemoryCache.addBitmapToMemoryCache(imageUrl, tempBitmap1);
Log.v("LOGGER, else to download Tag is "+downloadableImageView.getTag()+"After Cache>>>", "" + downloadableImageView.getTag()+"this>>>>"+this);
if(tempBitmap1!=null){
activity.runOnUiThread(new Runnable() {
@Override
public void run() {
Log.v("LOGGER, else to download Tag is "+downloadableImageView.getTag()+"RunOnUIThread>>>", "" + downloadableImageView.getTag()+"this>>>>"+loader);
downloadableImageView.setImageBitmap(tempBitmap1);
downloadableImageView.requestLayout();
}
});
}
}
}catch(Exception e){
Log.v("ExceptionBitmap",""+e.getMessage());
}
}
public Bitmap getBitmap(String imageUrl){
Bitmap bitmap=null;
try {
Log.v("Within getBitmap ","run");
URL uri = new URL(imageUrl);
HttpURLConnection connection = (HttpURLConnection)uri.openConnection();
connection.setInstanceFollowRedirects(true);
//bitmap = BitmapFactory.decodeStream(connection.getInputStream());
bitmap = decodeSampledBitmapFromInputStream(connection.getInputStream(), mRequiredWidth, mRequiredHeight);
} catch (Exception e) {
Log.v("ExceptionLoad",""+e.getMessage());
}
return bitmap;
}
}
public Bitmap decodeSampledBitmapFromInputStream(InputStream in
, int reqWidth, int reqHeight) {
InputStream copyiInputStream1 = null;
InputStream copyiInputStream2 = null;
try {
byte[] data = InputStreamTOByte(in);
copyiInputStream1 = byteTOInputStream(data);
copyiInputStream2 = byteTOInputStream(data);
} catch (Exception e) {
e.printStackTrace();
}
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeStream(copyiInputStream1, null, options);
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
return BitmapFactory.decodeStream(copyiInputStream2, null, options);
}
public static int calculateInSampleSize(
BitmapFactory.Options options, int reqWidth, int reqHeight) {
// Raw height and width of image
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
final int halfHeight = height / 2;
final int halfWidth = width / 2;
// Calculate the largest inSampleSize value that is a power of 2 and keeps both
// height and width larger than the requested height and width.
while ((halfHeight / inSampleSize) > reqHeight
&& (halfWidth / inSampleSize) > reqWidth) {
inSampleSize *= 2;
}
}
return inSampleSize;
}
public InputStream byteTOInputStream(byte[] in) throws Exception{
ByteArrayInputStream is = new ByteArrayInputStream(in);
return is;
}
public byte[] InputStreamTOByte(InputStream in) throws IOException {
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
byte[] data = new byte[1024*16];
int count = -1;
while((count = in.read(data,0,1024*16)) != -1)
outStream.write(data, 0, count);
data = null;
return outStream.toByteArray();
}
class BitmapUpdater implements Runnable
{
Bitmap bitmap;
ImageView imageView;
public BitmapUpdater(Bitmap bitmap, ImageView imageView){
bitmap=bitmap;
imageView =imageView;
}
public void run()
{
// Show bitmap on UI
if(bitmap!=null){
activity.runOnUiThread(new Runnable() {
@Override
public void run() {
imageView.setImageBitmap(bitmap);
}
});
}
else
imageView.setImageResource(R.drawable.account_photo_book_detail2);
}
}
}
我附上日志供参考,请帮忙解决这个问题
Image Tag(0,1)--> I applied Tag for ImageView to sort out the Image View instance
线程 1:(ImageDownloader1 线程对象)
04-06 17:05:57.662 20053-20053/com.xxx.xxxxmobileapp V/ImageLoader﹕ImageDownloader内https://lh6.googleusercontent.com/-8HO-4vIFnlw/URquZnsFgtI/AAAAAAAAAbs/WT8jViTF7vw/s1024/Antelope%252520Hallway.jpgthis>>>com.xxx.xxxxmobileapp.Imagebook.network. ImageLoader$ImageDownloader@435058b0 04-06 17:05:57.662 20053-20053/com.xxx.xxxxmobileapp V/ImageLoader﹕ImageDownloader内0(imageViewObjectTag)this>>>com.xxx.xxxxmobileapp.Imagebook.network.ImageLoader$ImageDownloader@
04-06 17:05:57.664 20053-20130/com.xxx.xxxxmobileapp V/ImageLoader:else要下载的Tag是0(imageViewObjectTag)this>>>>>com.xxx.xxxxmobileapp。 Imagebook.network.ImageLoader$ImageDownloader@435058b0
线程 2:((ImageDownloader2 线程对象))
04-06 17:05:57.666 20053-20053/com.xxx.xxxxmobileapp V/ImageLoader﹕ImageDownloader内https://lh5.googleusercontent.com/-7qZeDtRKFKc/URquWZT1gOI/AAAAAAAAAbs/hqWgteyNXsg/s1024/Another%252520Rockaway%252520Sunset.jpgthis>>>com.xxx.xxxxmobileapp.Imagebook.network.图片加载器$ImageDownloader@431a5d58 04-06 17:05:57.666 20053-20053/com.xxx.xxxxmobileapp V/ImageLoader﹕ImageDownloader内1(imageView)this>>>com.xxx.xxxxmobileapp.Imagebook.network.ImageLoader$ImageDownloader@431a5d58
线程 1 和 2 运行 ():
20053-20130/com.xxx.xxxxmobileapp V/ImageLoader﹕ 运行 0(imageViewObjectTag)这个>>>>>com.xxx.xxxxmobileapp.Imagebook.network.ImageLoader$ImageDownloader@435058b0 20053-20131/com.xxx.xxxxmobileapp V/ImageLoader﹕运行 1(imageViewObjectTag)这个>>>>>com.xxx.xxxxmobileapp.Imagebook.network.ImageLoader$ImageDownloader@431a5d58
其他下载标签是1this>>>>>com.xxx.xxxxmobileapp.Imagebook.network.ImageLoader$ImageDownloader@431a5d58
((ImageDownloader1 线程对象)) 下载后:
else to download Tag is 0(imageViewObjectTag)After Download>>>1024this>>>>>com.xxx.xxxxmobileapp.Imagebook.network.ImageLoader$ImageDownloader@435058b0//(ImageDownloader1 Object)) else to download Tag is 0(imageViewObjectTag)After Cache>>>: 0this>>>>com.xxx.xxxxmobileapp.Imagebook.network.ImageLoader$ImageDownloader@435058b0//(ImageDownloader1 Object)) else to download Tag is 0(imageViewObjectTag)运行OnUIThread>>>: 0this>>>>com.xxx.xxxxmobileapp.Imagebook.network.ImageLoader$ImageDownloader@435058b0//(ImageDownloader1 Object))
一切都好到此为止
((ImageDownloader2 线程对象))下载后:
else to download Tag is 0(imageViewObjectTag)After Download>>>1024this>>>>>com.xxx.xxxxmobileapp.Imagebook.network.ImageLoader$ImageDownloader@431a5d58//(ImageDownloader2 Object with ImageView tag coming as 0 不同,应该是 tag1)) else to download Tag is 0(imageViewObjectTag)After Cache>>>: 0this>>>>com.xxx.xxxxmobileapp.Imagebook.network.ImageLoader$ImageDownloader@431a5d58 //(ImageDownloader2 Object with ImageView tag coming as 0 different which should be标签 1)) else to download Tag is 0(imageViewObjectTag)运行OnUIThread>>>: 0this>>>>com.xxx.xxxxmobileapp.Imagebook.network.ImageLoader$ImageDownloader@431a5d58//(ImageDownloader2 Object with ImageView tag coming as 0不同,应该是 tag1))
我认为这是一个回收问题,问题在于下载完成后最初的ImageView
可能代表列表中的另一个位置。您看到问题发生在 getBitmap(imageUrl)
调用之后,但理论上,它也可能更早发生。我不确定你的代码中是否使用了BitmapUpdater
,但乍一看,它与你的情况无关。
因此,为了解决这个问题,您需要实施一种机制来避免 ImageView
被更新为 "old" 位图。您可以使用 ImageView
的 tag
属性 来保存实际需要显示的 URL。如果图片的 tag
中的 URL 与实际用于下载的不同,则缓存图片即可。你可以做类似
public void loadImage (String url,ImageView imageView){
if(imageView != null) imageView.setTag(url);
[...]
}
和
if(tempBitmap1!=null){
activity.runOnUiThread(new Runnable() {
@Override
public void run() {
Log.v("LOGGER, else to download Tag is " + downloadableImageView.getTag()+"RunOnUIThread>>>", "" + downloadableImageView.getTag()+"this>>>>"+loader);
if(downloadableImageView.getTag().equals(imageUrl) {
downloadableImageView.setImageBitmap(tempBitmap1);
}
else Log.v(LOGGER, "the image no longer wants this URL, ignoring");
//downloadableImageView.requestLayout();
}
});
}
此外,我建议避免 downloadableImageView.requestLayout();
,因为它会导致测量整个布局,而在您的情况下,则不需要。
图片下载为什么不用Glide库?
它在一行中完成所有事情。
这是它的语法
Glide.with(context).load(URL).into(Imageview);
是的,最后我通过我的朋友解决了这个问题arunkumar
向他致敬:)
我尝试了两件事,
1) 找出问题出在列表视图或执行程序服务 implementation.To 发现我用线性布局替换了列表视图并添加为成功工作的视图,这确认问题出在列表视图而不是执行器服务实现。
2) 图像在第一个图像中更新的真正问题是因为视图 ID(ImageView.getID()) 相同,
我设置了 ID 而不是设置标签,我将 ID 传递给图像加载器 class,我通过 findViewById(SetID) 检索了图像,这有效
我正在添加一些有用的代码
用于在适配器中设置 ID class:
final ImageView imageView = holder.jobImageView;
holder.jobImageView.setId(position);
loader.loadImage(object.getlargeImageUrl(),holder.jobImageView,position);
获取适配器中的 ID class:
final Bitmap tempBitmap1 = getBitmap(imageUrl);
Log.v(LOGGER, "else to download Tag is " +imageViewId + "After Download>>>" + tempBitmap1.getWidth() + "this>>>>>" + this);
mMemoryCache.addBitmapToMemoryCache(imageUrl, tempBitmap1);
downloadableImageView = (ImageView)activity.findViewById(imageViewId);
Log.v("LOGGER, else to download Tag is "+downloadableImageView.getTag()+"After Cache>>>", "" + downloadableImageView.getTag()+"this>>>>"+this);
if(tempBitmap1!=null){
activity.runOnUiThread(new Runnable() {
@Override
public void run() {
Log.v("LOGGER, else to download Tag is " + downloadableImageView.getTag() + "RunOnUIThread>>>", "" + downloadableImageView.getTag() + "this>>>>" + loader);
downloadableImageView.setImageBitmap(tempBitmap1);
//downloadableImageView.requestLayout();
}
});
}
可以使用毕加索图片加载库
Link 用于 Picasso
像解码本地存储或在线流中的大位图这样繁重的工作,我们必须在工作线程中完成,问题是解码完成后,imageview 已被回收。解决它:
// In your adapter (onCreateView)
bitmap = yourBitmapCache.get(position);
if (bitmap != null)
yourImageView.setImageBitmap(bitmap);
else if (imageLoaderManager.isLoading.get(position) == false){
imagerLoaderManager.load(position, url);
}
// Create Callback interface
interface Callback {
void onFinishLoad(int position, Bitmap bm);
}
// Create inner class ImageLoaderManager
class ImageLoaderManager {
Hasmap<Integer, Boolean> isLoading = new Hasmap<>();
Callback callback = new Callback() {
@Override
void onFinishLoad(int position, Bitmap bitmap){
isLoading.put(position, false);
if (bitmap != null) {
yourBitmapCache.put(position, bitmap)
activity.runOnUiThread(new Runnable() {
@Override
public void run(){
notifyDataSetInvalidated();
// If you use recycler view adapter: notifyItemChanged(position)
}
});
}
}
};
public void load(int position, String url){
isLoading.put(position, true);
newYourImageLoader(url, position, callback).start();
// when loader finish job,
// it's must call back using callback.onFinishLoad(given position, bitmap result);
}
}
无需在我的解决方案中保留 ImageView
引用。请记住 position
并要求适配器在解码任务完成后重新加载此位置的项目视图,现在位图已经存在于 yourBitmapCache
.