2012-09-22 16 views
8

Tôi bị rò rỉ bộ nhớ trong tệp này, tôi không thể tìm thấy chính xác ở đâu, nhưng tôi nghĩ là hình ảnh xung quanh ->(Bitmap bm = BitmapFactory.decodeFile(filename)), tôi đã thử nhiều cách khác nhau nhưng tôi không thể làm được.Rò rỉ bộ nhớ trong Android khi cố gắng gửi biểu mẫu có hình ảnh tới máy chủ PHP

package prod.vegs; 

//All imports here but not need to write them all now :-) 


public class ProductForm extends Activity { 

private static int TAKE_PICTURE = 1; 
private static int SELECT_PICTURE = 2; 

//JSON Response node names 
private static String KEY_SUCCESS = "success"; 
private static String ERROR_MSG = "error_msg"; 
private static String KEY_TYPES = "subtypes"; 
private static String TYPE_NAME = "name"; 
private static String TYPE_ID = "id_type"; 
private static String PRODUCT_ID = "id_product"; 

private JSONObject json; 
private JSONParser jsonParser; 
private String barcodeStr; 
private String filename; 
private int code; 
private ProgressDialog dialog; 
private TypeClass[] items; 
private TypeClass[] sub_items; 

//Declare assets objects 
Spinner type; 
Spinner subtype; 
TextView errorMsg; 
TextView description; 
TextView name; 
Button camera; 
Button gallery; 
Intent intent; 
ImageView preview; 
Bundle bundle; 
LinearLayout errorMsgContainer; 

Context context; 

public void onCreate(Bundle icicle) { 
    super.onCreate(icicle); 
    setContentView(R.layout.product_form); 
    context = this; 

    Bundle b = getIntent().getExtras(); 
    barcodeStr = b.getString("barcode"); 

    jsonParser = new JSONParser(); 
    dialog = new ProgressDialog(this); 
    dialog.setMessage(getString(R.string.loading)); 
    dialog.setTitle(getString(R.string.progress)); 
    dialog.setCancelable(true); 

    //Set assets 
    name = (TextView) findViewById(R.id.productName); 
    description = (TextView) findViewById(R.id.productDescription); 
    errorMsg = (TextView) findViewById(R.id.error_msg); 
    errorMsgContainer = (LinearLayout) findViewById(R.id.error_msg_container); 
    type = (Spinner) findViewById(R.id.productParentType); 
    subtype = (Spinner) findViewById(R.id.productType); 
    camera = (Button) findViewById(R.id.productCamera); 
    gallery = (Button) findViewById(R.id.productGallery); 
    preview = (ImageView) findViewById(R.id.productPreview); 
    filename = Environment.getExternalStorageDirectory() + String.format(getString(R.string.api_product_form_picture_file), barcodeStr); 

    Boolean fromScanner = b.getBoolean("scanner"); 
    if (fromScanner == true) { 

     AlertDialog.Builder alertbox = new AlertDialog.Builder(this); 
     alertbox.setMessage(getString(R.string.insert_product)); 
     alertbox.setPositiveButton(getString(R.string.yes), 
      new DialogInterface.OnClickListener() { 
       public void onClick(DialogInterface arg_1, int arg_num) { 
        final Functions function = new Functions(); 
        List<NameValuePair> params = new ArrayList<NameValuePair>(); 
        String url = String.format(getString(R.string.api_product_form_types_url), getString(R.string.api_url)); 
        json = function.loadJSONUrl(url, params); 
        if(json != null){ 
         try { 
          if (json.getString(KEY_SUCCESS) != null) { 
           String res = json.getString(KEY_SUCCESS); 
           if(Integer.parseInt(res) == 1){ 

            JSONArray types = json.getJSONArray(KEY_TYPES); 
            items = convertJSONArray(types); 

            SpinAdapter listViewArrayAdapter = new SpinAdapter(context, android.R.layout.simple_spinner_item, items); 
            listViewArrayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); 
            type.setAdapter(listViewArrayAdapter); 
            type.setOnItemSelectedListener(new OnItemSelectedListener(){ 
             public void onItemSelected(AdapterView<?> parent, View v, int pos, long id) { 
              try { 
               String url = String.format(getString(R.string.api_subtypes_id_url), getString(R.string.api_url), ((TypeClass) type.getSelectedItem()).getId()); 
               List<NameValuePair> params = new ArrayList<NameValuePair>(); 
               JSONObject json_subtypes = function.loadJSONUrl(url, params); 
               if (json_subtypes.getString(KEY_SUCCESS) != null) { 
                JSONArray subtypes = json_subtypes.getJSONArray(KEY_TYPES); 
                sub_items = convertJSONArray(subtypes); 
                SpinAdapter subTypeAdapter = new SpinAdapter(context, android.R.layout.simple_spinner_item, sub_items); 
                subTypeAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); 
                subtype.setAdapter(subTypeAdapter); 
                subtype.setPrompt("Selecciona la cateogría"); 
               } 
              } catch (Exception e) { 
               e.printStackTrace(); 
              } 
             } 

             public void onNothingSelected(AdapterView<?> args) { 
              //Auto-generated method stub 
             } 
            }); 
            type.setPrompt("Selecciona la cateogría"); 

            //camera action 
            camera.setOnClickListener(new View.OnClickListener() { 
             public void onClick(View view) { 
              intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); 
              int timeMili = (int) (System.currentTimeMillis()); 
              filename = Environment.getExternalStorageDirectory() + "/" + timeMili + ".jpg"; 
              Uri output = Uri.fromFile(new File(filename)); 
              intent.putExtra(MediaStore.EXTRA_OUTPUT, output); 
              code = TAKE_PICTURE; 
              startActivityForResult(intent, code); 
             } 
            }); 

            //gallery action 
            gallery.setOnClickListener(new View.OnClickListener() { 
             public void onClick(View view) { 
              intent = new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.INTERNAL_CONTENT_URI); 
              code = SELECT_PICTURE; 
              startActivityForResult(intent, code); 
             } 
            }); 

            //button of the form 
            Button button = (Button) findViewById(R.id.button); 
            button.setOnClickListener(new View.OnClickListener() { 
             public void onClick(View view) { 
              if (!NetworkHelper.CheckNetworkStatus(view.getContext())) { 
               return; 
              } 
              bundle = new Bundle(); 
              bundle.putString("barcode", barcodeStr.toString()); 
              bundle.putString("name", name.getText().toString()); 
              bundle.putString("description", description.getText().toString()); 
              bundle.putString("type_id", ((TypeClass) subtype.getSelectedItem()).getId()); 

              if (_checkFormValues()) { 
               new SendDataJSON().execute(view); 
              } else { 
               Toast.makeText(view.getContext(), getString(R.string.error_form_incomplete), Toast.LENGTH_LONG).show(); 
              } 
             } 
            }); 

           } else { 
            errorMsg.setText(json.getString(ERROR_MSG)); 
            errorMsgContainer.setVisibility(LinearLayout.VISIBLE); 
           } 
          } 
         } catch (JSONException e) { 
          e.printStackTrace(); 
         } 
        } else { 

        } 
       } 
     }).setNegativeButton("No", 
      new DialogInterface.OnClickListener() { 
       public void onClick(DialogInterface arg0, int arg1) { 
        Intent myIntent = new Intent(ProductForm.this, CaptureActivity.class); 
        startActivity(myIntent); 
        finish(); 
       } 
     }).show(); 

    } else { 
     finish(); 
    } 

} 

class SendDataJSON extends AsyncTask<View, Void, View>{ 

    @Override 
    protected View doInBackground(View... views) { 

     String url = String.format(getString(R.string.api_product_form_url),getString(R.string.api_url)); 
     HttpPost httpPost = new HttpPost(url); 

     try { 
      // Add your data 
      MultipartEntity entity = new MultipartEntity(); 

      File photo = new File(filename); 
      if (photo.exists()) { 
       //create the compressed image to send     
       //create the file to send the image 
       File sd = Environment.getExternalStorageDirectory(); 
       File data = Environment.getDataDirectory(); 
       if (!sd.canWrite()) { sd = data; } 
       String destinationFolderPath = sd + "/" + getString(R.string.app_dir) + "/"; 
       String destinationImageName= "photo_" + bundle.getString("barcode") + ".jpg"; 

       //create the folder to store it 
       File destinationFolder = new File(destinationFolderPath); 
       if (!destinationFolder.exists()) { 
        destinationFolder.mkdirs(); 
       } 

       File destination = new File(destinationFolder, destinationImageName); 
       FileOutputStream out = new FileOutputStream(destination); 

       Bitmap bm = BitmapFactory.decodeFile(filename);     
       int width = bm.getWidth(); 
       int height = bm.getHeight(); 
       int max_value = 1024; 
       int max = Math.max(width,height); 
       if (max > max_value) { 
        width = width * max_value/max; 
        height = height * max_value/max; 
       } 

       //Make the new image with the new size values 
       try { 
        Bitmap bm2 = Bitmap.createScaledBitmap(bm, width, height, true); 
        //Compress the image 
        bm2.compress(CompressFormat.JPEG, 75, out);      
        out.flush(); 
        out.close();       
        destination = new File(destinationFolder, destinationImageName);       
        FileBody filePhoto = new FileBody(destination); 
        entity.addPart("image", filePhoto); 
       } catch (Exception e) { 
        Log.w(ProductForm.class.getSimpleName(), e); 
       } 

      } 
      SharedPreferences userSettings = getSharedPreferences("UserPreferences", Context.MODE_PRIVATE); 
      Charset chars = Charset.forName("UTF-8"); 
      entity.addPart("barcode", new StringBody(bundle.getString("barcode"),chars)); 
      entity.addPart("name", new StringBody(bundle.getString("name"),chars)); 
      entity.addPart("description", new StringBody(bundle.getString("description"),chars)); 
      entity.addPart("id_type", new StringBody(bundle.getString("type_id"))); 
      entity.addPart("uid",new StringBody(userSettings.getString("uid", ""),chars)); 
      httpPost.setEntity(entity); 
      HttpClient httpclient = new DefaultHttpClient(); 
      httpclient.execute(httpPost); 

     } catch (IOException e) { 
      // 
     } 

     return views[0]; 
    } 

    @Override 
    protected void onPreExecute() { 
     dialog.setMax(100); 
     dialog.setProgress(0); 
     dialog.show(); 
    } 

    @Override 
    protected void onPostExecute(View view) { 
     //redirect to the product page   
     setContentView(R.layout.product_barcode);   
     String url = String.format(getString(R.string.api_product_barcode_url), getString(R.string.api_url), bundle.getString("barcode")); 
     new LoadJSONBarcode().execute(url); 
    } 
} 

//Send data to server and receive respond 
private class LoadJSONBarcode extends AsyncTask<String, Void, JSONObject>{ 

    @Override 
    protected JSONObject doInBackground(String... urls) { 
     List<NameValuePair> params = new ArrayList<NameValuePair>(); 
     json = new JSONObject(); 
     json = jsonParser.getJSONFromUrl(urls[0], params); 
     return json; 
    } 

    @Override 
    protected void onPreExecute() { 
     dialog.setMax(100); 
     dialog.setProgress(0); 
     dialog.show(); 
    } 

    @Override 
    protected void onPostExecute(JSONObject json) { 

     if (json != null) { 
      try { 

       if (json.getString(KEY_SUCCESS) != null) { 
        String res = json.getString(KEY_SUCCESS); 
        if(Integer.parseInt(res) == 1){ 
         View view = findViewById(R.id.productBarcodeXML);      
         Intent myIntent = new Intent(view.getContext(), Product.class); 
         Bundle b = new Bundle(); 
         b.putString("id", json.getString(PRODUCT_ID)); 
         myIntent.putExtras(b); 
         view.getContext().startActivity(myIntent); 
        } else { 
         errorMsg.setText(json.getString(ERROR_MSG)); 
         errorMsgContainer.setVisibility(LinearLayout.VISIBLE); 
        } 
        dialog.dismiss(); 
       } 

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

} 

protected void onActivityResult(int requestCode, int resultCode, Intent data) { 
    if (requestCode == TAKE_PICTURE) { 
     if (data != null) { 
      if (data.hasExtra("data")) { 
       preview.setImageBitmap((Bitmap) data.getParcelableExtra("data")); 
       preview.setVisibility(ImageView.VISIBLE); 
      } 
     } else { 
      preview.setImageBitmap(BitmapFactory.decodeFile(filename)); 
      preview.setVisibility(ImageView.VISIBLE); 
      new MediaScannerConnectionClient() { 
       private MediaScannerConnection msc = null; { 
        msc = new MediaScannerConnection(getApplicationContext(), this); msc.connect(); 
       } 
       public void onMediaScannerConnected() { 
        msc.scanFile(filename, null); 
       } 
       public void onScanCompleted(String path, Uri uri) { 
        msc.disconnect(); 
       } 
      };    
     } 
    } else if (requestCode == SELECT_PICTURE){ 
     if (data != null){ 
      Uri selectedImage = data.getData(); 
      InputStream is; 
      String[] filePathColumn = {MediaStore.Images.Media.DATA}; 
      Cursor cursor = getContentResolver().query(selectedImage, filePathColumn, null, null, null); 
      cursor.moveToFirst(); 

      int columnIndex = cursor.getColumnIndex(filePathColumn[0]); 
      filename = cursor.getString(columnIndex); 
      cursor.close(); 

      try { 
       is = getContentResolver().openInputStream(selectedImage); 
       BufferedInputStream bis = new BufferedInputStream(is); 
       Bitmap bitmap = BitmapFactory.decodeStream(bis);    
       preview.setImageBitmap(bitmap);  
       preview.setVisibility(ImageView.VISIBLE); 
      } catch (FileNotFoundException e) { 

      } 
     } 
    } 
} 

private TypeClass[] convertJSONArray(JSONArray jsonArray){ 
    int len = jsonArray.length(); 
    TypeClass[] t = new TypeClass[len]; 
    if (jsonArray != null) { 
     for (int i=0;i<len;i++){ 
      try { 
       JSONObject o = jsonArray.getJSONObject(i); 
       t[i] = new TypeClass(); 
       t[i].setName(o.getString(TYPE_NAME)); 
       t[i].setId(o.getString(TYPE_ID)); 
      } catch (JSONException e) { 
       e.printStackTrace(); 
      } 
     } 
    } 
    return t; 
} 

protected boolean _checkFormValues() { 

    boolean result = true; 

    if (name.getText().length() == 0) { 
     name.requestFocus(); 
     result = false; 
    } 
    if (((TypeClass) subtype.getSelectedItem()).getId() == null){ 
     subtype.requestFocus(); 
     result = false; 
    } 
    return result; 
} 

} 

Lỗi Log

11-07 23:55:26.914: E/AndroidRuntime(15457): FATAL EXCEPTION: AsyncTask #3 
11-07 23:55:26.914: E/AndroidRuntime(15457): java.lang.RuntimeException: An error occured while executing doInBackground() 
11-07 23:55:26.914: E/AndroidRuntime(15457): at android.os.AsyncTask$3.done(AsyncTask.java:278) 
11-07 23:55:26.914: E/AndroidRuntime(15457): at java.util.concurrent.FutureTask$Sync.innerSetException(FutureTask.java:273) 
11-07 23:55:26.914: E/AndroidRuntime(15457): at java.util.concurrent.FutureTask.setException(FutureTask.java:124) 
11-07 23:55:26.914: E/AndroidRuntime(15457): at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:307) 
11-07 23:55:26.914: E/AndroidRuntime(15457): at java.util.concurrent.FutureTask.run(FutureTask.java:137) 
11-07 23:55:26.914: E/AndroidRuntime(15457): at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1076) 
11-07 23:55:26.914: E/AndroidRuntime(15457): at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:569) 
11-07 23:55:26.914: E/AndroidRuntime(15457): at java.lang.Thread.run(Thread.java:864) 
11-07 23:55:26.914: E/AndroidRuntime(15457): Caused by: java.lang.OutOfMemoryError: (Heap Size=35491KB, Allocated=27993KB) 
11-07 23:55:26.914: E/AndroidRuntime(15457): at android.graphics.BitmapFactory.nativeDecodeFile(Native Method) 
11-07 23:55:26.914: E/AndroidRuntime(15457): at android.graphics.BitmapFactory.decodeFile(BitmapFactory.java:373) 
11-07 23:55:26.914: E/AndroidRuntime(15457): at android.graphics.BitmapFactory.decodeFile(BitmapFactory.java:443) 
11-07 23:55:26.914: E/AndroidRuntime(15457): at prod.vegs.ProductForm$SendDataJSON.doInBackground(ProductForm.java:272) 
11-07 23:55:26.914: E/AndroidRuntime(15457): at prod.vegs.ProductForm$SendDataJSON.doInBackground(ProductForm.java:1) 
11-07 23:55:26.914: E/AndroidRuntime(15457): at android.os.AsyncTask$2.call(AsyncTask.java:264) 
11-07 23:55:26.914: E/AndroidRuntime(15457): at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305) 
11-07 23:55:26.914: E/AndroidRuntime(15457): ... 4 more 
+3

Vâng, hình ảnh có thể lớn đến cỡ nào? Nếu bạn tải một ảnh 5 Megapixel, và sau đó thay đổi kích thước nó thành 1k * 1k trong khi vẫn giữ ảnh cũ trong bộ nhớ, bạn có thể kết thúc với 24MB chỉ bằng một hình ảnh đó. – Jave

+0

http://stackoverflow.com/a/12819091/726863 –

+0

Có rất nhiều mã trên bài đăng của bạn, bạn có thể giảm mã đó xuống mức phù hợp nhất không HOẶC xem xét việc xóa mã không liên quan. – Siddharth

Trả lời

10

Bitmaps là người tiêu dùng bộ nhớ rất lớn. Có hai nạp vào bộ nhớ có thể là vấn đề lớn. Bạn nên cân nhắc sử dụng BitmapFactory.Options khi bạn giải mã bitmap mới. Ngoài ra, bạn không cần bm2. Thay vào đó, thay thế dòng đó với điều này:

bm = Bitmap.createScaledBitmap(bm, width, height, true); 

Cuối cùng, nếu bạn không có lựa chọn khác, bạn có thể tăng kích thước heap của ứng dụng của bạn bằng cách sử dụng thuộc tính ứng dụng android:largeHeap="true" trong bạn AndroidManifest.xml. Tùy chọn này không cần thiết - và chỉ nên được xem xét cho các ứng dụng cực kỳ đồ họa.

EDIT

Một liên kết mà bạn có thể tìm thấy hữu ích để tối ưu hóa việc sử dụng Bitmap: http://developer.android.com/training/tv/optimizing-layouts-tv.html#HandleLargeBitmaps

+0

Để mở rộng nhận xét của Phil, bạn sẽ muốn đặt tùy chọn 'inJustDecodeBounds' khi bạn tải' Bitmap' đầu tiên: http://developer.android.com/reference/android/graphics/BitmapFactory.Options.html#inJustDecodeBounds – twaddington

+0

Tôi đã thử và nó không hoạt động, nhưng nó chỉ là trong một số mô hình mà nó không hoạt động vì nó đi ok trong anh hùng Nexus HTC, vv Bây giờ tôi đang thử nghiệm nó với HTC One S và nó ăn tất cả bộ nhớ , nhưng cho đến nay câu trả lời của bạn là câu trả lời hữu ích hơn. Cảm ơn, tôi sẽ tiếp tục cố gắng cho đến khi tôi khắc phục và tôi sẽ cập nhật câu hỏi. – jonaypelluz

2

Một vài gợi ý chung:

  • Như @Phil đề nghị, Bitmap đối tượng có xu hướng ăn nhiều bộ nhớ trong Android. Bạn nên luôn sử dụng SoftReferences để giữ bitmap để hệ điều hành có thể giải phóng bộ nhớ khi cần.
  • Bạn cũng nên sử dụng phương pháp recycle() để vứt bỏ các bitmap chuyển đổi (ví dụ: biến số bm2) của bạn khi bạn kết thúc với chúng.
  • Như hoang tưởng như nó âm thanh, thiết lập bitmap để NULL khi bạn kết thúc với họ là một thực hành tốt để gợi ý cho các nhà sưu tập rác mà họ có thể được thu thập. Tuy nhiên, theo nguyên tắc chung, hãy gọi gc theo cách thủ công trong Android hoặc làm cho vấn đề trở nên tồi tệ hơn hoặc không có hiệu lực.
  • Và cuối cùng, profile your application sử dụng ddms!
0

Không thể nói chắc chắn vì tôi không phải là nhà phát triển Java, nhưng trong .NET BitMap calss là IDisposable và được khuyến nghị tái chế ngay khi không sử dụng.
Có thể bạn nên giải phóng bộ nhớ của mình sau khi tải BitMap?

4

Ảnh bitmap sử dụng hết bộ nhớ rất rõ ràng. Bạn cần phải quan tâm đến những điều sau để sử dụng bitmap hiệu quả

  • Hãy nhớ rằng png của bạn có thể vẽ được tự động thay đổi kích thước dựa trên kích thước màn hình của Android. Và điều đó chiếm rất nhiều bộ nhớ. Android không thay đổi kích thước hình ảnh nếu tìm thấy hình ảnh có kích thước/quy mô cần thiết trong thư mục có thể vẽ chính xác. Vì vậy, để bắt đầu với việc sao chép tất cả các tập tin ldpi để hdpi quá. Điều này sẽ giảm thiểu việc sử dụng bộ nhớ của bạn ít nhất 40%. Tôi biết làm thế nào điều này âm thanh, nhưng điều này là đúng, hồ sơ ứng dụng của bạn bằng cách sử dụng debuggable = true trong manifest, và heap sử dụng bằng cách sử dụng ddms. Thực hiện thay đổi và chạy chính xác cùng một kịch bản, bạn sẽ nhận thấy mức giảm 40%.
  • Khi bạn đọc bitmap của mình, hãy chia tỷ lệ bitmap xuống.Không sử dụng chỉ CreateBitmap, vì nó sẽ đọc toàn bộ tệp và sử dụng nhiều bộ nhớ hơn. Thay vào đó hãy sử dụng BitmapOptions và chia tỷ lệ. Để giảm tỷ lệ này xuống trước tiên, bạn cần phải đặt các tùy chọn của mình, sau đó sử dụng các tùy chọn này làm tham số cho cuộc gọi CreateBitmap của bạn. Here là một liên kết tốt đẹp. Tìm kiếm thêm trên stackoverflow, bạn sẽ tìm thấy một số câu trả lời thú vị hơn.
  • Nếu bạn có bất kỳ tệp nào trong bản vẽ có kích thước 1024x1212, hãy chia tỷ lệ chúng xuống. HOẶC Tạo các tệp mới rõ ràng nhưng có kích thước nhỏ hơn. Sử dụng những tập tin này cho mdpi, xóa ldpi. Sử dụng 1024X512 cho thư mục hdpi của bạn.
  • Khám phá khả năng sử dụng các tệp nhỏ hơn, sắp xếp theo kích thước và phát xung quanh nó một chút. Chế độ xem đồ họa trên nhật thực cho các tệp xml thực sự gọn gàng và tương đối không có lỗi. Sử dụng nó.
  • Đã chỉnh sửa: Đừng quên để trống bitmap của bạn để thu thập rác. Điều này là quan trọng nhất.
+0

Tôi đã sử dụng DDMS và bây giờ tôi biết nơi rò rỉ bộ nhớ là gì. Khi tôi chọn hình ảnh từ thư mục hoặc tôi chụp, đó là vào thời điểm đó mà tôi mất phần lớn bộ nhớ, với câu trả lời Phil và của bạn tôi đang cố gắng sửa chữa nó, cảm ơn! – jonaypelluz

+0

Đã thêm một sửa chữa khác mà bạn cần thực hiện. – Siddharth

0

Có Bộ nhớ cache cung cấp truy cập nhanh vào bitmap với chi phí chiếm dụng bộ nhớ ứng dụng có giá trị. Nếu LruCache không thể giải quyết vấn đề bạn có thể thử điều này: ImageManager, trong lớp ImageManager, nó có phương thức recycleBitmaps.

+0

Sử dụng LRUCache chỉ được khuyến nghị nếu anh ta sử dụng lại bitmap. Đây không phải là trường hợp đó. Chỉ cần sử dụng bitmap là gây ra một vụ tai nạn. – Siddharth

+0

@jonaypelluz Có thể, bạn có thể thử [ImageManager] (http://blog.pseudoblue.com/2010/08/15/android-bitmaps-and-memory-leaks/) trong lớp ImageManager, nó có phương thức recycleBitmaps . – Jamesprite

+0

Tôi đã thấy LruCache và tôi sẽ thực hiện nó trong một ứng dụng khác, nhưng tôi nghĩ rằng tôi sẽ có một đi với nó để kiểm tra nó giải quyết vấn đề trong này. cảm ơn! – jonaypelluz

Các vấn đề liên quan