Lazy Download Images into Gridview

Lazy download images into gridView

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:

// HOLD THE URL TO MAKE THE API CALL TO
private String URL;

// STORE THE PAGING URL
private String pagingURL;

// FLAG FOR CURRENT PAGE
int current_page = 1;

// BOOLEAN TO CHECK IF NEW FEEDS ARE LOADING
Boolean loadingMore = true;

Boolean stopLoadingData = false;

This is the code block that fetches the initial set of Images:

private class getPhotosData extends AsyncTask<Void, Void, Void> {

@Override
protected Void doInBackground(Void... arg0) {

// CHANGE THE LOADING MORE STATUS TO PREVENT DUPLICATE CALLS FOR
// MORE DATA WHILE LOADING A BATCH
loadingMore = true;

// SET THE INITIAL URL TO GET THE FIRST LOT OF ALBUMS
URL = "https://graph.facebook.com/" + initialAlbumID
+ "/photos&access_token="
+ Utility.mFacebook.getAccessToken() + "?limit=10";

try {

HttpClient hc = new DefaultHttpClient();
HttpGet get = new HttpGet(URL);
HttpResponse rp = hc.execute(get);

if (rp.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
String queryAlbums = EntityUtils.toString(rp.getEntity());

JSONObject JOTemp = new JSONObject(queryAlbums);

JSONArray JAPhotos = JOTemp.getJSONArray("data");

// IN MY CODE, I GET THE NEXT PAGE LINK HERE

getPhotos photos;

for (int i = 0; i < JAPhotos.length(); i++) {
JSONObject JOPhotos = JAPhotos.getJSONObject(i);
// Log.e("INDIVIDUAL ALBUMS", JOPhotos.toString());

if (JOPhotos.has("link")) {

photos = new getPhotos();

// GET THE ALBUM ID
if (JOPhotos.has("id")) {
photos.setPhotoID(JOPhotos.getString("id"));
} else {
photos.setPhotoID(null);
}

// GET THE ALBUM NAME
if (JOPhotos.has("name")) {
photos.setPhotoName(JOPhotos.getString("name"));
} else {
photos.setPhotoName(null);
}

// GET THE ALBUM COVER PHOTO
if (JOPhotos.has("picture")) {
photos.setPhotoPicture(JOPhotos
.getString("picture"));
} else {
photos.setPhotoPicture(null);
}

// GET THE PHOTO'S SOURCE
if (JOPhotos.has("source")) {
photos.setPhotoSource(JOPhotos
.getString("source"));
} else {
photos.setPhotoSource(null);
}

arrPhotos.add(photos);
}
}
}
} catch (Exception e) {
e.printStackTrace();
}

return null;
}

@Override
protected void onPostExecute(Void result) {

// SET THE ADAPTER TO THE GRIDVIEW
gridOfPhotos.setAdapter(adapter);

// CHANGE THE LOADING MORE STATUS
loadingMore = false;
}

}

This is to detect when the user has scrolled to the end and fetch new set of images:

// ONSCROLLLISTENER
gridOfPhotos.setOnScrollListener(new OnScrollListener() {

@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {

}

@Override
public void onScroll(AbsListView view, int firstVisibleItem,
int visibleItemCount, int totalItemCount) {
int lastInScreen = firstVisibleItem + visibleItemCount;
if ((lastInScreen == totalItemCount) && !(loadingMore)) {

if (stopLoadingData == false) {
// FETCH THE NEXT BATCH OF FEEDS
new loadMorePhotos().execute();
}

}
}
});

And finally, this is how I fetch the next set of images:

private class loadMorePhotos extends AsyncTask<Void, Void, Void> {

@Override
protected Void doInBackground(Void... arg0) {

// SET LOADING MORE "TRUE"
loadingMore = true;

// INCREMENT CURRENT PAGE
current_page += 1;

// Next page request
URL = pagingURL;

try {

HttpClient hc = new DefaultHttpClient();
HttpGet get = new HttpGet(URL);
HttpResponse rp = hc.execute(get);

if (rp.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
String queryAlbums = EntityUtils.toString(rp.getEntity());
// Log.e("PAGED RESULT", queryAlbums);

JSONObject JOTemp = new JSONObject(queryAlbums);

JSONArray JAPhotos = JOTemp.getJSONArray("data");

// IN MY CODE, I GET THE NEXT PAGE LINK HERE

getPhotos photos;

for (int i = 0; i < JAPhotos.length(); i++) {
JSONObject JOPhotos = JAPhotos.getJSONObject(i);
// Log.e("INDIVIDUAL ALBUMS", JOPhotos.toString());

if (JOPhotos.has("link")) {

photos = new getPhotos();

// GET THE ALBUM ID
if (JOPhotos.has("id")) {
photos.setPhotoID(JOPhotos.getString("id"));
} else {
photos.setPhotoID(null);
}

// GET THE ALBUM NAME
if (JOPhotos.has("name")) {
photos.setPhotoName(JOPhotos.getString("name"));
} else {
photos.setPhotoName(null);
}

// GET THE ALBUM COVER PHOTO
if (JOPhotos.has("picture")) {
photos.setPhotoPicture(JOPhotos
.getString("picture"));
} else {
photos.setPhotoPicture(null);
}

// GET THE ALBUM'S PHOTO COUNT
if (JOPhotos.has("source")) {
photos.setPhotoSource(JOPhotos
.getString("source"));
} else {
photos.setPhotoSource(null);
}

arrPhotos.add(photos);
}
}
}
} catch (Exception e) {
e.printStackTrace();
}

return null;
}

@Override
protected void onPostExecute(Void result) {

// get listview current position - used to maintain scroll position
int currentPosition = gridOfPhotos.getFirstVisiblePosition();

// APPEND NEW DATA TO THE ARRAYLIST AND SET THE ADAPTER TO THE
// LISTVIEW
adapter = new PhotosAdapter(Photos.this, arrPhotos);
gridOfPhotos.setAdapter(adapter);

// Setting new scroll position
gridOfPhotos.setSelection(currentPosition + 1);

// SET LOADINGMORE "FALSE" AFTER ADDING NEW FEEDS TO THE EXISTING
// LIST
loadingMore = false;
}

}

And this is the helper class to SET and GET the data collected from the queries above:

public class getPhotos {

String PhotoID;

String PhotoName;

String PhotoPicture;

String PhotoSource;

// SET THE PHOTO ID
public void setPhotoID(String PhotoID) {
this.PhotoID = PhotoID;
}

// GET THE PHOTO ID
public String getPhotoID() {
return PhotoID;
}

// SET THE PHOTO NAME
public void setPhotoName(String PhotoName) {
this.PhotoName = PhotoName;
}

// GET THE PHOTO NAME
public String getPhotoName() {
return PhotoName;
}

// SET THE PHOTO PICTURE
public void setPhotoPicture(String PhotoPicture) {
this.PhotoPicture = PhotoPicture;
}

// GET THE PHOTO PICTURE
public String getPhotoPicture() {
return PhotoPicture;
}

// SET THE PHOTO SOURCE
public void setPhotoSource(String PhotoSource) {
this.PhotoSource = PhotoSource;
}

// GET THE PHOTO SOURCE
public String getPhotoSource() {
return PhotoSource;
}
}

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:

public class PhotosAdapter extends BaseAdapter {

private Activity activity;

ArrayList<getPhotos> arrayPhotos;

private static LayoutInflater inflater = null;
ImageLoader imageLoader;

public PhotosAdapter(Activity a, ArrayList<getPhotos> arrPhotos) {

activity = a;

arrayPhotos = arrPhotos;

inflater = (LayoutInflater)activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
imageLoader = new ImageLoader(activity.getApplicationContext());
}

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

public Object getItem(int position) {
return arrayPhotos.get(position);
}

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

public View getView(final int position, View convertView, ViewGroup parent) {

ViewHolder holder;

View vi = convertView;
if(convertView == null) {
vi = inflater.inflate(R.layout.photos_item, null);

holder = new ViewHolder();

holder.imgPhoto = (ImageView)vi.findViewById(R.id.grid_item_image);

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

if (arrayPhotos.get(position).getPhotoPicture() != null){
imageLoader.DisplayImage(arrayPhotos.get(position).getPhotoPicture(), holder.imgPhoto);
}
return vi;
}

static class ViewHolder {
ImageView imgPhoto;

}
}

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.

<LinearLayout
android:id="@+id/linlaProgressBar"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="horizontal" >

<ProgressBar
style="@style/Spinner"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="2dp" />
</LinearLayout>

In your Java, declare the Linearlayout linlaProgressBar as Global and cast it in the onCreate() and set it's visibility as linlaProgressBar.setVisibility(View.GONE);

And in the onPreExecute() use it like this:

@Override
protected void onPreExecute() {
// SHOW THE BOTTOM PROGRESS BAR (SPINNER) WHILE LOADING MORE PHOTOS
linlaProgressBar.setVisibility(View.VISIBLE);
}

And finally add, this in the onPostExecute()

// HIDE THE BOTTOM PROGRESS BAR (SPINNER) AFTER LOADING MORE ALBUMS
linlaProgressBar.setVisibility(View.GONE);

Lazy loading GridView with images downloading from internet

Follow this approach.

First, create a custom WebImageView class as follows.

public class WebImageView extends ImageView {

private Drawable placeholder, image;

public WebImageView(Context context) {
super(context);
}
public WebImageView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public WebImageView(Context context, AttributeSet attrs) {
super(context, attrs);
}

public void setPlaceholderImage(Drawable drawable) {
placeholder = drawable;
if (image == null) {
setImageDrawable(placeholder);
}
}
public void setPlaceholderImage(int resid) {
placeholder = getResources().getDrawable(resid);
if (image == null) {
setImageDrawable(placeholder);
}
}

public void setImageUrl(String url) {
DownloadTask task = new DownloadTask();
task.execute(url);
}

private class DownloadTask extends AsyncTask<String, Void, Bitmap> {

@Override
protected Bitmap doInBackground(String... params) {
String url = params[0];
try {
URLConnection conn = (new URL(url)).openConnection();
InputStream is = conn.getInputStream();
BufferedInputStream bis = new BufferedInputStream(is);

ByteArrayBuffer baf = new ByteArrayBuffer(50);
int current = 0;
while ((current=bis.read()) != -1) {
baf.append((byte)current);
}

byte[] imageData = baf.toByteArray();
return BitmapFactory.decodeByteArray(imageData, 0, imageData.length);

} catch (Exception e) {
return null;
}
}

@Override
protected void onPostExecute(Bitmap result) {
image = new BitmapDrawable(result);
if (image != null) {
setImageDrawable(image);
}
}
}
}

Next, in Activity use the above custom ImageView as follows:

protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);

WebImageView imageView = (WebImageView) findViewById(R.id.webimage);
imageView.setPlaceholderImage(R.drawable.ic_launcher);
imageView.setImageUrl("http://www.google.co.in/images/srpr/logo3w.png");
}

In brief, you are setting a placeholder image for the ImageView which gets replaced by the actual image when download completes. So the GridView will render immediately without delay.

Implementation Details:
So in your custom view (with an image + text) instead of using a simple ImageView, use WebImageView as shown above. When you get the JSON response set the TextView with the caption and the WebImageView with the image url.
So the caption will display immediately and the Image will load lazily.

Android Lazy loading of images with Grid view ( Without using any libraries )

Use this project and Add four files to your project i.e. https://github.com/thest1/LazyList/tree/master/src/com/fedorvlasov/lazylist

You don't need any Library. It will work standalone.

public class LazyAdapter extends BaseAdapter {

private Activity activity;
private String[] data;
private static LayoutInflater inflater=null;
**public ImageLoader imageLoader;**

public LazyAdapter(Activity a, String[] d) {
activity = a;
data=d;
inflater = (LayoutInflater)activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
**imageLoader=new ImageLoader(activity.getApplicationContext());**
}

public int getCount() {
return data.length;
}

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

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

public View getView(int position, View convertView, ViewGroup parent) {
View vi=convertView;
if(convertView==null)
vi = inflater.inflate(R.layout.item, null);

TextView text=(TextView)vi.findViewById(R.id.text);;
ImageView image=(ImageView)vi.findViewById(R.id.image);
text.setText("item "+position);
**imageLoader.DisplayImage(data[position], image);**
return vi;
}
}

Check Bold Strings. in Which custom LazyAdapter shows to set image inside your adapter. That adapter set to Gridview.

how to implement lazy loading of images in gridview

Use this library https://github.com/nostra13/Android-Universal-Image-Loader There is loading in every style... list, grid etc

Loading images from URLs into gridview

1.You are passing wrong arguments in the gridView's constructor.

  gvd = new GridViewAdapter(this, arrayList, arrayList3);

should be

  gvd = new GridViewAdapter(this, arrayList, arrayList2);

as stated in your code, arrayList2 consists of Images.

2.In adapter, change the second argument in constructor:

 from ArrayList<String> to ArrayList<Integer>

public GridViewAdapter(MainActivity mainActivity, ArrayList<String> prgmNameList, ArrayList<Integer> prgmImages) {
//...

}

After this, try passing it to Picasso.

New :
Can you try the following code :

      //server url
String imageURL = ""
//array of images passed in constructor to append with url
String arrayOfImages[] = imageId;
String completeImageURL = server + arrayOfImages[position];
Picasso.with(context)
.load(completeImageURL)
.into(holder.img);

How to Load image to grid view?

As you are having list of URLs (Images) and want to load them into GridView, you can try:

  1. Universal Image Loader for Android
  2. Android Image Loader by Novoda

Lazy load images in grid view decoding the image path from SD card

To save memory, always decode bitmaps to the sames size that you plan to display them. For this problem, the official documentation is your best friend. Download the BitmapFun project for exactly how to do this properly. https://developer.android.com/training/displaying-bitmaps/index.html

Downloads images from URL and display it in a GridView

First figure out a way of how you are going to download all the images from a single link, which I believe is somewhat difficult.

Then put all the link locations into a string array. now use the below code to download the images.

    public Drawable LoadImage(String url) {

Drawable d;
try {
InputStream is = (InputStream) new URL(url).getContent();
d = Drawable.createFromStream(is, "src name");
return d;
} catch (NullPointerException e) {
d = getResources().getDrawable(R.drawable.icon);
return d;
} catch (Exception e) {
d = getResources().getDrawable(R.drawable.icon);
return d;
}
}

Get the length of the string array in which you have stored the link locations. And inside of a for loop try executing the above code. This will return an drawable object which you can convert into either resources or Bitmap and add it to the GridView.



Related Topics



Leave a reply



Submit