2015-05-19 7 views
8

Ben yarım gün bir cevap arıyorum, ancak ortak bir sorun olduğunu düşündüm rağmen bir şey bulamıyorum. Benim Sorunum: Farklı boyutlarda (yükseklik) öğeler içeren bir ListView var. Her öğe bir ImageView içerir. Bu ImageView için Görüntü bir ImageLoader sınıfı tarafından arka planda yüklenir:ListView - ImageLoader hamle List/Items on Scroll up

imageLoader.DisplayImage(url, holder.image); 

i ListView her şey çalışıyor aşağı kaydırarak. görüntüler yüklenir ve görüntülenir (elbette ekranın/listenin en altında).

Ama yukarı kaydırıp görüntü artık önbellekte saklanmıyorsa, ImageLoader görüntüyü yeniden yüklemelidir, ListView atlar/öğeler taşınır. Bunun sebebi, 0d'un 0dp yüksekliğine sahip ImageView ile listenin en üstünde oluşturulduğudur. Resim yüklendiyse ve ImageView olarak ayarlanmışsa, ImageView'un yüksekliği, 0dp'den görüntünün boyutuna otomatik olarak değişir. Bu, ListView'u aşağıya itecektir, bence.

Görüntü ayarlanmışsa, ImageViews yüksekliğini kaydetmeyi denedim ve sonra kaydedilen yüksekliğin üstüne oluşturulan ImageView yüksekliğini ayarlayın. Ama hiçbir başarı ile ..

sorunumu anlayabiliyorsanız bilmiyorum

: D :) böylece

Teşekkür umut ve güzel bir gün!

DÜZENLEME: Eklenen DÜZENLEME

public class ImageLoader { 

MemoryCache memoryCache=new MemoryCache(); 
FileCache fileCache; 
int size; 
Context context; 
private Map<ImageView, String> imageViews=Collections.synchronizedMap(new WeakHashMap<ImageView, String>()); 
private HashMap<String, Integer> imagesSizes; 
ExecutorService executorService; 
Handler handler=new Handler();//handler to display images in UI thread 

public ImageLoader(Context context, int size){ 
    fileCache=new FileCache(context); 
    this.context = context; 
    executorService=Executors.newFixedThreadPool(5); 
    this.size = size; 
    imagesSizes = new HashMap<String, Integer>(); 
} 

final int stub_id=R.color.transparent; 
public void DisplayImage(String url, ImageView imageView) 
{ 
    imageViews.put(imageView, url); 
    Bitmap bitmap=memoryCache.get(url); 
    if(bitmap!=null){ 
     imageView.setImageBitmap(bitmap); 
     saveImageSize(imageView, url); 
    } 
    else 
    { 
     queuePhoto(url, imageView); 
     imageView.setImageResource(stub_id); 
     setImageSize(imageView, url); 
    } 
} 

public void DisplayImage(File file, ImageView imageView) 
{ 
    imageViews.put(imageView, file.getAbsolutePath()); 
    Bitmap bitmap=memoryCache.get(file.getAbsolutePath()); 
    if(bitmap!=null){ 
     imageView.setImageBitmap(bitmap); 
     saveImageSize(imageView, file.getAbsolutePath()); 
    } 
    else 
    { 
     queuePhoto(file, imageView); 
     imageView.setImageResource(stub_id); 
     setImageSize(imageView, file.getAbsolutePath()); 
    } 
} 

private void saveImageSize(ImageView imageView, String url){ 

    int height = imageView.getHeight(); 
    imagesSizes.put(url, height); 
    System.out.println("IMAGE SIZE: Save: " + url + " " + height); 
} 

private void setImageSize(ImageView imageView, String url){ 
    if(imageView != null && imagesSizes!=null && imagesSizes.containsKey(url)){ 
     imageView.getLayoutParams().height = imagesSizes.get(url); 
     imageView.requestLayout(); 
     System.out.println("IMAGE SIZE: Set: " + url + " " + imagesSizes.get(url)); 
    } 
} 


private void queuePhoto(String url, ImageView imageView) 
{ 
    PhotoToLoad p=new PhotoToLoad(url, imageView); 
    executorService.submit(new PhotosLoader(p)); 
} 

private void queuePhoto(File file, ImageView imageView) 
{ 
    PhotoToLoad p=new PhotoToLoad(file, imageView); 
    executorService.submit(new PhotosLoader(p)); 
} 

public Bitmap getImage(String url){ 
    return getBitmap(url); 
} 

private Bitmap getBitmap(String url) 
{ 
    File f=fileCache.getFile(url); 

    //from SD cache 
    Bitmap b = decodeFile(f); 
    if(b!=null) 
     return b; 

    //from web 
    try { 
     Bitmap bitmap=null; 
     URL imageUrl = new URL(url); 
     HttpURLConnection conn = (HttpURLConnection)imageUrl.openConnection(); 
     conn.setConnectTimeout(30000); 
     conn.setReadTimeout(30000); 
     conn.setInstanceFollowRedirects(true); 
     InputStream is=conn.getInputStream(); 
     OutputStream os = new FileOutputStream(f); 
     Utils.CopyStream(is, os); 
     os.close(); 
     conn.disconnect(); 
     bitmap = decodeFile(f); 
     return bitmap; 
    } catch (Throwable ex){ 
     ex.printStackTrace(); 
     if(ex instanceof OutOfMemoryError) 
      memoryCache.clear(); 
     return null; 
    } 
} 

//decodes image and scales it to reduce memory consumption 
private Bitmap decodeFile(File f){ 
    try { 
     //decode image size 
     BitmapFactory.Options o = new BitmapFactory.Options(); 
     o.inJustDecodeBounds = true; 
     FileInputStream stream1=new FileInputStream(f); 
     BitmapFactory.decodeStream(stream1,null,o); 
     stream1.close(); 

     //Find the correct scale value. It should be the power of 2. 
     final int REQUIRED_SIZE=size; 
     int width_tmp=o.outWidth, height_tmp=o.outHeight; 
     int scale=1; 
     while(true){ 
      if(width_tmp/2<REQUIRED_SIZE || height_tmp/2<REQUIRED_SIZE) 
       break; 
      width_tmp/=2; 
      height_tmp/=2; 
      scale*=2; 
     } 

     //decode with inSampleSize 
     BitmapFactory.Options o2 = new BitmapFactory.Options(); 
     o2.inSampleSize=scale; 
     FileInputStream stream2=new FileInputStream(f); 
     Bitmap bitmap=BitmapFactory.decodeStream(stream2, null, o2); 
     stream2.close(); 
     return bitmap; 
    } catch (FileNotFoundException e) { 
    } 
    catch (IOException e) { 
     e.printStackTrace(); 
    } 
    return null; 
} 

//Task for the queue 
private class PhotoToLoad 
{ 
    public File file; 
    public String url; 
    public ImageView imageView; 
    public PhotoToLoad(String u, ImageView i){ 
     url=u; 
     imageView=i; 
     file = null; 
    } 

    public PhotoToLoad(File file, ImageView i){ 
     url=file.getAbsolutePath(); 
     imageView=i; 
     this.file = file; 
    } 
} 

class PhotosLoader implements Runnable { 
    PhotoToLoad photoToLoad; 
    PhotosLoader(PhotoToLoad photoToLoad){ 
     this.photoToLoad=photoToLoad; 
    } 

    @Override 
    public void run() { 
     try{ 
      if(imageViewReused(photoToLoad)) 
       return; 
      Bitmap bmp; 
      if(photoToLoad.file== null){ 
       bmp=getBitmap(photoToLoad.url); 
      } else { 
       bmp=decodeFile(photoToLoad.file); 
      } 
      memoryCache.put(photoToLoad.url, bmp); 
      if(imageViewReused(photoToLoad)) 
       return; 
      BitmapDisplayer bd=new BitmapDisplayer(bmp, photoToLoad); 
      handler.post(bd); 
     }catch(Throwable th){ 
      th.printStackTrace(); 
     } 
    } 
} 

boolean imageViewReused(PhotoToLoad photoToLoad){ 
    String tag=imageViews.get(photoToLoad.imageView); 
    if(tag==null || !tag.equals(photoToLoad.url)) 
     return true; 
    return false; 
} 

//Used to display bitmap in the UI thread 
class BitmapDisplayer implements Runnable 
{ 
    Bitmap bitmap; 
    PhotoToLoad photoToLoad; 
    public BitmapDisplayer(Bitmap b, PhotoToLoad p){bitmap=b;photoToLoad=p;} 
    public void run() 
    { 
     if(imageViewReused(photoToLoad)) 
      return; 
     if(bitmap!=null) 
      photoToLoad.imageView.setImageBitmap(bitmap); 
     else 
      photoToLoad.imageView.setImageResource(stub_id); 
     if(photoToLoad.file== null){ 
      setImageSize(photoToLoad.imageView, photoToLoad.url); 
     } else { 
      setImageSize(photoToLoad.imageView, photoToLoad.file.getAbsolutePath()); 
     } 

    } 
} 



public void clearCache() { 
    memoryCache.clear(); 
    fileCache.clear(); 
} 

ImageLoader Sınıf: Eklendi Adaptör: Burada

public class LazyNewPostsAdapter extends BaseAdapter implements Constants{ 

private Activity activity; 
private ArrayList<Image> data; 
private static LayoutInflater inflater=null; 
private ImageLoader imageLoader; 
private AsyncHelper helper; 
public static final int VIEW_TYPE_LOADING = 0; 
public static final int VIEW_TYPE_ACTIVITY = 1; 

private int imgposition; 
Handler fmHandler = null; 

Handler handler = new Handler(){ 
    public void handleMessage(android.os.Message msg) { 
     switch(msg.what){ 
     case HANDLER_NEW_POST_VOTE_IMAGE: 
       int position = msg.arg1; 
      JSONObject json; 
      try { 
       json = new JSONObject((String) msg.obj); 

       int success = json.getInt("success"); 

       if(success == 1){ 

        int i_id = json.getInt("i_id"); 
        int votesUp = json.getInt("votes_up"); 
        int votesDown = json.getInt("votes_down"); 

        data.get(position).setVotesUp(votesUp); 
        data.get(position).setVotesDown(votesDown); 
        notifyDataSetChanged(); 
       } 

      } catch (JSONException e) { 
       e.printStackTrace(); 
      } 

      break; 
     case HANDLER_USER_REPORTED_IMAGE: 
      JSONObject json2 = Utils.createJSON((String)msg.obj); 
      System.out.println("REPORT IMAGE " + json2); 
      if(json2 != null){ 
       try { 
        int success = json2.getInt("success"); 
        if(success==1){ 
         Toast.makeText(activity, "Image reported!", Toast.LENGTH_LONG).show(); 

        } 
       } catch (JSONException e) { 
        // TODO Auto-generated catch block 
        e.printStackTrace(); 
       } 
      } 
      break; 
     case HANDLER_IMAGE_SIZE_AVAILABLE: 
      String url = (String) msg.obj; 
      int height = msg.arg1; 
      int width = msg.arg2; 

      int imgPosition = findImageOfCertainURL(url); 
      System.out.println("GETVIEW HANDLER 1: IMAGE POSITION" + imgPosition); 

      if(imgPosition != -1){ 
       data.get(imgPosition).setHeight(height); 
       data.get(imgPosition).setWidth(width); 
      } 
      Message copyMsg = new Message(); 
      copyMsg.what = HANDLER_IMAGE_SIZE_AVAILABLE; 
      copyMsg.arg1 = height; 
      copyMsg.arg2 = width; 
      copyMsg.obj = url; 
      fmHandler.sendMessage(copyMsg); 
      notifyDataSetChanged(); 
      break; 
     } 
    }; 
}; 

private int findImageOfCertainURL(String url){ 
    for(int i = 0; i <data.size();i++){ 
     if((URL_FOLDER_IMAGES + data.get(i).getUrl()).equalsIgnoreCase(url)){ 
      return i; 
     } 
    } 
    return -1; 
} 

public LazyNewPostsAdapter(Activity a, ArrayList<Image> d, Handler fragmentHandler) { 

    activity = a; 

    data=d; 
    inflater = (LayoutInflater)activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
    helper = new AsyncHelper(activity, handler); 

    imageLoader=new ImageLoader(activity.getApplicationContext(), 600,handler) ; 
    fmHandler = fragmentHandler; 
} 

public void updateData(ArrayList<Image> d){ 
    data = d; 
    notifyDataSetChanged(); 
} 



public int getCount() { 
    return data.size()+1; 
} 

@Override 
public int getViewTypeCount() { 
    return 2; 
} 

@Override 
public int getItemViewType(int position) { 
    // TODO Auto-generated method stub 
    return (position >= data.size()) ? VIEW_TYPE_LOADING 
      : VIEW_TYPE_ACTIVITY; 
} 

@Override 
public boolean isEnabled(int position) { 
    return getItemViewType(position) == VIEW_TYPE_ACTIVITY; 
} 

public Object getItem(int position) { 
    return (getItemViewType(position) == VIEW_TYPE_ACTIVITY) ? data.get(position) : null; 
} 

public long getItemId(int position) { 
    return (getItemViewType(position) == VIEW_TYPE_ACTIVITY) ? position 
      : -1; 
} 

public View getFooterView(int position, View convertView, 
     ViewGroup parent) { 

     // the ListView has reached the last row 
     TextView tvLastRow = new TextView(activity); 
     if(AsyncHelper.isDownloadingImages){ 
      tvLastRow.setHint("Requesting new Images.."); 
     } else { 

      tvLastRow.setHint("Reached the last row."); 
     } 
     tvLastRow.setGravity(Gravity.CENTER); 
     return tvLastRow; 

} 

private OnClickListener myHotButtonClickListener = new OnClickListener() { 
    @Override 
    public void onClick(View v) { 
     int position = (Integer) v.getTag(); 
     if(ActivityMain.user.isLoggedIn()){ 
      data.get(position).setThisUserVote(1); 
      helper.vote_image(position, data.get(position).getId(), HOT); 
     } else { 
      Toast.makeText(activity, "Login to vote" , Toast.LENGTH_SHORT).show(); 
     } 
    } 
}; 

private OnClickListener myColdButtonClickListener = new OnClickListener() { 
    @Override 
    public void onClick(View v) { 
     int position = (Integer) v.getTag(); 
     if(ActivityMain.user.isLoggedIn()){ 
      data.get(position).setThisUserVote(2); 
      helper.vote_image(position, data.get(position).getId(), COLD); 
     }else { 
      Toast.makeText(activity, "Login to vote" , Toast.LENGTH_SHORT).show(); 
     } 
    } 
}; 

private OnClickListener myOptionsButtonClickListener = new OnClickListener() { 
    @Override 
    public void onClick(View v) { 
     final int position = (Integer) v.getTag(); 
     Runnable optionsRunnable = new Runnable() { 

      @Override 
      public void run() { 


       openOptionsDialog(position); 

      } 
     }; 
     handler.postDelayed(optionsRunnable, 500); 


    } 
}; 
private void openOptionsDialog(final int imgposition){ 
    final CharSequence[] items = {"Share", "Save", "Report"}; 

    AlertDialog.Builder builder = new AlertDialog.Builder(activity); 
    builder.setTitle("Options"); 
    builder.setItems(items, new DialogInterface.OnClickListener() { 
     public void onClick(DialogInterface dialog, int item) { 
      if(item==0){ 
       Utils.shareImage(activity, imageLoader.getImage(URL_FOLDER_IMAGES + data.get(imgposition).getUrl()) , data.get(imgposition).getTitle()); 
      } else if(item==1) { 
       Utils.saveImage(imageLoader.getImage(URL_FOLDER_IMAGES + data.get(imgposition).getUrl()),activity); 
      } else if(item==2) { 
       openReportDialog(imgposition); 
      } 
     } 
    }); 
    AlertDialog alert = builder.create(); 
    alert.show(); 
} 

private void openReportDialog(final int imgposition){ 

    AlertDialog.Builder builder = new AlertDialog.Builder(activity, R.style.AppCompatAlertDialogStyle); 
    builder.setTitle("Report This Image?"); 
    builder.setPositiveButton("Yes", new DialogInterface.OnClickListener() { 

     @Override 
     public void onClick(DialogInterface dialog, int which) { 
      helper.reportImage(data.get(imgposition).getId()); 
     } 
    }); 
    builder.setNegativeButton("No", null); 

    AlertDialog alert = builder.create(); 
    alert.show(); 
} 

public View getView(final int position, View convertView, ViewGroup parent) { 
    if (getItemViewType(position) == VIEW_TYPE_LOADING) { 
     // display the last row 
     return getFooterView(position, convertView, parent); 
    } 
    View vi=convertView; 
    final ViewHolder holder; 
    final Image img = data.get(position); 
    boolean isViNull = false; 
    if(convertView==null){ 
    vi = inflater.inflate(R.layout.item_new_posts, null); 
     holder = new ViewHolder(); 
     isViNull = true; 
     holder.title=(BrushTextView)vi.findViewById(R.id.tv_newposts_title); 
     holder.image=(RatioImageView)vi.findViewById(R.id.iv_newposts_image); 
     holder.uploader = (BrushTextView) vi.findViewById(R.id.tv_newposts_uploader); 
     holder.upvotes = (BrushTextView) vi.findViewById(R.id.tv_newposts_upvotes); 
     holder.downvotes= (BrushTextView) vi.findViewById(R.id.tv_newposts_downvotes); 
     holder.options=(LinearLayout)vi.findViewById(R.id.ll_newposts_button_options); 

     holder.iv_hot=(ImageView)vi.findViewById(R.id.iv_newposts_button_upvote); 
     holder.iv_cold=(ImageView)vi.findViewById(R.id.iv_newposts_button_downvote); 
     holder.ll_hot=(LinearLayout)vi.findViewById(R.id.ll_newposts_button_upvote); 
     holder.ll_cold=(LinearLayout)vi.findViewById(R.id.ll_newposts_button_downvote); 

     vi.setTag(holder); 

    } else { 
     holder = (ViewHolder) vi.getTag(); 
    } 


    if(img.getHeight() != 0 && img.getWidth() != 0){ 

     holder.image.getLayoutParams().height = img.getHeight(); 
     holder.image.getLayoutParams().width = img.getWidth(); 
     holder.image.requestLayout(); 
    } 
    holder.ll_hot.setTag(position); 
    holder.ll_hot.setOnClickListener(myHotButtonClickListener); 
    holder.ll_cold.setTag(position); 
    holder.ll_cold.setOnClickListener(myColdButtonClickListener); 


    holder.options.setTag(position); 
    holder.options.setOnClickListener(myOptionsButtonClickListener); 


    changeVoteButtonImages(img, holder.iv_hot, holder.iv_cold); 
    if(img.getTitle()!=null){ 
     holder.title.setVisibility(View.VISIBLE); 
     holder.title.setText(img.getTitle()); 
    } else { 
     holder.title.setVisibility(View.GONE); 
    } 
    holder.uploader.setText(img.getUploader()); 
    holder.upvotes.setText(img.getVotesUp()+""); 
    holder.downvotes.setText(img.getVotesDown()+""); 
    String url = URL_FOLDER_IMAGES + img.getUrl(); 
    System.out.println("GETVIEW NEW POST ADAPTER: height = " + img.getHeight() + " width = " + img.getWidth()); 
    if(isViNull) 
    System.out.println("GETVIEW CONVERTVIEW: VI: " +vi.getHeight()); 
    imageLoader.DisplayImage(url, holder.image); 

    return vi; 
} 

private void changeVoteButtonImages(Image image, ImageView upvote,ImageView downvote){ 
    switch(image.getThisUserVote()){ 
    case 0: 
     upvote.setImageDrawable(activity.getResources().getDrawable(R.drawable.ic_post_hot_0)); 
     downvote.setImageDrawable(activity.getResources().getDrawable(R.drawable.ic_post_cold_0)); 
     break; 
    case 1: 
     downvote.setImageDrawable(activity.getResources().getDrawable(R.drawable.ic_post_cold_0)); 
     upvote.setImageDrawable(activity.getResources().getDrawable(R.drawable.ic_post_hot_1)); 
     break; 
    case 2: 
     upvote.setImageDrawable(activity.getResources().getDrawable(R.drawable.ic_post_hot_0)); 
     downvote.setImageDrawable(activity.getResources().getDrawable(R.drawable.ic_post_cold_1)); 
     break; 
    } 
} 

static class ViewHolder {    
    public BrushTextView title, uploader, upvotes, downvotes; 
    public ImageView iv_hot,iv_cold; 
    public LinearLayout options, ll_hot,ll_cold; 
    public RatioImageView image; 
} 

} 

Ve ListView

içeren Fragment olduğu

Şimdi birçok bilgi ve kod burada. Umarım yardım edecek kimseyi korkutmaz: D

Teşekkürler!

+0

kodunuzu ona gönderin e? Getter setter sınıfını kullandın mı? –

+0

Yayını düzenledim.Yardımcı olabilir :) – Wicked161089

+0

ImageLoader'ın iyi çalıştığını varsayıyorum ama ListView ve Adaptörüyle ilgili kod göndermeniz gerekiyor. Şimdiden var mı? Yanıtların eksik ve uykuda olduğunu fark ettim. –

cevap

2

Herhalde Sorun çözüldü .. Son olarak .. GetView içinde ImageView yüksekliğini ayarlama Benim fikrim o kadar kötü değildi .. sorun oldu:

Benim ImageView XML'indeki CardView içine sarılmış .. Bu yüzden yerine CardView yüksekliği değiştirmek için gereken ImageView :)

1

WeakHashMap ... zayıf referanslar kullanıyorsunuz. Hangisi doğru mu? Artık kullanılmadığında nesneleri siler. Yani, sadece HashMap'e değiştir ve iyi yapmalısın.

+0

Bu işe yaramadı .. Böyle kısa bir cevap için çok mutlu oldum: D – Wicked161089

+0

ne yapmadı? – rubmz

+0

WeakHashMap yerine HashMap olarak değiştirdim, ancak – Wicked161089

4

, "Tekerlek yeniden icat" vb Picasso gibi önbelleğe alma görüntü yükleme için orada herhangi lib kullanmayın Lütfen lütfen lütfen, Fresk, Glide vs ....

+0

Görüntü kütüphaneleri hakkında haklı olmanıza rağmen, yanılıyorsunuz. Çünkü Glide gibi kokarsan bile, bu problemi almaya devam edeceksin. Kaydırma sırasında bir görüntü yüksekliğinin ve genişliğinin hesaplanması ve bir resmin bu yeri işgal etmeye çalışmasıdır. Örneğin, https://github.com/bumptech/glide/issues/582 veya http://stackoverflow.com/questions/27616574/dynamically-added-bitmaps-to-android-listview-on-scrolling-down adresine bakın. Ayrıntılar-list-zıplayarak. – CoolMind