2013-03-29 67 views
0

我寫了一個從JSON中獲取圖像的類。它正在工作,bur存在內存問題。當我向下滾動應用程序時,它正在泄漏內存中。這裏是我的代碼。Android中的ListView內存泄漏

package com.nexum.senddata; 

public class MainActivity extends Activity { 

private ListView list; 
private MyAdapter adapter; 

    private final String parsingUrl = "http://sametdede.com/expo/data.json"; 
private String tag_coord = "Coord"; 
private String tag_lat = "Lat"; 
private String tag_lon = "Lon";// Double 
private String tag_image = "Image"; 
private String tag_InIzmir = "InIzmir"; 
private String tag_name = "Name"; 

private ProgressDialog pDialog; 

private static int clickedItemPosition = -1; 
private final int REQUEST_CODE_DETAIL = 1; 

ArrayList<CoordItem> items; 

@Override 
protected void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.main); 

    items = new ArrayList<CoordItem>(); 
    adapter = new MyAdapter(this, R.layout.list_item, items); 

    list = (ListView) findViewById(R.id.exampList); 
    list.setAdapter(adapter); 

    pDialog = new ProgressDialog(this); 
    pDialog.requestWindowFeature(Window.FEATURE_NO_TITLE); 
    pDialog.setMessage("Veriler alınıyor..."); 

    new ListViewLoad().execute(); 

    list.setOnItemClickListener(new OnItemClickListener() { 

     @SuppressLint("ShowToast") 
     @Override 
     public void onItemClick(AdapterView<?> a, View v, int position, 
       long id) { 
      /* 
      * String bulunma = ""; if (items.get(position).inIzmir) { 
      * bulunma+="İzmir de bulundu."; }else{ 
      * bulunma+="İzmir de bulunmadı."; } String 
      * s="Name:"+items.get(position).name+"\nInIzmir:"+bulunma; 
      * Toast.makeText(getApplicationContext(), s, 
      * Toast.LENGTH_LONG).show(); 
      */ 

      clickedItemPosition = position; 
      Intent myIntent = new Intent(MainActivity.this, 
        DetailActivity.class); 
      Bundle bundle = new Bundle(); 
      bundle.putParcelable(
        "parcelable_key", 
        new CoordItem(items.get(position).name, items 
          .get(position).img, items.get(position).lat, 
          items.get(position).lon, 
          items.get(position).inIzmir)); 
      myIntent.putExtras(bundle); 
      // Güncelleme olayı burada başlıyor 
      // startActivityForResult(myIntent, REQUEST_CODE_DETAIL); 

      startActivityForResult(myIntent, REQUEST_CODE_DETAIL); 

     } 

    }); 

} 

@Override 
protected void onActivityResult(int requestCode, int resultCode, Intent data) { 
    // TODO Auto-generated method stub 
    super.onActivityResult(requestCode, resultCode, data); 

    if (requestCode == REQUEST_CODE_DETAIL && resultCode == RESULT_OK 
      && data != null) { 
     CoordItem coorditem = new CoordItem(data.getStringExtra("name"), 
       items.get(clickedItemPosition).img, Double.parseDouble(data 
         .getStringExtra("lat")), Double.parseDouble(data 
         .getStringExtra("lon")), 
       items.get(clickedItemPosition).inIzmir); 

     items.set(clickedItemPosition, coorditem); 
     adapter.notifyDataSetChanged(); 
     Toast.makeText(getApplicationContext(), "Guncelleme yapıldı.", 
       Toast.LENGTH_SHORT).show(); 
    } 
    /* 
    * CoordItem coorditem = new CoordItem(data.getStringExtra("name"), 
    * items.get(clickedItemPosition).img, 
    * Double.parseDouble(data.getStringExtra("lat")),Double.parseDouble(
    * data.getStringExtra("lon")), items.get(clickedItemPosition).inIzmir); 
    * 
    * items.set(clickedItemPosition, coorditem); 
    * adapter.notifyDataSetChanged(); 
    * Toast.makeText(getApplicationContext(), "Guncelleme yapıldı.", 
    * Toast.LENGTH_SHORT).show(); 
    */ 

} 

private class ListViewLoad extends AsyncTask<Void, Void, Void> { 

    @Override 
    protected void onPreExecute() { 
     super.onPreExecute(); 
     pDialog.show(); 
    } 

    @Override 
    protected Void doInBackground(Void... params) { 

     String json = getStringFromURL(parsingUrl); 
     try { 
      final JSONArray jArray = new JSONArray(json); 

      for (int i = 0; i < jArray.length(); i++) { 
       JSONObject c = jArray.getJSONObject(i); 
       JSONObject coord = c.getJSONObject(tag_coord); 
       double lat = coord.getDouble(tag_lat); 
       double lon = coord.getDouble(tag_lon); 
       String image = c.getString(tag_image); 
       boolean InIzmir = c.getBoolean(tag_InIzmir); 
       String name = c.getString(tag_name); 

       CoordItem item = new CoordItem(name, image, lat, lon, 
         InIzmir); 
       items.add(item); 
      } 

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

     return null; 
    } 

    @Override 
    protected void onPostExecute(Void result) { 
     super.onPostExecute(result); 

     adapter.notifyDataSetChanged(); 

     pDialog.dismiss(); 
    } 

} 

private class MyAdapter extends ArrayAdapter<CoordItem> { 

    private LayoutInflater inflater; 

    public MyAdapter(Context context, int textViewResourceId, 
      ArrayList<CoordItem> objects) { 
     super(context, textViewResourceId, objects); 

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

    @Override 
    public int getCount() { 
     if (items != null) 
      return items.size(); 
     else 
      return 0; 
    } 

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

     ViewHolder viewholder = null; 

     if (convertView == null) { 
      viewholder = new ViewHolder(); 

      convertView = inflater.inflate(R.layout.list_item, parent, 
        false); 
      viewholder.listItemImage = (ImageView) convertView 
        .findViewById(R.id.listItemImage); 

      viewholder.listItemName = (TextView) convertView 
        .findViewById(R.id.listItemName); 
      viewholder.listItemInIzmir = (TextView) convertView 
        .findViewById(R.id.listItemInIzmir); 
      viewholder.listItemLatitude = (TextView) convertView 
        .findViewById(R.id.listItemLatitude); 
      viewholder.listItemLongitude = (TextView) convertView 
        .findViewById(R.id.listItemLongitude); 
      convertView.setTag(viewholder); 
     } else { 
      viewholder = (ViewHolder) convertView.getTag(); 
     } 

     viewholder.listItemName.setText(items.get(position).name); 
     if (items.get(position).inIzmir) { 
      viewholder.listItemInIzmir.setText("Izmirde."); 
     } else { 
      viewholder.listItemInIzmir.setText("Izmirde degil."); 
     } 

     try { 
      viewholder.listItemImage 
        .setImageDrawable(getDrawableFromUrl(new URL(items.get(
          position).getImg()))); 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 

     return convertView; 
    } 

    public Drawable getDrawableFromUrl(URL url) { 
     try { 
      InputStream is = (InputStream) url.getContent(); 
      Drawable d = Drawable.createFromStream(is, "src"); 
      return d; 
     } catch (Exception e) { 
      return null; 
     } 
    } 

} 

/** 
* Burada layoutinflater da kullandığımız layoutun componentlerini 
* yazıyoruz.Bu da bizim list_item.xml imizdir. 
*/ 
static class ViewHolder { 
    ImageView listItemImage; 
    TextView listItemName, listItemInIzmir, listItemLatitude, 
      listItemLongitude; 
} 

public String getStringFromURL(String url) { 

    // Making HTTP request 
    String json = ""; 
    InputStream is = null; 
    try { 
     // defaultHttpClient 
     DefaultHttpClient httpClient = new DefaultHttpClient(); 
     HttpPost httpPost = new HttpPost(url); 

     HttpResponse httpResponse = httpClient.execute(httpPost); 
     HttpEntity httpEntity = httpResponse.getEntity(); 
     is = httpEntity.getContent(); 

    } catch (UnsupportedEncodingException e) { 
     e.printStackTrace(); 
    } catch (ClientProtocolException e) { 
     e.printStackTrace(); 
    } catch (IOException e) { 
     e.printStackTrace(); 
    } 

    try { 
     BufferedReader reader = new BufferedReader(new InputStreamReader(
       is, "UTF-8"), 8); 
     StringBuilder sb = new StringBuilder(); 
     String line = null; 
     while ((line = reader.readLine()) != null) { 
      sb.append(line + "\n"); 
     } 
     is.close(); 
     json = sb.toString(); 
    } catch (Exception e) { 
     e.printStackTrace(); 
    } 

    // return JSON String 
    return json; 

} 

}

我在哪裏可以閱讀和獲取的圖像用於執行速度更快,而不是內存泄漏?

回答

1

您已經使用了ViewHolder。

使用LazyList或通用圖像裝載機

懶列表

圖像可以被緩存到本地SD卡或手機mmeory。網址被認爲是關鍵。如果密鑰存在於sdcard中,則顯示來自SD卡的圖像,否則通過從服務器下載顯示圖像並將其緩存到您選擇的位置。緩存限制可以設置。您也可以選擇自己的位置來緩存圖像。緩存也可以被清除。

而不是用戶等待下載大圖像,然後顯示懶惰列表按需加載圖像。由於緩存的圖像區域可以離線顯示圖像。

https://github.com/thest1/LazyList。懶列表

在你getview

imageLoader.DisplayImage(imageurl, imageview); 

ImageLoader的顯示方式

public void DisplayImage(String url, ImageView imageView) //url and imageview as parameters 
{ 
imageViews.put(imageView, url); 
Bitmap bitmap=memoryCache.get(url); //get image from cache using url as key 
if(bitmap!=null)   //if image exists 
    imageView.setImageBitmap(bitmap); //dispaly iamge 
else //downlaod image and dispaly. add to cache. 
{ 
    queuePhoto(url, imageView); 
    imageView.setImageResource(stub_id); 
} 
} 

通用圖像裝載機

https://github.com/nostra13/Android-Universal-Image-Loader

可以從本地或從服務器加載圖像。

它基於Lazy List(基於相同原理)。但它有很多其他配置。我寧願使用通用圖像加載程序,因爲它提供了更多的配置選項。如果downlaod失敗,您可以顯示錯誤圖像。可以顯示圓角的圖像。可以緩存在光盤或內存上。可以壓縮圖像。

在您的自定義適配器構造

File cacheDir = StorageUtils.getOwnCacheDirectory(activity context, "your folder");//for caching 

// Get singletone instance of ImageLoader 
imageLoader = ImageLoader.getInstance(); 
// Create configuration for ImageLoader (all options are optional) 
ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(a) 
// You can pass your own memory cache implementation 
.discCache(new UnlimitedDiscCache(cacheDir)) // You can pass your own disc cache implementation 
.discCacheFileNameGenerator(new HashCodeFileNameGenerator()) 
.enableLogging() 
.build(); 
// Initialize ImageLoader with created configuration. Do it once. 
imageLoader.init(config); 
options = new DisplayImageOptions.Builder() 
.showStubImage(R.drawable.stub_id)//display stub image untik image is loaded 
.cacheInMemory() 
.cacheOnDisc() 
.displayer(new RoundedBitmapDisplayer(20)) 
.build(); 

在你getView()

ImageView image=(ImageView)vi.findViewById(R.id.imageview); 
imageLoader.displayImage(imageurl, image,options);//provide imageurl, imageview and options. 

你可以用其他選項配置,以滿足您的需求。

+0

我從JSON獲取網址。那麼如何根據我的代碼初始化ImageLoader? – emrerme

+0

imageLoader.displayImage(imageurl,image,options);如果您使用的是圖像加載器,請使用上面的圖像加載器。傳遞圖像網址到你的cusotm適配器,並提供URL像url [position] – Raghunandan

+0

No no。我怎樣才能初始化ImageLoader類。它需要一些參數ImageLoader imageloader = new ImageLoader(?);在我的代碼中,我可以放什麼?在您的適配器構造函數中感謝 – emrerme