0

I've been trying to update my Images GridView.
The images get updated only if I set the adapter again. Setting the adapter again makes my activity scroll back to top and I try to avoid that.

Here's some code:

private class LoadImagesTask extends AsyncTask<Object,Void, Object> {
    private ImageAdapter imageAdapter;
    private ArrayList<Integer> idsArray;
    @Override
    protected void onPreExecute() {   
        imageAdapter = new ImageAdapter(getApplicationContext());
        Bitmap bmap = BitmapFactory.decodeResource(getResources(),
                R.drawable.locked_image);
        idsArray = dbHelper.getPicturesIdsByAlbumId(1);
        for(int i = 0;i<idsArray.size();i++){
            imageAdapter.bitmaps.add(bmap);
        }

        gridView.setAdapter(imageAdapter);
    }
    @Override
    protected Void doInBackground(Object... arg) {

        for(int i = 0;i<idsArray.size();i++){
            byte[] data = dbHelper.getPictureById(idsArray.get(i)).littlePicBytes;
            imageAdapter.bitmaps.set(i, BitmapFactory.decodeByteArray(data, 0, data.length));
            publishProgress(); //********** This line calls onProgressUpdate()  *********
        }
        return null;

    }
}

Now, this code works for updating the views:

@Override
protected void onProgressUpdate(Void... params) {
    gridView.setAdapter(imageAdapter);
}

But this doesnt:

@Override
protected void onProgressUpdate(Void... params) {
    imageAdapter.notifyDataSetChanged();
    gridView.invalidateViews();
}

What could be the reason for not updating my views? Thank you!

EDIT: The ImageAdapter code:

public class ImageAdapter extends BaseAdapter {
    private Context mContext;
    public ArrayList<Bitmap> bitmaps = new ArrayList<Bitmap>();
    public ImageAdapter(Context c) {
        mContext = c;

    }

    public int getCount() {
        return bitmaps.size();
    }

    public Object getItem(int position) {
        return position;
    }

    public long getItemId(int position) {
        return position;
    }

    // create a new ImageView for each item referenced by the Adapter
    public View getView(int position, View convertView, ViewGroup parent) {
        LayoutInflater inflater = (LayoutInflater) mContext
                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);

            View gridView;

            if (convertView == null) {

                gridView = new View(mContext);

                // get layout from mobile.xml
                gridView = inflater.inflate(R.layout.image_adapter, null);

                // set image based on selected text
                ImageView imageView = (ImageView) gridView
                        .findViewById(R.id.imageView);
                imageView.setImageBitmap(bitmaps.get(position));
            }
                else{ 
                    gridView = (View) convertView;
                }
            return gridView;
    }
}
Shivam Kumar
  • 1,892
  • 2
  • 21
  • 33
idish
  • 3,190
  • 12
  • 53
  • 85
  • can you please show the code of the adapter itself? btw, calling notifyDataSetChanged should be enough. you could also update only the needed view instead of invalidating all of the items. – android developer Jul 13 '13 at 10:52
  • @androiddeveloper Edited my post with the ImageAdapter code. I'm aware of that I can update only the needed view but it doesn't work anyways :) – idish Jul 13 '13 at 10:56
  • you getView isn't implemented correctly. please read more about it and also watch "the world of listView" (both gridview and listview extend from adapterView, so their tips are the same for both) : http://www.google.com/events/io/2010/sessions/world-of-listview-android.html . i will now write down what's wrong in your code and offer how to correct it, but please read about it. – android developer Jul 13 '13 at 11:00
  • you will have to set the content to the gridview first. You call `notifyDataSetChanged` on your adapter when you have new data and you want to refresh/update gridview. – Raghunandan Jul 13 '13 at 11:04

1 Answers1

1

you have 2 main problems in your code:

  1. in the doInBackground , you change the data of the adapter, which is not a thread safe operation, since the adapter might read now from the data while you change it. i'm talking about this line:

    imageAdapter.bitmaps.set(i, BitmapFactory.decodeByteArray(data, 0, data.length));
    

    instead, you should update its data only on the UI thread, for example inside the onProgressUpdate .

  2. in the getView, you have implemented it incorrectly . when the convertView is not null, you never update the content of the imageView. what it should be like is something like:

public View getView(int position, View convertView, ViewGroup parent) 
  {
  View rootView=convertView;
  ViewHolder holder;
  if (rootView != null) 
    holder=(ViewHolder) rootView.getTag();
  else
    {
    rootView = inflater.inflate(R.layout.image_adapter, null,false);
    holder = new ViewHolder();
    holder.imageView = (ImageView) rootView.findViewById(R.id.imageView);
    rootView.setTag(holder);
    }
  holder.imageView.setImageBitmap(getItem(position));
  return rootView;
  }


private Bitmap getItem(final int position)
  {
  return bitmaps.get(position); 
  }    

private static class ViewHolder
  {
  ImageView imageView;
  }
android developer
  • 114,585
  • 152
  • 739
  • 1,270
  • It works well and now I only have to call notifydatasetchanged() but the layout of the gridview still scrolls back to top while it gets updated. I was trying to save the position of the scroll and the set the selection again but the scrolling is pretty buggy and isn't smooth. – idish Jul 20 '13 at 14:58
  • it shouldn't scroll back to the top when you update the data. however, if you wish to save&restore its state, use listView.onSaveInstanceState() and listView. onRestoreInstanceState() , as shown here: http://stackoverflow.com/a/5688490/878126 . this is usually used when the configuration of the device changes (like when the device is rotated). again this should not have happened to you, so maybe you should post a new question and show some more code. – android developer Jul 20 '13 at 15:19
  • if you wish to update a single item, there is a trick to do it without using notifyDataSetChanged: http://stackoverflow.com/a/3727813/878126 or http://stackoverflow.com/a/15614795/878126. also, don't forget to ignore it when it returns a null as the view being returned. – android developer Jul 20 '13 at 15:51
  • Alright, the second solution works like a charm. Toda Raba :) – idish Jul 20 '13 at 18:40
  • how did you know i know hebrew? – android developer Jul 20 '13 at 19:54
  • oh, ok. i suggest you watch google io videos to learn more tricks. those that are related to listView (and gridView) are on the lecture "the world of listView" – android developer Jul 21 '13 at 12:08