2014-12-05 134 views
2

我想使動態加載的圖像ListView,使用AsyncTask下載圖像,然後將其設置到ListView。我的問題是,在向下滾動時,圖像會隨機更改。Android - ListView圖像滾動時滾動

public class GetAllCustomerListViewAdapter extends BaseAdapter { 

private JSONArray dataArray; 
private Activity activity; 

private static LayoutInflater inflater = null; 
private static final String baseUrlForImage = "http://192.168.254.1/contact/images/"; 

public GetAllCustomerListViewAdapter(JSONArray jsonArray, Activity a) 
{ 
    this.dataArray = jsonArray; 
    this.activity = a; 


    inflater = (LayoutInflater) this.activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
} 

@Override 
public int getCount() { 
    return this.dataArray.length(); 
} 

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

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

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

    // set up convert view if it is null 
    final ListCell cell; 
    if (convertView == null) 
    { 
     convertView = inflater.inflate(R.layout.get_all_customer_list_view_cell, null); 
     cell = new ListCell(); 

     cell.FullName = (TextView) convertView.findViewById(R.id.customer_full_name); 
     cell.Age = (TextView) convertView.findViewById(R.id.customer_age); 

     cell.mobile = (ImageView) convertView.findViewById(R.id.customer_mobile); 

     convertView.setTag(cell); 
    } 
    else 
    { 
     cell = (ListCell) convertView.getTag(); 
    } 

    // change the data of cell 

    try 
    { 
     JSONObject jsonObject = this.dataArray.getJSONObject(position); 
     cell.FullName.setText(jsonObject.getString("FirstName")+" "+jsonObject.getString("LastName")); 
     cell.Age.setText(" "+jsonObject.getInt("Age")); 

     String nameOfImage = jsonObject.getString("id"); 

     String urlForImageInServer = "http://192.168.254.1/contact/getImage.php?id="+nameOfImage; 

     new AsyncTask<String, Void, Bitmap>() { 

      @Override 
      protected Bitmap doInBackground(String... params) { 
       String url = params[0]; 
       Bitmap icon = null; 

       try { 
        InputStream in = new java.net.URL(url).openStream(); 
        icon = BitmapFactory.decodeStream(in); 
       } catch (IOException e) { 
        // TODO Auto-generated catch block 
        e.printStackTrace(); 
       } 

       return icon; 
      } 

      protected void onPostExecute(Bitmap result) { 
       cell.mobile.setImageBitmap(result);    
      }    


     }.execute(urlForImageInServer);   



    } 
    catch (JSONException e) 
    { 
     e.printStackTrace(); 
    } 


    return convertView; 
} 



private class ListCell 
{ 
    private TextView FullName; 
    private TextView Age; 

    private ImageView mobile; 

}  

}

+0

沒有出示擔保其getview()調用甚至多少次,所以如果你在這個方法中考慮asyntask它是不好的做法.. – QuokMoon 2014-12-05 18:33:16

+0

另外,儘量在位圖懶洋洋地加載和緩存。會發生什麼事情是,每當你滾動到該項目上 - 無論你是否早些加載它,但滾動 - 它也會重新加載。 – MDragon00 2014-12-05 18:35:37

+0

我不是一個母語英語的人,但不應該是「when」或「while」或「on」而不是「whem」 – wawa 2014-12-05 18:35:56

回答

1

我只是做這個最近(凌晨1點實際上) - 問題是,ListView控件是積極回收的意見。因此,它獲得了仍然保存位圖的舊視圖。

以下是你需要的東西:

[注:檢查位圖更早緩存。如果沒有,做下面的步驟]

  1. 緩存位圖首先嚐試加載它
  2. 緩存目標ImageView的(和跟蹤哪些位圖是應該去什麼位圖)前。此外,清空ImageView以防萬一它還包含上一個再循環項目的位圖(imageView.setImageBitmap(null);
  3. 仔細檢查是否已經緩存了以前項目的緩存ImageView。如果以前已經被緩存了,那麼不知怎麼的說,接收到的位圖不應該被加載(我通過爲每個點存儲一個ImageView來實現這一點,一旦接收到Bitmap,如果該行的ImageView再次爲空,那麼我就不會加載位圖)
  4. 加載位圖(如上所述)如果你仍然應該 - 即,如果ImageView沒有再次回收。正如我前面提到的

該解決方案雖然有點複雜,但如果正確實施,效果非常好。如果你想要一個例子,請隨時檢查一個行動here in my current project

編輯的要求例如:

下面是一些不那麼僞僞。你仍然需要做的主要部分是實現延遲加載系統(這是一個完整的其他主題)。再次,請隨時訪問我上面鏈接的項目,特別是看看"ImageLoaderNoCache" NetworkUtil

public class GetAllCustomerListViewAdapter extends BaseAdapter { 

    private JSONArray dataArray; 
    private Activity activity; 

    private static LayoutInflater inflater = null; 
    private static final String baseUrlForImage = "http://192.168.254.1/contact/images/"; 

    // The list caches bitmaps as well as target imageViews, in order of the rows 
    private ArrayList<RowViewData> rowViewDataList; 

    public GetAllCustomerListViewAdapter(JSONArray jsonArray, Activity a) 
    { 
     this.dataArray = jsonArray; 
     this.activity = a; 


     inflater = (LayoutInflater) this.activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 

     // Initialize the list 
     rowViewDataList = new ArrayList<RowViewData>(dataArray.length()); 

     // This is more of a preference, but add in every item for the rowViewDataList 
     for(int i = 0; i < dataArray.length(); ++i) { 
      // Create a new, empty rowViewData instance and put it into the list 
      RowViewData rowData = new RowViewData(); 
      rowViewDataList.add(rowData); 
     } 
    } 

    @Override 
    public int getCount() { 
     return this.dataArray.length(); 
    } 

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

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

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

     // set up convert view if it is null 
     final ListCell cell; 
     if (convertView == null) 
     { 
      convertView = inflater.inflate(R.layout.get_all_customer_list_view_cell, null); 
      cell = new ListCell(); 

      cell.FullName = (TextView) convertView.findViewById(R.id.customer_full_name); 
      cell.Age = (TextView) convertView.findViewById(R.id.customer_age); 

      cell.mobile = (ImageView) convertView.findViewById(R.id.customer_mobile); 

      convertView.setTag(cell); 
     } 
     else 
     { 
      cell = (ListCell) convertView.getTag(); 
     } 

     // change the data of cell 

     try 
     { 
      JSONObject jsonObject = this.dataArray.getJSONObject(position); 
      cell.FullName.setText(jsonObject.getString("FirstName")+" "+jsonObject.getString("LastName")); 
      cell.Age.setText(" "+jsonObject.getInt("Age")); 


      // Get the rowViewData for this position 
      RowViewData curRowViewData = rowViewDataList.get(position); 

      // If the bitmap is already cached, just use it 
      if(curRowViewData.bitmap != null) { 
       cell.mobile.setImageBitmap(curRowViewData.bitmap); 
      } 
      // Otherwise, gotta do some real work 
      else { 
       // First, set the cell's imageView's bitmap to null 
       //  [in case this is a recycled view already with a bitmap] 
       cell.mobile.setImageBitmap(null); 

       // Then, start up the caching system 
       String nameOfImage = jsonObject.getString("id"); 
       String urlForImageInServer = "http://192.168.254.1/contact/getImage.php?id="+nameOfImage; 

       // Create a system to load images lazily and then receive the bitmaps 
       // Look at my ImageLoaderNoCache for an example. Feel free to reuse it 
       /** 
       * this = this adapter should implement an interface. Look below for the corresponding method 
       * url = image source url 
       * position = position this bitmap belongs to. Will get returned along with bitmap for reference 
       */ 
       LazyImageLoader.GetBitmap(this, url, position); 

       // Cache/target this imageView for later 
       curRowViewData.targetImageView = cell.mobile; 

       // Double check this imageView is not being targeted already elsewhere 
       //  ie, one of the recycling fixes [else, two bitmaps would load at once, etc] 
       // Also, probably could be more efficient 
       for(int i = 0; i < rowViewDataList.size(); ++i) { 
        // If this is the current position, then skip all the logic for this round 
        if(i == position) continue; 

        // Get the rowViewData for this round 
         // Yeah... I should've used "cell" instead of row for you... 
        RowViewData checkRowData = rowViewDataList.get(i); 

        // If the targeted ImageView is the same, null-ify it 
        if(checkRowData.targetImageView == curRowViewData.targetImageView) { 
         // The old one should be null as the bitmap should not load suddenly into 
         //  the current recycled item 
         checkRowData.targetImageView = null; 

         // Personally, I knew that there would only be one copy at any time 
         //  so I tried to save time by breaking out here. Feel free to be 
         //   cautious and comment out the break statement 
         break; 
        } 
       } 
      } 
     } 
     catch (JSONException e) 
     { 
      e.printStackTrace(); 
     } 


     return convertView; 
    } 

    /** 
    * Should be called as part of an interface with the LazyImageLoader 
    * @param bitmap - The lazily loaded bitmap that was requested earlier 
    * @param position - The row/cell position that the bitmap was requested for 
    */ 
    public void getBitmapForPosition(Bitmap bitmap, int position) { 
     // Get the rowViewData instance for this row/position 
     RowViewData curRowData = rowViewDataList.get(position); 

     // Cache the bitmap 
     curRowData.bitmap = bitmap; 

     // Check if the bitmap should be loaded still 
     if(curRowData.targetImageView != null) { 
      curRowData.targetImageView.setImageBitmap(bitmap); 

      // Not sure if strictly necessary, but good practice to make the cached view null now 
      curRowData.targetImageView = null; 
     } 
    } 

    private class ListCell 
    { 
     private TextView FullName; 
     private TextView Age; 

     private ImageView mobile; 

    } 

    // Holds all the data for lazily loading an image with a bitmap 
    private class RowViewData { 
     public ImageView targetImageView; 
     public Bitmap bitmap; 
    } 
} 
+0

你能告訴我應該如何離開我的代碼嗎? – 2014-12-05 18:38:04

+0

我需要花幾個小時才能回到這個頁面,但是您希望我寫僞代碼嗎? – MDragon00 2014-12-05 18:39:06

+0

它可能會幫助很多 – 2014-12-05 18:45:37