ListView - ImageLoader moves List / Items on Scroll up
Asked Answered
U

3

8

I'm looking for an answer half a day, but I can't find anything although I thought it is a common problem. My Problem: I have a ListView which has items of different sizes (heights). Every item contains an ImageView. The Image for this ImageView is loaded in background by an ImageLoader class:

imageLoader.DisplayImage(url, holder.image);

If i scroll down the ListView everything works fine. the images are loaded and display (of course at the bottom of the screen / list).

But If I scroll up and the image isn't stored in cache anymore, so the ImageLoader has to reload the image, the ListView jumps / the items are moved. I think it is because a new View is created on top of the list, with an ImageView with 0dp height. If the Image is loaded and set to the ImageView the height of the ImageView changes automatically from 0dp to the size of the Image. This would push the ListView down, I think.

I tried saving the height of the ImageViews if an Image is set and then set the height of the ImageView which is created on top to the saved height. But with no success..

I don't know if you can understand my problem :D I hope so :)

Thanks and have a nice day!

EDIT: Added ImageLoader Class

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

EDIT: Added Adapter:

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

}

And here is the Fragment, which contains the ListView

public class Fragment_New_Posts extends Fragment implements Constants, OnRefreshListener{

private static final String ARG_SECTION_NUMBER = "section_number";

private ListView list;
private LazyNewPostsAdapter adapter;
private Images images;
private ArrayList<Image> imagesList;
private SharedPreferences prefs;
private Editor editor;
private int visible_i_id;
private SwipeRefreshLayout swipeLayout;
private int option_image_filter;
private AsyncHelper helper;
private boolean onRefreshFired = false;
private Parcelable state;

public static Fragment_New_Posts newInstance(int sectionNumber) {
    Fragment_New_Posts fragment = new Fragment_New_Posts();
    Bundle args = new Bundle();
    args.putInt(ARG_SECTION_NUMBER, sectionNumber);
    fragment.setArguments(args);
    return fragment;
}

public static Fragment_New_Posts newInstance(int sectionNumber, Images imgs) {
    Fragment_New_Posts fragment = new Fragment_New_Posts(imgs);
    Bundle args = new Bundle();
    args.putInt(ARG_SECTION_NUMBER, sectionNumber);
    fragment.setArguments(args);
    return fragment;
}

public void updateImages(Images images, boolean createNew, boolean loadOldImages){
    int i_id_position = 0;
    this.images = images;
    if(!images.hasErrorOccured){
        if(this.imagesList == null || createNew || onRefreshFired){
            this.imagesList = images.getListOfImages();
        } else {
            this.imagesList.addAll(images.getListOfImages());
        }
    } 

    if(loadOldImages){
        i_id_position = this.images.getIDPosition(visible_i_id);
    }
    if(onRefreshFired){
        swipeLayout.setRefreshing(false);
        onRefreshFired = false;
    }
    synchronized (adapter) {
        adapter.updateData(this.imagesList);
        if(list!=null && createNew){
            if(loadOldImages){
                list.setSelection(i_id_position);
            } else {
                list.setSelection(0);
            }
        }
    }

}

private Handler handler = new Handler(){
    public void handleMessage(android.os.Message msg) {
        switch(msg.what){
        case HANDLER_MAIN_IMAGE_UPDATE:
            String imagesString =  (String) msg.obj;
            Images imgs = new Images(imagesString);
            updateImages(imgs, false, false);
            if(imgs.hasErrorOccured){
                Toast.makeText(getActivity(), "Can\'t get new Images", Toast.LENGTH_SHORT).show();
            }
            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 2: IMAGE POSITION" + imgPosition);
            if(imgPosition != -1){
                imagesList.get(imgPosition).setHeight(height);
                imagesList.get(imgPosition).setWidth(width);
            }

            break;
        }

    };
};

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

public Fragment_New_Posts() {
}

public Fragment_New_Posts(Images imgs) {
    this.images = imgs;
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) {
    System.out.println("NEW POST FRAGMENT ONCREATE");
    View rootView = inflater.inflate(R.layout.fragment_new_posts, container, false);
    prefs = getActivity().getSharedPreferences(PREF_WOODU, getActivity().MODE_PRIVATE);
    editor = prefs.edit();
    if(prefs!=null){
        visible_i_id = prefs.getInt(PREF_NEW_POSTS_VISIBLE_I_ID, 0);
        option_image_filter = prefs.getInt(PHP_TAG_IMAGE_FILTER, 0);
    }
    swipeLayout = (SwipeRefreshLayout) rootView.findViewById(R.id.swipe_container);
    swipeLayout.setColorSchemeColors(R.color.red_hot);
    swipeLayout.setOnRefreshListener(this);
    helper = new AsyncHelper(getActivity(), handler);
    imagesList = new ArrayList<Image>();
    if(images != null){
        imagesList = images.getListOfImages();
        System.out.println("SAVE IMAGES: load: imgsList " + imagesList);

    }
    list = (ListView) rootView.findViewById(R.id.lv_new_posts);
    adapter = new LazyNewPostsAdapter(getActivity(), imagesList, handler);
    list.setAdapter(adapter);

    list.setOnScrollListener(new EndlessScrollListener() {
        @Override
        public void onLoadMore(int page, int totalItemsCount) {
            if(imagesList!=null && imagesList.size()!=0){
                helper.getImageUpdate(imagesList.get(imagesList.size()-1).getId(), option_image_filter);
            }
        }
    });

    if(images != null){
        updateImages(images, true, true);
    }

    return rootView;
}



@Override
public void onPause() {
    int lastVisposition = list.getLastVisiblePosition();
    if(lastVisposition>=0 && lastVisposition < this.imagesList.size()){
        visible_i_id = this.imagesList.get(list.getFirstVisiblePosition()).getId();
        editor.putInt(PREF_NEW_POSTS_VISIBLE_I_ID, visible_i_id);
        editor.commit();
    }

    super.onPause();
}




@Override
public void onResume() {
    super.onResume();


}

@Override
public void onDestroy() {
    if(images != null){
        editor.putString(PREF_NEW_POSTS_CURRENT_IMAGES, Utils.createJSONStringFromImageArrayList(imagesList, editor));
        editor.commit();
    }
    super.onDestroy();
}

@Override
public void onRefresh() {
    onRefreshFired = true;
    if(prefs!=null){
        option_image_filter = prefs.getInt(PHP_TAG_IMAGE_FILTER, 0);
    }
    helper.getImageUpdate(0, option_image_filter);
}
}

Now here are many many information and code. I hope that does not scare anyone to help :D

Thanks!!

Ucayali answered 19/5, 2015 at 17:27 Comment(10)
post your code here ? have you used getter setter class ?Overliberal
i edited the post. May it helps :)Ucayali
I am assuming that the ImageLoader works fine but you need to post code related to ListView and its Adapter. Do you have that already? I noticed that the responses have been lacking and dormant.Brindled
@TheOriginalAndroid I added the Fragment and the Adapter.. ThanksUcayali
Are you sure you want to do this with your own implementation? I suggest you use RecyclerView and some other image loading libraries available out there.Verity
I haven't use RecyclerView .. I got the ImageLoader Class from GitHub and thought it would be a good way.. I have to read into RecyclerView firstUcayali
Listview basically works fine! But you have implemented code disregarding the basic functionality of ListView and the BaseAdapter. So...the big question is do you really want to do this your way? If you do, it's going to be harder and may not work in future Android framework. I have to let you know.Brindled
I think the main problem is that the ListView items have different heights depending on the size of the ImageView.. and this is by XML "wrap_content" .. But getting the imageview height while scrolling down... saving it in onPause and setting it in getView (if I scroll up) does not work.. But I maybe that code has a bug.. Don't know why, but save the img height mostly returns an integer of 708.. And the images are definatly not all that size :(Ucayali
Sorry I beg to differ. ListView and the View attributes allow some customization, though I admit it's not obvious. For example, ImageView has a method setMaxHeight, to satisfy the Listview item height. And of course, I think you know you can detect user scrolling up. I have done many things with ListView, someday I'll try RecyclerView, less robust though.Brindled
Another useful class for setting UI attributes is ViewGroup.LayoutParams, good for setting height and width, and many stuff...At least next time, you'll know.Brindled
U
2

I probably solved the Problem.. Finally.. My idea of setting the height of the ImageView in getView wasn't so bad.. problem was:

My ImageView was wrapped inside a CardView in XML.. So I needed to change the Height of the CardView instead of the ImageView :)

Ucayali answered 31/5, 2015 at 10:29 Comment(0)
A
4

Please, Please , Please don't "re-invent the Wheel" and use any lib out there for image loading, caching etc like Picasso, Fresco , Glide etc....

Aquatint answered 5/6, 2015 at 10:1 Comment(1)
Though you are right about image libraries, you are wrong. Because even if you plug in smth like Glide you will continue getting this problem. It is because during scrolling an image height and width are calculated and an image tries to occupy this place. See, for instance, github.com/bumptech/glide/issues/582 or #27617074.Ersatz
U
2

I probably solved the Problem.. Finally.. My idea of setting the height of the ImageView in getView wasn't so bad.. problem was:

My ImageView was wrapped inside a CardView in XML.. So I needed to change the Height of the CardView instead of the ImageView :)

Ucayali answered 31/5, 2015 at 10:29 Comment(0)
P
1

WeakHashMap ... you are using weak references. Which does right that. Deletes objects when used no more. So, just change it to HashMap and you should be doing fine.

Po answered 31/5, 2015 at 6:17 Comment(2)
I changed it to HashMap instead of WeakHashMap, but my ListView Items still gets pushed down if i scroll upUcayali
Yepp, the complete answer is to check memoryCache (which is of type MemoryCache) which seems to get full and starts dropping your imagesPo

© 2022 - 2024 — McMap. All rights reserved.