0

I have a fragment with GridView with ImageViews as items. The amount cells is around 25.

For every Image I have a server request by Id. So its 25 server requests. Takes 2-3 seconds.

How can I receive one image at a time and dynamically set it as content of cell? And every cell, which doesn't have image yet should contain ProgressBar.

What do I have now: I'm trying to load items in AsyncTask and return Bitmap array back to UI thread. But I don't know how to do that for every Image. My GridView appears only after ALL images downloaded. And it should be visible first with 25 elements which contain ProgressBars and no Images.


Code code

fragment's onCreate():

@Override
public void onCreate(Bundle savedInstanceState) {
    ...

    mItems = new Bitmap[dataChannelsList.size()];

    try {
    //starting AsyncTask
        mItems = new LoadImageAsyncTask(dataChannelsList).execute().get();
    } catch (InterruptedException e) {
        e.printStackTrace();
    } catch (ExecutionException e) {
        e.printStackTrace();
    }
}

LoadImageAsyncTask:

private class LoadImageAsyncTask extends AsyncTask<Bitmap[], Void, Bitmap[]> {
    private ArrayList<DataChannels> dataChannelsList;
    private Bitmap[] bitmapList;

    public LoadImageAsyncTask(ArrayList<DataChannels> dataChannelsList) {
        this.dataChannelsList = dataChannelsList;

        bitmapList = new Bitmap[dataChannelsList.size()];
    }

    protected void onPreExecute() {
        super.onPreExecute();
    }

    protected Bitmap[] doInBackground(Bitmap[]... params) {
        for (int i = 0; i < dataChannelsList.size(); i++) {
            bitmapList[i] = getChannelImg(dataChannelsList.get(i).getId());
        }
        return bitmapList;
    }


    protected void onPostExecute(Bitmap[] param) {
        super.onPostExecute(param);
    }

    private Bitmap getChannelImg(String id) {
        ...returns Bitmap image by id
    }

}

GridView adapter:

    public class GridViewAdapter extends BaseAdapter {
    private Context mContext;
    private Bitmap[] mItems;

    public GridViewAdapter(Context context, Bitmap[] items) {
        mContext = context;
        mItems = items;
    }

    @Override
    public int getCount() {
        return mItems.length;
    }

    @Override
    public Object getItem(int position) {
        return mItems[position];
    }

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

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolder viewHolder;

        if (convertView == null) {
            // inflate the GridView item layout
            LayoutInflater inflater = LayoutInflater.from(mContext);
            convertView = inflater.inflate(R.layout.gridview_item, parent, false);

            // initialize the view holder
            viewHolder = new ViewHolder();
            viewHolder.ivIcon = (ImageView) convertView.findViewById(R.id.imageview_channelIcon);
            viewHolder.progressBar = (ProgressBar) convertView.findViewById(R.id.progress_bar_load_image);
            convertView.setTag(viewHolder);
        } else {
            // recycle the already inflated view
            viewHolder = (ViewHolder) convertView.getTag();
        }

        // update the item view
        Bitmap item = mItems[position];

        //hide progress bar and bring image to top
        viewHolder.progressBar.setVisibility(View.GONE);
        viewHolder.ivIcon.setImageBitmap(item);
        return convertView;
    }

}

private static class ViewHolder {
    ImageView ivIcon;
    ProgressBar progressBar;
}

Guys, I really need your help. Tell if some more code or explanations needed.

AnZ
  • 1,040
  • 24
  • 54
  • 1
    check out Picasso http://stackoverflow.com/questions/22330772/why-use-android-picasso-library-to-download-images, or at least review an open source solution like this to learn – CSmith Mar 26 '15 at 14:14
  • You should call imageLoaderTask onGetView() method of adapter. Also your loader task download should be parameterized and called by adapter with your image_id. – kgnkbyl Mar 26 '15 at 14:17

2 Answers2

3

You can use publishProgress() for this to call onProgressUpdate()

So in your for loop something like

for (int i = 0; i < dataChannelsList.size(); i++) {
        // create a variable for the current bitmap
        Bitmap curBitmap = getChannelImg(dataChannelsList.get(i).getId()); 
        // add it to your list
        bitmapList[i] = curBitmap;
        // and pass it along
        publishProgress(curBitmap);
    }

then you will need to override onProgressUpdate() which is called by publishProgress()

@Override
public void onProgressUpdate(Bitmap...progress) {
    /* add the bitmap to your list you're using for your adapter here
     * and call notifyDataSetChanged() on your adapter
    */
}

You then would need to change your asynctask to

private class LoadImageAsyncTask extends AsyncTask<Bitmap[], Bitmap, Bitmap[]> {

You also don't want to call .get() on your AsyncTask because it is a blocking call

Something similar to this should give you what you want.

Alternatives

However, there are a lot of libraries that can do the work for you and give you benefits.

Community
  • 1
  • 1
codeMagic
  • 44,549
  • 13
  • 77
  • 93
1
@Override
public void onCreate(Bundle savedInstanceState) {
    ...

    mItems = new Bitmap[dataChannelsList.size()];
    GridView grid=// declare your gridview;
GridViewAdapter adapter=new GridViewAdapter(activityname.this,mItems);
grid.setAdapter(adapter);

    try {
    //starting AsyncTask here

    } catch (InterruptedException e) {
        e.printStackTrace();
    } catch (ExecutionException e) {
        e.printStackTrace();
    }
}

and in the assynctask

protected void onPostExecute(Bitmap[] param) {
        super.onPostExecute(param);
         adapter.notifydatasetchanged;

// adapter should be declared as class variable,so that it can be used here.or else pass adapter variable as actual parameter to assynctask constructor

    }

for progress bar I think what you are doing is correct change your adapter class's

@Override
    public int getCount() {
        return 25;// the size you want
    }

inside getView method

  @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolder viewHolder;

int currentposition=position;
        if (convertView == null) {
            // inflate the GridView item layout
            LayoutInflater inflater = LayoutInflater.from(mContext);
            convertView = inflater.inflate(R.layout.gridview_item, parent, false);

            // initialize the view holder
            viewHolder = new ViewHolder();
            viewHolder.ivIcon = (ImageView) convertView.findViewById(R.id.imageview_channelIcon);
            viewHolder.progressBar = (ProgressBar) convertView.findViewById(R.id.progress_bar_load_image);
           viewHolder.ivIcon.setTag(currentposition);
            convertView.setTag(viewHolder);
        } else {
            // recycle the already inflated view
            viewHolder = (ViewHolder) convertView.getTag();
        }

        // update the item view
        Bitmap item = mItems[position];

        //hide progress bar and bring image to top

if(Integer.parseInt(viewHolder.ivIcon.getTag().toString())>mItems.size()){
        viewHolder.progressBar.setVisibility(View.VISIBLE);
 viewHolder.ivIcon.setVisibility(View.VISIBLE);
}
else{
viewHolder.progressBar.setVisibility(View.INVISIBLE);
 viewHolder.ivIcon.setVisibility(View.INVISIBLE);

}
        viewHolder.ivIcon.setImageBitmap(item);
        return convertView;
    }

}
Karthika PB
  • 1,373
  • 9
  • 16
  • This can never work. Do not use .get() on an AsyncTask. – greenapps Mar 26 '15 at 19:59
  • @greenapps pls check the code once again ok...and that's not my codeline. – Karthika PB Mar 27 '15 at 06:52
  • Why did you remove the code to call the asynctask? Further this code does nothing with downloading all at once or one by one. So what are you solving? – greenapps Mar 27 '15 at 07:48
  • @greenapps What do I have now: I'm trying to load items in AsyncTask and return Bitmap array back to UI thread. But I don't know how to do that for every Image. My GridView appears only after ALL images downloaded. And it should be visible first with 25 elements which contain ProgressBars and no Images. this was the question and the above codelines need to be added in his existing code.he have code for download already pls read his question.I just gave him suggestion to how to refresh his gridview after each image download and how to show progress bar in grids with no iimage.that's all – Karthika PB Mar 27 '15 at 09:35
  • `But I don't know how to do that for every Image.`. Yes thats why i said that it was not gonna work, The answer of codeMagic shows how it can be done. – greenapps Mar 27 '15 at 09:47