In my application I need to download a lot of pictures from urls and display them in a gridView. (It can be between 1-200 pictures). I don't want to download all pictures at once. I read about lazy downloading and my question is: Can i get only one part of the Json, download the pictures in a different thread, and only if the user scroll down the gridView, I will continue to the other parts of the Json, and so on?
Edit: Hi again. I want to implement multi select in this gridView and i'm having difficulty to implement the code in the getView() method of the adapter. This is the example i'm using:example. How can I combine this code in my getView() method:
public View getView(int position, View convertView, ViewGroup parent) {
CheckableLayout l;
ImageView i;
if (convertView == null) {
i = new ImageView(Grid3.this);
i.setScaleType(ImageView.ScaleType.FIT_CENTER);
i.setLayoutParams(new ViewGroup.LayoutParams(50, 50));
l = new CheckableLayout(Grid3.this);
l.setLayoutParams(new GridView.LayoutParams(GridView.LayoutParams.WRAP_CONTENT,
GridView.LayoutParams.WRAP_CONTENT));
l.addView(i);
} else {
l = (CheckableLayout) convertView;
i = (ImageView) l.getChildAt(0);
}
ResolveInfo info = mApps.get(position);
i.setImageDrawable(info.activityInfo.loadIcon(getPackageManager()));
return l;
}
public class CheckableLayout extends FrameLayout implements Checkable {
private boolean mChecked;
public CheckableLayout(Context context) {
super(context);
}
public void setChecked(boolean checked) {
mChecked = checked;
setBackgroundDrawable(checked ?
getResources().getDrawable(R.drawable.blue)
: null);
}
public boolean isChecked() {
return mChecked;
}
public void toggle() {
setChecked(!mChecked);
}
}
my getView() code:
public View getView(int position, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
ViewHolder holder;
View vi = convertView;
if(convertView == null) {
vi = inflater.inflate(com.egedsoft.instaprint.R.layout.item_clickable, null);
holder = new ViewHolder();
holder.imgPhoto = (ImageView)vi.findViewById(com.egedsoft.instaprint.R.id.imageClickable);
vi.setTag(holder);
} else {
holder = (ViewHolder) vi.getTag();
}
if (!arrayUrls.get(position).getThumbnailUrl().isEmpty()){
imageLoader.DisplayImage(arrayUrls.get(position).getThumbnailUrl(), holder.imgPhoto);
}
return vi;
}
You can, take a look to Using adapter Views and GridView from Android Documentation. The most important thing is that the adapter call the method
getView
passing only the position of the entries showing on screen, and asking for different positions when user scrolls.The easy way to do is download the required image on the
getView
method of your adapter with and AsyncTask.There is an example
I found IceMAN's answer very useful, but I also recommend avoid using two AsyncTasks and you can make this easily.
You need to create a universal method to fetch needed data, where you can make an if/else condition (as an example):
addMovies is a boolean in your onScroll method. In AsyncTask provide current page in query URL and voila - you made your code smaller :)
This is how I fetch multiple photos in my activity. You can use parts of it for fit your logic. I use this to fetch Facebook Images from an Album. So my needs are (I am assuming) different from your needs. But again, the logic may be of use to you.
Note: This will be lengthy. ;-)
These are the global declarations for use through the ACtivity:
This is the code block that fetches the initial set of Images:
This is to detect when the user has scrolled to the end and fetch new set of images:
And finally, this is how I fetch the next set of images:
And this is the helper class to
SET
andGET
the data collected from the queries above:If you also want the
adapter
code, let me know. I use Fedor's Lazy Loading method in the adapter.Phew. Hope any of this helps. If you have further question, feel free to ask. :-)
EDIT: Adapter code added:
EDIT: Added steps to show Progress while loading:
Add a ProgressBar to you XML where you have the GridView right below it. Play around with the weight if it causes any problems.
In your Java, declare the
Linearlayout linlaProgressBar
as Global and cast it in theonCreate()
and set it's visibility aslinlaProgressBar.setVisibility(View.GONE);
And in the
onPreExecute()
use it like this:And finally add, this in the
onPostExecute()
Talking from experience, it's tricky to achieve smooth scrolling (and overall responsiveness) while consuming memory reasonably.
It would be a good idea to look for existing solutions first, e.g., start here: Lazy load of images in ListView
We ended up with a custom proprietary solution. It is a background thread that queues download requests and downloads and caches on the external storage only the images that are still visible. When a new image arrives, the view gets notified and decides when to notify the adapter to update.
It also saves the bandwidth, which was important in some cases.