Lazy uploads images to gridView

In my application, I need to download many images from URLs and display them in a gridView. (This can be from 1 to 200 images). I do not want to upload all the photos at once. I read about lazy loading, and my question is: can I only get one part of Json, load images in another thread , and only if the user scrolls down the gridView will I continue the other parts of Json, etc.

Edit: Hi. I want to implement multi select in this gridView, and it is difficult for me to implement the code in the getView () method of the adapter. This is an example that I am using: an example . How to 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; } 
+7
source share
4 answers

This is how I extract a few photos in my activity. You can use parts of it for your logic. I use this to get Facebook images from an album. Therefore, my needs (I guess) are different from your needs. But again, logic may come in handy.

Note: It will be long lasting .; -)

These are global declarations for use through 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 a block of code that retrieves the original 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 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 means that the user scrolls to the end and selects a 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 get the following 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 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 a helper class for SET and GET 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 need the adapter code, let me know. I use the Lazy Loading method in the adapter.

Phew Hope this helps. If you have further questions, 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 display "Progress" on boot:

Add a ProgressBar to the XML, where you have a GridView right below it. Play with 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 enter it in onCreate() and set its visibility as linlaProgressBar.setVisibility(View.GONE);

And in 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 to onPostExecute()

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

You can take a look at Using Views and GridView adapters from the Android documentation. Most importantly, the adapter calls the getView method, which transfers only the position of the records displayed on the screen and requests different positions when scrolling through the user.

The easiest way is to download the desired image using the getView method of your adapter using AsyncTask .

There is an example

+3
source

Speaking from experience, it is difficult to achieve smooth scrolling (and overall responsiveness) with reasonable memory consumption.

It would be nice to first look for existing solutions, for example, start here: Lazy loading images in a ListView

We are done with our own solutions. This is a background thread that makes download requests and only downloads images that are still visible, downloads and caches on external storage. When a new image arrives, the view is notified and decides when to notify the adapter for updating.

It also saves bandwidth, which was important in some cases.

0
source

I found IceMAN's answer very useful, but I also recommend avoiding using two AsyncTasks, and you can do it easily.

You need to create a universal method for extracting the necessary data, where you can make an if / else condition (as an example):

  movies = fetchMovie.execute(sort).get(); if (movies == null) { movieList = new ArrayList<>(); } else if (addMovies) { movieList.addAll(movies); } else { movieList = movies; } 

addMovies is a boolean in the onScroll method. In AsyncTask, specify the current page in the request URL and voila - you have reduced your code :)

0
source

All Articles