【问题标题】:Issue in Downloading the Image and Updating the listView下载图像和更新 listView 的问题
【发布时间】:2016-07-26 05:52:15
【问题描述】:

我在下载图像和更新 ImageView 时遇到问题,我正在使用 ExecutorServices 下载图像,但我面临的问题是,就场景而言,我正在使用基本适配器在列表中显示 Imageview。图像已下载,但两个图像仅在 firstImage 视图中更新。

所以 Bitmap 在同一个 imageView 中得到更新,有没有人遇到过类似的问题

例如,我正在下载 2 个图像,它正在创建 2 个 ImageDownloader 实例,所有运行良好,直到下载部分之前该类的 Run() 行,一旦图像被下载,我得到对象引用First Image Downloader类的ImageView,不知道为什么?我觉得跟listview或者adapter没有什么关系,更多的是跟Executor和Runnable Implementation有关,

公共类 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 to download Tag is0(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.ImageLoader$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)this>>>>>com.xxx.xxxxmobileapp.Imagebook.network.ImageLoader$ImageDownloader@435058b0 20053-20131/com.xxx.xxxxmobileapp V/ImageLoader:运行 1(imageViewObjectTag)this>>>>>com.xxx.xxxxmobileapp.Imagebook.network.ImageLoader$ImageDownloader@431a5d58

else to download Tag is1this>>>>>com.xxx.xxxxmobileapp.Imagebook.network.ImageLoader$ImageDownloader@431a5d58

((ImageDownloader1 Thread Object)) 下载后:

else to download Tag is 0(imageViewObjectTag)下载后>>>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)RunOnUIThread>>>: 0this>>>>com.xxx.xxxxmobileapp.Imagebook.network.ImageLoader$ImageDownloader@435058b0//(ImageDownloader1 Object))

到现在为止都还好

((ImageDownloader2 Thread Object))下载后:

else to download Tag is 0(imageViewObjectTag)After Download>>>1024this>>>>>com.xxx.xxxxmobileapp.Imagebook.network.ImageLoader$ImageDownloader@431a5d58//(ImageDownloader2 Object with ImageView tag come as 0 different这应该是标签1)) else to download Tag is 0(imageViewObjectTag)After Cache>>>: 0this>>>>com.xxx.xxxxmobileapp.Imagebook.network.ImageLoader$ImageDownloader@431a5d58 //(ImageDownloader2 Object with ImageView tag come as 0 different which should be标签1)) else to download Tag is 0(imageViewObjectTag)RunOnUIThread>>>: 0this>>>>com.xxx.xxxxmobileapp.Imagebook.network.ImageLoader$ImageDownloader@431a5d58//(ImageDownloader2 Object with ImageView tag 作为0不同应该是tag1 ))

【问题讨论】:

  • 我觉得问题是传递给网络加载器类的引用是相同的 - 不,我不这么认为,因为你通过了 holder.testImageView ,一定是别的东西。
  • 如何发送不同的图像视图,或者正确的做法是什么
  • @Rakesh 我的朋友,你为什么不能使用通用图像加载器来下载你的图像?我使用它,我的使用 baseAdapter 的列表视图得到了很好的更新,就像没人做生意一样

标签: android listview runnable executorservice


【解决方案1】:

是的,最后我通过我的朋友arunkumar解决了这个问题

向他致敬:)

我尝试了两件事,

1) 找出问题出在列表视图或执行器服务实现上。找出我用线性布局替换列表视图并添加为成功工作的视图,确认问题出在列表视图而不是执行器服务实现。

2) 图像在第一张图片中更新的真正问题是因为视图 ​​ID(ImageView.getID()) 相同,

我设置了 ID 而不是设置标签,我将 id 传递给图像加载器类,我通过 findViewById(SetID) 检索图像,它起作用了

我正在添加一些有用的代码

用于在适配器类中设置 ID:

 final ImageView imageView = holder.jobImageView;
       holder.jobImageView.setId(position);
       loader.loadImage(object.getlargeImageUrl(),holder.jobImageView,position);

获取适配器类的ID:

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();
                        }
                    });
                }

【讨论】:

    【解决方案2】:

    像解码本地存储或在线流中的大型位图这样繁重的工作,我们必须在工作线程中进行,问题是解码完成后,图像视图已被回收。解决它:

    // 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中。

    【讨论】:

      【解决方案3】:

      您可以使用毕加索图片加载库。
      Picasso的文档链接

      【讨论】:

        【解决方案4】:

        为什么不使用 Glide 库进行图片下载?

        它在一行中完成所有事情。

        这是它的语法

        Glide.with(context).load(URL).into(Imageview);
        

        【讨论】:

          【解决方案5】:

          我认为这是一个回收问题,问题是最初的ImageView,在下载完成后,可能代表列表中的另一个位置。您会看到问题是在getBitmap(imageUrl) 调用之后发生的,但从理论上讲,它也可能更早发生。我不确定您的代码中是否使用了BitmapUpdater,但乍一看,它与您的情况无关。

          所以为了解决这个问题,您需要实现一种机制来避免ImageView 被“旧”位图更新。您可以使用ImageViewtag 属性来保存需要显示的实际URL。如果图片tag中的URL与实际用于下载的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();,因为它会导致整个布局被测量,而在你的情况下,它是不需要的。

          【讨论】:

          • 嗨安娜,这也没有结果,只更新了第一个imageView,没有解决问题
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2023-03-05
          • 2010-11-27
          • 2016-04-30
          • 1970-01-01
          • 2021-10-02
          相关资源
          最近更新 更多