2015-10-11 43 views
1

我正在創建一個應用程序,從互聯網中檢索圖像,並以無限滾動顯示在列表視圖中。問題是滾動一段時間之後,我越來越內存不足。任何人都可以告訴我我在這裏做錯了什麼?由於使用無限滾動時獲取outofmemoryerror android listview

MainActivity:

@Override 
protected void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.activity_main); 
     context=this; 

    fetchPosts(lPost); 
     lv=(ListView) findViewById(R.id.listView1); 
     lv.setOnScrollListener(new InfiniteScrollListener(5) { 
      @Override 
      public void loadMore(int page, int totalItemsCount) { 
       fetchPosts(lPost); 
      } 
     }); 

     cAdapter = new CustomAdapter(this, prgmNameList,prgmImages, prgmLikeNum, prgmCommentNum); 
     lv.setAdapter(cAdapter); 

}  



public void fetchImages(String imageName, int position) { 

    loadImage task = new loadImage(MainActivity.this, R.id.listView1, imageName, position); 

    task.setOnResultsListener(MainActivity.this); 
    task.execute("null"); 
} 

public void fetchPosts(int lastPost){ 
    LoadPosts lTask = new LoadPosts(MainActivity.this, lastPost); 

    lTask.setOnResultsListener(MainActivity.this); 
    lTask.execute("asd"); 

} 

@Override 
public void onResultsSucceeded(Bitmap image, int position) { 

      if(prgmImages.size() > position) 
      { 
       if(lPost==0) 
        prgmImages.set(position, image); 
       else 
        prgmImages.set(position+lPost-5, image); 
      } 

        cAdapter.notifyDataSetChanged(); 

} 



@Override 
public void onPostsSucceeded(JSONArray obj) throws JSONException { 

    //tView.setText(obj.toString()); 
    lPost += obj.length(); 

    for (int i = 0; i < obj.length(); i++) { 
     JSONObject object = obj.getJSONObject(i); 
     String postTitle = object.getString("post_title"); 
     String imageName = object.getString("image_name"); 
     String likeNum = object.getString("like_num"); 
     String commentNum = object.getString("comment_num"); 
     fetchImages(imageName, i); 
     prgmImages.add(null); 
     prgmNameList.add(postTitle); 
     prgmLikeNum.add(likeNum); 
     prgmCommentNum.add(commentNum); 

    } 


} 

CustomAdapter:

public CustomAdapter(MainActivity mainActivity, ArrayList<String>    prgmNameList, ArrayList<Bitmap> prgmImages, ArrayList<String> prgmLikeNum, ArrayList<String> prgmCommentNum) { 
    // TODO Auto-generated constructor stub 
    context=mainActivity; 
    activity=mainActivity; 
    inflater = (LayoutInflater)context. 
      getSystemService(Context.LAYOUT_INFLATER_SERVICE); 

    result = prgmNameList; 
    imageId=prgmImages; 
    likeNum=prgmLikeNum; 
    commentNum=prgmCommentNum; 

} 






public class Holder 
{ 
    TextView tv; 
    ImageView img; 
    TextView likes; 
    TextView comments; 
} 
@Override 
public View getView(final int position, View convertView, ViewGroup parent) { 
    // TODO Auto-generated method stub 
    holder=new Holder(); 
    View rowView = convertView; 
    if(rowView == null) 
    { 
     rowView = inflater.inflate(R.layout.post_item, null); 
    } 
     holder.tv=(TextView) rowView.findViewById(R.id.postTitle); 
     holder.img=(ImageView) rowView.findViewById(R.id.postImage);  
     holder.likes=(TextView) rowView.findViewById(R.id.likeNum); 
     holder.comments=(TextView) rowView.findViewById(R.id.commentNum); 
     holder.tv.setText(result.get(position)); 
     holder.img.setImageBitmap(imageId.get(position)); 
     holder.likes.setText(likeNum.get(position)); 
     holder.comments.setText(commentNum.get(position)); 
    rowView.setOnClickListener(new OnClickListener() {    
     @Override 
     public void onClick(View v) { 
      // TODO Auto-generated method stub 
     // Toast.makeText(context, "You Clicked "+result[position], Toast.LENGTH_LONG).show(); 
     } 
    }); 
    return rowView; 
} 
+1

好像你在數組列表中存儲了很多位圖,這消耗了大量的內存。 –

+0

你建議如何避免這種情況? @RahulTiwari –

+0

泄漏金絲雀會立即指出您的問題...... – OceanLife

回答

2

以下是提高你的列表性能,擺脫

  1. 一個Android應用程序有一個非常有限的堆所以OOM的一些要點你不應該在List下載並存儲很多位圖,它會觸發一個OOM。

    解決方法是在getView()被調用時開始下載,因此您應該有一個下載圖像的請求,而不是holder.img.setImageBitmap(imageId.get(position));。在Android的

    管理圖像列表是困難的,你必須照顧:

    • 位圖大小調整
    • 線程併發
    • 緩存管理

    爲了簡單起見,我建議你可以使用這樣的庫:

    例如與滑翔下載中心圖像您有:

    Glide.with(mContext) 
        .load(IMAGE_URL) 
        .into(holder.img); 
    

    滑翔/畢加索會管理的位圖調整大小,併發和緩存:)

  2. 從android doc

您的代碼可能會在滾動ListView時頻繁地調用findViewById(),這會降低性能。

更多信息here

所以,你必須將這些線移動到if(rowView == null)條件

holder.tv=(TextView) rowView.findViewById(R.id.postTitle); 
holder.img=(ImageView) rowView.findViewById(R.id.postImage);  
holder.likes=(TextView) rowView.findViewById(R.id.likeNum); 
holder.comments=(TextView) rowView.findViewById(R.id.commentNum); 
  • 你不應該在每次調用getView()創建一個新的持有人!
  • 這裏是getView()

    @Override 
    public View getView(final int position, View convertView, ViewGroup parent) { 
        Holder holder; 
    
        // Check if the item's view is recycled 
        if(convertView == null) 
        { 
         // The item's view doesn't exist 
         // Create the item's view 
         LayoutInflater inflater = ((Activity) mContext).getLayoutInflater(); 
         convertView = inflater.inflate(R.layout.post_item, null); 
    
         holder = new Holder(); // Create the holder 
    
         holder.tv=(TextView) rowView.findViewById(R.id.postTitle); 
         holder.img=(ImageView) rowView.findViewById(R.id.postImage);  
         holder.likes=(TextView) rowView.findViewById(R.id.likeNum); 
         holder.comments=(TextView) rowView.findViewById(R.id.commentNum); 
    
         // Store the holder with the view. 
         convertView.setTag(holder); 
        } 
        else 
        { 
         // The item's view already exist 
         // Retrieve the older 
         holder = (Holder) convertView.getTag(); 
        } 
    
        holder.tv.setText(result.get(position)); 
        holder.img.setImageBitmap(imageId.get(position)); 
        Glide.with(mContext) 
         .load(imageUrls.get(position)) 
         .into(holder.img) 
        holder.likes.setText(likeNum.get(position)); 
        holder.comments.setText(commentNum.get(position)); 
    
        convertView.setOnClickListener(new OnClickListener() {  
    
         @Override 
         public void onClick(View v) { 
          // TODO impl 
         } 
        }); 
    
        return convertView; 
    } 
    

    更多信息here一個正確實施。

    希望它的幫助:)

    +0

    嗨。這個解決方案寫得非常好。我已經嘗試過了,它會處理OOM錯誤。但我不會使用它,因爲它需要太多的時間來加載圖像,這使得listview不那麼流暢。我用webviews而不是imageviews來加載我的圖片。謝謝。 –

    +0

    嗨。由於圖像大小,可能花費太多時間?什麼是你想要顯示的平均圖像尺寸?您應該(如果可能)在下載圖像之前使用服務調整圖像大小。對於圖像列表,您可以只使用一半ImageView像素尺寸的位圖。例如,對於100 * 100像素的ImageView,您可以下載只有50 * 50像素的圖像,它看起來不錯。 – DarzuL

    +0

    Glide絕對不是問題。我不喜歡它如何對待圖像。我使用了webviews,而且速度非常快。謝謝你的幫助。乾杯:) –

    0

    看來你加載了很多位圖,你不內存免費給,如果你不再使用它們。

    你可以做到這一點(當位圖是位圖就不需要了)

    bitmap.recycle(); 
    bitmap=null; 
    

    在你的適配器類是使用持有人的錯誤。這不會影響內存問題,但會降低應用程序的性能。通常情況下,您使用視圖持有者來避免經常調用findViewById。如果rowview == null,則應在您的視圖和佈局之間鏈接一次。 如果你已經完成了這個操作,並且第二次從getView中加載相同的視圖,那麼rowview將爲!= null,並且不需要再調用findViewById,這樣可以節省大量時間。

    所以,你的代碼應該是這樣的:

    if(rowview==null) 
    { 
        rowView = inflater.inflate(R.layout.post_item, null); 
        holder.tv=(TextView) rowView.findViewById(R.id.postTitle); 
        holder.img=(ImageView) rowView.findViewById(R.id.postImage);  
        holder.likes=(TextView) rowView.findViewById(R.id.likeNum); 
        holder.comments=(TextView) rowView.findViewById(R.id.commentNum); 
    } 
    holder.tv.setText(result.get(position)); 
    holder.img.setImageBitmap(imageId.get(position)); 
    holder.likes.setText(likeNum.get(position)); 
    holder.comments.setText(commentNum.get(position)); 
    rowView.setOnClickListener(new OnClickListener() {    
        @Override 
        public void onClick(View v) { 
         // TODO Auto-generated method stub 
        // Toast.makeText(context, "You Clicked "+result[position], Toast.LENGTH_LONG).show(); 
        } 
    });