2012-11-07 72 views
7

在我的應用程序中,我需要從網址下載大量圖片並將它們顯示在gridView中。 (它可以在1-200張圖片之間)。我不想一次下載所有照片。我讀了關於懶惰下載和我的問題是:我可以只獲得Json的一部分,下載圖片在不同的線程,,並且只有當用戶向下滾動 gridView時,我會繼續到Json的其他部分, 等等?懶惰下載圖像到gridView

編輯:你好。我想在這個GridView中實現多選,我很難在適配器的getView()方法中實現代碼。這是我正在使用的示例:example。我怎麼能在我的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; 
} 
+0

你是如何請求獲取JSON數據?源支持分頁嗎? –

+0

如果有更多照片需要加載,我會從源代碼中獲得「下一個網址」 – user1787773

+0

@Siddharth Lele:如果您可以查看我編輯過的問題,我將不勝感激。非常感謝你的幫助。 – user1787773

回答

37

這是我在我的活動獲取多張照片。你可以使用它的一部分來適應你的邏輯。我用它從相冊中獲取Facebook圖像。所以我的需求(我假設)與您的需求不同。但是,這個邏輯對你來說可能是有用的。

注意:這將是漫長的。 ;-)

這些是全局聲明用於通過活動使用:

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

} 

這是當檢測用戶已滾動到結尾並獲取新的一組圖像:

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

} 

這是輔助類來SETGET數據從上面的查詢收集:

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代碼,讓我知道。我在適配器中使用Fedor'sLazy Loading方法。

Phew。希望這有助於任何。如果您有進一步的問題,請隨時詢問。:-)

編輯:適配器代碼添加:

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; 

    } 
} 

編輯:添加的步驟,以顯示進度,同時加載:

添加一個進度條到你的XML,你必須在GridView右側下方。如果它帶來任何問題,請隨身攜帶重量。

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

在Java中,聲明Linearlayout linlaProgressBar Global和在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); 
+0

這正是我需要的!我現在會嘗試。我很感激你是否可以發佈適配器代碼。謝謝! – user1787773

+0

@ user1787773:「適配器」代碼已添加到帖子中。 –

+0

非常感謝!它的工作很棒。你知道是否有可能在網格的底部添加一個小的加載符號? (時間加載需要幾分鐘) – user1787773

3

您可以採取從Android文檔一看就Using adapter ViewsGridView。 最重要的是,適配器調用方法getView只傳遞屏幕上顯示的條目的位置,並在用戶滾動時詢問不同的位置。

最簡單的方法是使用AsyncTask將適配器的getView方法下載所需的圖像。

有一個example

0

從經驗談起,在合理消耗內存的同時實現平滑滾動(以及整體響應)是非常棘手的。

這將是一個好主意,尋找現有的解決方案首先,例如,從這裏開始: Lazy load of images in ListView

我們結束了一個定製的專有解決方案。它是一個後臺線程,它將隊列下載請求和下載以及緩存到外部存儲器上,只有那些仍然可見的圖像。當新圖像到達時,視圖會得到通知,並決定何時通知適配器進行更新。

它還節省了帶寬,這在某些情況下很重要。

+0

是否有代碼我可以在任何地方看到實現你們實現的東西?謝謝! –

0

我發現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提供查詢網址當前頁和瞧 - 你讓你的代碼更小:)