Lazy загружает изображения в gridView

В моем приложении мне нужно загрузить много изображений из URL-адресов и отобразить их в gridView. (Это может быть от 1 до 200 изображений). Я не хочу загружать все фотографии сразу. Я читал о ленивой загрузке, и мой вопрос: могу ли я получить только одну часть Json, загрузить изображения в другом streamе, и только если пользователь прокрутит вниз по gridView, я продолжу другие части Json и скоро?

Изменить: Привет. Я хочу реализовать multi select в этом gridView, и мне трудно реализовать код в методе getView () адаптера. Это пример, который я использую: пример . Как я могу объединить этот код в моем методе getView ():

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); } } 

мой код getView ():

 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; } 

Вот как я получаю несколько фотографий в своей деятельности. Вы можете использовать его части для своей логики. Я использую это для получения изображений Facebook из альбома. Поэтому мои потребности (я предполагаю) отличаются от ваших потребностей. Но опять-таки логика может быть вам полезна.

Примечание. Это будет длительным. 😉

Это глобальные декларации для использования через 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; 

Это блок кода, который извлекает исходный набор изображений:

 private class getPhotosData extends AsyncTask { @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; } } 

Это нужно, чтобы определить, когда пользователь прокручивается до конца и извлекает новый набор изображений:

 // 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(); } } } }); 

И, наконец, так я получаю следующий набор изображений:

 private class loadMorePhotos extends AsyncTask { @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; } } 

И это вспомогательный class для SET и GET данные, собранные из запросов выше:

 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; } } 

Если вам также нужен код adapter , сообщите мне. Я использую метод Lazy Loading Fedor в адаптере.

Уф. Надеюсь, что это поможет. Если у вас есть дополнительные вопросы, не стесняйтесь спрашивать. 🙂

EDIT: добавлен код адаптера:

 public class PhotosAdapter extends BaseAdapter { private Activity activity; ArrayList arrayPhotos; private static LayoutInflater inflater = null; ImageLoader imageLoader; public PhotosAdapter(Activity a, ArrayList 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: Добавлены шаги для отображения «Прогресс» при загрузке:

Добавьте ProgressBar в XML, где у вас есть GridView прямо под ним. Играйте с весом, если это вызывает какие-либо проблемы.

    

В вашей Java объявите Linearlayout linlaProgressBar как Global и Linearlayout linlaProgressBar его в onCreate() и установите его видимость как linlaProgressBar.setVisibility(View.GONE);

И в onPreExecute() используйте его вот так:

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

И, наконец, добавьте это в onPostExecute()

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

Вы можете взглянуть на « Использование адаптивных представлений» и « GridView» из документации Android. Самое главное, что адаптер вызывает метод getView передающий только позицию записей, отображаемых на экране, и запрашивает разные позиции при getView пользователя.

Самый простой способ – загрузить требуемое изображение в методе getView вашего адаптера с помощью AsyncTask .

Существует пример

Говоря по опыту, сложно добиться плавной прокрутки (и полной отзывчивости) при разумном потреблении памяти.

Было бы неплохо сначала искать существующие решения, например, начать здесь: ленивая загрузка изображений в ListView

Мы закончили с собственными собственными решениями. Это фоновый stream, который ставит запросы на загрузку и загружает и кэширует на внешнем хранилище только изображения, которые все еще видны. Когда приходит новое изображение, уведомление получает уведомление и решает, когда следует уведомить адаптер для обновления.

Он также экономит полосу пропускания, что было важно в некоторых случаях.

Я нашел ответ IceMAN очень полезным, но я также рекомендую избегать использования двух AsyncTasks, и вы можете сделать это легко.

Вам нужно создать универсальный метод для извлечения необходимых данных, где вы можете сделать условие if / else (в качестве примера):

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

addMovies является логическим в методе onScroll. В AsyncTask укажите текущую страницу в URL-адресе запроса и voila – вы уменьшили свой код 🙂

Давайте будем гением компьютера.