android - সমস - মেমোরি থেকে কিছু ডিলেট হচ্ছে না




একটি বিটম্যাপ বস্তুর একটি চিত্র লোড করার সময় মেমরি সমস্যা অদ্ভুত আউট (20)

প্রতিটি সারির ছবি বোতামগুলির সাথে আমার একটি তালিকা দৃশ্য রয়েছে। যখন আপনি তালিকা সারিটি ক্লিক করেন, এটি একটি নতুন কার্যকলাপ আরম্ভ করে। ক্যামেরা লেআউটের সাথে একটি সমস্যার কারণে আমার নিজস্ব ট্যাব তৈরি করতে হয়েছে। ফলাফলের জন্য চালু করা ক্রিয়াকলাপটি একটি মানচিত্র। চিত্র প্রিভিউটি চালু করতে আমার বাটনটিতে ক্লিক করলে (এসডি কার্ড থেকে একটি চিত্র লোড করুন) অ্যাপ্লিকেশনটি listview হ্যান্ডলারের কার্যকলাপের ক্রিয়াকলাপ থেকে ফিরিয়ে আনতে আমার নতুন কার্যকলাপটি পুনরায় চালু করে যা কোনও চিত্র উইজেটের চেয়ে বেশি কিছু নয়।

তালিকা ভিউতে চিত্র পূর্বরূপটি কার্সার এবং তালিকা ListAdapter সাথে সম্পন্ন করা হচ্ছে। এটিটি বেশ সহজ করে তোলে, তবে আমি কীভাবে একটি পুনঃআকৃত চিত্রটি স্থাপন করতে পারি তা নিশ্চিত নই (আমি ছোট আকারের পিক্সেলটি src চিত্র বোতামটির জন্য src হিসাবে পিক্সেল না। তাই আমি কেবলমাত্র সেই ছবিটি পুনরায় আকার দিয়েছি যা ফোন ক্যামেরা থেকে এসেছে।

সমস্যা হল যে যখন আমি ফিরে যেতে এবং দ্বিতীয় ক্রিয়াকলাপটি পুনরায় চালু করার চেষ্টা করি তখন মেমরি ত্রুটিটি খুঁজে বের করি।

  • আমি কীভাবে অ্যাডাপ্টারের সারিটি সহজে সারি সারিতে তৈরি করতে পারি এমন একটি উপায় আছে, যেখানে আমি ফ্লাই ( বিট বিজ্ঞাপনে ) আকার পরিবর্তন করতে পারি?

এটি আরও ভাল হবে কারণ প্রতিটি সারির উইজেট / উপাদানের বৈশিষ্ট্যগুলিতে কিছু পরিবর্তন করতে হবে কারণ আমি ফোকাস সমস্যাটির কারণে স্পর্শ স্ক্রীন সহ একটি সারি নির্বাচন করতে অক্ষম। ( আমি রোলের বল ব্যবহার করতে পারেন। )

  • আমি জানি আমি ব্যান্ড আকার পরিবর্তন করতে এবং আমার ছবিটি সংরক্ষণ করতে পারি, কিন্তু আমি যা করতে চাই তা সত্যি নয়, তবে এর জন্য কিছু নমুনা কোড চমৎকার হবে।

যত তাড়াতাড়ি আমি তালিকা ভিউ ইমেজ নিষ্ক্রিয় হিসাবে এটি আবার জরিমানা কাজ।

FYI: আমি কিভাবে এটি ছিল:

String[] from = new String[] { DBHelper.KEY_BUSINESSNAME,DBHelper.KEY_ADDRESS,DBHelper.KEY_CITY,DBHelper.KEY_GPSLONG,DBHelper.KEY_GPSLAT,DBHelper.KEY_IMAGEFILENAME  + ""};
int[] to = new int[] {R.id.businessname,R.id.address,R.id.city,R.id.gpslong,R.id.gpslat,R.id.imagefilename };
notes = new SimpleCursorAdapter(this, R.layout.notes_row, c, from, to);
setListAdapter(notes);

যেখানে R.id.imagefilename একটি ButtonImage

এখানে আমার LogCat:

01-25 05:05:49.877: ERROR/dalvikvm-heap(3896): 6291456-byte external allocation too large for this process.
01-25 05:05:49.877: ERROR/(3896): VM wont let us allocate 6291456 bytes
01-25 05:05:49.877: ERROR/AndroidRuntime(3896): Uncaught handler: thread main exiting due to uncaught exception
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): java.lang.OutOfMemoryError: bitmap size exceeds VM budget
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.graphics.BitmapFactory.nativeDecodeStream(Native Method)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:304)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.graphics.BitmapFactory.decodeFile(BitmapFactory.java:149)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.graphics.BitmapFactory.decodeFile(BitmapFactory.java:174)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.graphics.drawable.Drawable.createFromPath(Drawable.java:729)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.widget.ImageView.resolveUri(ImageView.java:484)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.widget.ImageView.setImageURI(ImageView.java:281)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.widget.SimpleCursorAdapter.setViewImage(SimpleCursorAdapter.java:183)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.widget.SimpleCursorAdapter.bindView(SimpleCursorAdapter.java:129)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.widget.CursorAdapter.getView(CursorAdapter.java:150)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.widget.AbsListView.obtainView(AbsListView.java:1057)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.widget.ListView.makeAndAddView(ListView.java:1616)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.widget.ListView.fillSpecific(ListView.java:1177)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.widget.ListView.layoutChildren(ListView.java:1454)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.widget.AbsListView.onLayout(AbsListView.java:937)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.view.View.layout(View.java:5611)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1119)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.widget.LinearLayout.layoutHorizontal(LinearLayout.java:1108)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.widget.LinearLayout.onLayout(LinearLayout.java:922)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.view.View.layout(View.java:5611)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.widget.FrameLayout.onLayout(FrameLayout.java:294)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.view.View.layout(View.java:5611)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1119)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.widget.LinearLayout.layoutVertical(LinearLayout.java:999)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.widget.LinearLayout.onLayout(LinearLayout.java:920)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.view.View.layout(View.java:5611)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.widget.FrameLayout.onLayout(FrameLayout.java:294)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.view.View.layout(View.java:5611)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.view.ViewRoot.performTraversals(ViewRoot.java:771)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.view.ViewRoot.handleMessage(ViewRoot.java:1103)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.os.Handler.dispatchMessage(Handler.java:88)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.os.Looper.loop(Looper.java:123)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.app.ActivityThread.main(ActivityThread.java:3742)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at java.lang.reflect.Method.invokeNative(Native Method)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at java.lang.reflect.Method.invoke(Method.java:515)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:739)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:497)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at dalvik.system.NativeStart.main(Native Method)
01-25 05:10:01.127: ERROR/AndroidRuntime(3943): ERROR: thread attach failed 

একটি চিত্র প্রদর্শন করার সময় আমারও একটি নতুন ত্রুটি রয়েছে:

01-25 22:13:18.594: DEBUG/skia(4204): xxxxxxxxxxx jpeg error 20 Improper call to JPEG library in state %d
01-25 22:13:18.604: INFO/System.out(4204): resolveUri failed on bad bitmap uri: 
01-25 22:13:18.694: ERROR/dalvikvm-heap(4204): 6291456-byte external allocation too large for this process.
01-25 22:13:18.694: ERROR/(4204): VM won't let us allocate 6291456 bytes
01-25 22:13:18.694: DEBUG/skia(4204): xxxxxxxxxxxxxxxxxxxx allocPixelRef failed

OutOfMemory ত্রুটিটি ঠিক করতে, আপনাকে এমন কিছু করতে হবে:

BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 8;
Bitmap preview_bitmap = BitmapFactory.decodeStream(is, null, options);

এই inSampleSize বিকল্পটি মেমরি খরচ হ্রাস করে।

এখানে একটি সম্পূর্ণ পদ্ধতি। প্রথমত এটি কন্টেন্ট ডিকোডিং ছাড়া ইমেজ আকার পড়া। তারপর এটি সেরা inSampleSize মান খুঁজে পায়, এটি 2 এর শক্তি হওয়া উচিত এবং অবশেষে ছবিটি inSampleSize হয়।

// Decodes image and scales it to reduce memory consumption
private Bitmap decodeFile(File f) {
    try {
        // Decode image size
        BitmapFactory.Options o = new BitmapFactory.Options();
        o.inJustDecodeBounds = true;
        BitmapFactory.decodeStream(new FileInputStream(f), null, o);

        // The new size we want to scale to
        final int REQUIRED_SIZE=70;

        // Find the correct scale value. It should be the power of 2.
        int scale = 1;
        while(o.outWidth / scale / 2 >= REQUIRED_SIZE && 
              o.outHeight / scale / 2 >= REQUIRED_SIZE) {
            scale *= 2;
        }

        // Decode with inSampleSize
        BitmapFactory.Options o2 = new BitmapFactory.Options();
        o2.inSampleSize = scale;
        return BitmapFactory.decodeStream(new FileInputStream(f), null, o2);
    } catch (FileNotFoundException e) {}
    return null;
}

আমার এই একই সমস্যা ছিল এবং BitmapFactory.decodeStream বা decodeFile ফাংশন এড়াতে এটি সমাধান করেছিল এবং পরিবর্তে BitmapFactory.decodeFileDescriptor ব্যবহার BitmapFactory.decodeFileDescriptor

decodeFileDescriptor দেখে মনে হচ্ছে এটি বিভিন্ন স্থানীয় পদ্ধতিগুলিকে ডিকোড স্ট্রিম / ডিকোডফিলের চেয়ে কল করে।

যাইহোক, এই কাজটি কী ছিল (নোট করুন যে আমি উপরের কিছু হিসাবে কিছু অপশন যুক্ত করেছি, কিন্তু এটি কোন পার্থক্য তৈরি করেছে তা নয়। ডিটোড স্ট্রিম বা ডিকোডফাইলের পরিবর্তে BitmapFactory.decodeFileDescriptor এ কলটি কী সমালোচনামূলক?)

private void showImage(String path)   {
    Log.i("showImage","loading:"+path);
    BitmapFactory.Options bfOptions=new BitmapFactory.Options();
    bfOptions.inDither=false;                     //Disable Dithering mode
    bfOptions.inPurgeable=true;                   //Tell to gc that whether it needs free memory, the Bitmap can be cleared
    bfOptions.inInputShareable=true;              //Which kind of reference will be used to recover the Bitmap data after being clear, when it will be used in the future
    bfOptions.inTempStorage=new byte[32 * 1024]; 


    File file=new File(path);
    FileInputStream fs=null;
    try {
        fs = new FileInputStream(file);
    } catch (FileNotFoundException e) {
        //TODO do something intelligent
        e.printStackTrace();
    }

    try {
        if(fs!=null) bm=BitmapFactory.decodeFileDescriptor(fs.getFD(), null, bfOptions);
    } catch (IOException e) {
        //TODO do something intelligent
        e.printStackTrace();
    } finally{ 
        if(fs!=null) {
            try {
                fs.close();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
    //bm=BitmapFactory.decodeFile(path, bfOptions); This one causes error: java.lang.OutOfMemoryError: bitmap size exceeds VM budget

    im.setImageBitmap(bm);
    //bm.recycle();
    bm=null;



}

আমি মনে করি ডিস্কোস্ট্রিম / ডিকোডফিলে ব্যবহৃত স্থানীয় ফাংশনটির সাথে একটি সমস্যা আছে। আমি decodeFileDescriptor ব্যবহার করার সময় একটি ভিন্ন স্থানীয় পদ্ধতি বলা হয় নিশ্চিত করেছেন। এছাড়াও আমি যা পড়ি তা হল "যে চিত্রগুলি (বিটম্যাপ) একটি আদর্শ জাভা উপায়ে বরাদ্দ করা হয় না কিন্তু নেটিভ কলগুলির মাধ্যমে বরাদ্দ করা হয়; বরাদ্দগুলি ভার্চুয়াল হিপের বাইরে করা হয় তবে এটির বিরুদ্ধে গণনা করা হয়! "


আমি আইওএস অভিজ্ঞতা থেকে এসেছি এবং আমি লোড এবং একটি চিত্র দেখাচ্ছে হিসাবে তাই কিছু মৌলিক সঙ্গে একটি সমস্যা আবিষ্কার করতে হতাশ ছিল। সব পরে, এই সমস্যা হচ্ছে যে সবাই যুক্তিসঙ্গত আকারের ইমেজ প্রদর্শন করার চেষ্টা করছে। যাইহোক, এখানে আমার দুটি সমস্যা রয়েছে যা আমার সমস্যাটি স্থির করেছে (এবং আমার অ্যাপ্লিকেশনটিকে খুব প্রতিক্রিয়াশীল করেছে)।

1) প্রতিবার আপনি BitmapFactory.decodeXYZ() , তবে নিশ্চিত করুন যে এটি একটি BitmapFactory.Options inPurgeable সেট সেট (এবং inPurgeable BitmapFactory.Options সাথে সেট করা থাকে) সহ পাস করতে ভুলবেন না।

2) Bitmap.createBitmap(width, height, Config.ARGB_8888) ব্যবহার Bitmap.createBitmap(width, height, Config.ARGB_8888)Bitmap.createBitmap(width, height, Config.ARGB_8888) । আমি কখনও মানে না! আমি কিছু জিনিস পরে মেমরি ত্রুটি বাড়াতে না যে জিনিস ছিল না। recycle() কোন পরিমাণ recycle() , System.gc() , যাই হোক না কেন সাহায্য। এটা সবসময় ব্যতিক্রম উত্থাপিত। আসলে যে অন্য উপায়টি কাজ করে তা হল আপনার আঁকাগুলির মধ্যে একটি ডামি চিত্র (অথবা অন্য বিটম্যাপ যা আপনি উপরে ধাপ 1 ব্যবহার করে ডিকোড করেছেন), যেটি আপনি চান তা পুনরায় সংরক্ষণ করুন, তারপর বিটম্যাপ (যেমন ক্যানভাসে এটি প্রেরণ করা) আরো মজা জন্য)। সুতরাং, এর পরিবর্তে আপনার কী ব্যবহার করা উচিত: Bitmap.createScaledBitmap(srcBitmap, width, height, false) । যদি কোনও কারণে আপনাকে ব্রুট ফোর্সটি অবশ্যই তৈরি করতে হয় তবে অন্তত Config.ARGB_4444Config.ARGB_4444 পাস Config.ARGB_4444

এটি প্রায়শই দিনের জন্য আপনি সংরক্ষণ করার জন্য প্রায় নিশ্চিত করা হয়। ইমেজ, ইত্যাদি স্কেলিং সম্পর্কে যে সব কথা সত্যিই কাজ করে না (যদি না আপনি ভুল আকার বা হতাশ ইমেজ একটি সমাধান পেতে বিবেচনা না)।


আমি ফেডারের কোডে ছোট উন্নতি করেছি। এটা মূলত একই কাজ করে, কিন্তু ছাড়া (আমার মতামত) কুৎসিত যখন লুপ এবং এটি সবসময় দুটি একটি শক্তি ফলাফল। মূল সমাধান তৈরির জন্য ফেডোরকে কুদস, আমি তার সন্ধান না হওয়া পর্যন্ত আটকে ছিলাম, এবং তারপরে আমি এটি তৈরি করতে পেরেছিলাম :)

 private Bitmap decodeFile(File f){
    Bitmap b = null;

        //Decode image size
    BitmapFactory.Options o = new BitmapFactory.Options();
    o.inJustDecodeBounds = true;

    FileInputStream fis = new FileInputStream(f);
    BitmapFactory.decodeStream(fis, null, o);
    fis.close();

    int scale = 1;
    if (o.outHeight > IMAGE_MAX_SIZE || o.outWidth > IMAGE_MAX_SIZE) {
        scale = (int)Math.pow(2, (int) Math.ceil(Math.log(IMAGE_MAX_SIZE / 
           (double) Math.max(o.outHeight, o.outWidth)) / Math.log(0.5)));
    }

    //Decode with inSampleSize
    BitmapFactory.Options o2 = new BitmapFactory.Options();
    o2.inSampleSize = scale;
    fis = new FileInputStream(f);
    b = BitmapFactory.decodeStream(fis, null, o2);
    fis.close();

    return b;
}

এটি একটি পরিচিত বাগ , এটি বড় ফাইলগুলির কারণে নয়। অ্যান্ড্রয়েড ক্যাশে ড্রবেবেলস থেকে, এটি কয়েকটি ছবি ব্যবহার করার পরে মেমরির বাইরে চলে যাচ্ছে। কিন্তু আমি অ্যান্ড্রয়েড ডিফল্ট ক্যাশ সিস্টেম বাদ দিয়ে এটির জন্য একটি বিকল্প উপায় খুঁজে পেয়েছি।

সমাধান : ছবিগুলি "সম্পদ" ফোল্ডারে সরান এবং বিটম্যাপড্রোভাল পেতে নিম্নলিখিত ফাংশনটি ব্যবহার করুন:

public static Drawable getAssetImage(Context context, String filename) throws IOException {
    AssetManager assets = context.getResources().getAssets();
    InputStream buffer = new BufferedInputStream((assets.open("drawable/" + filename + ".png")));
    Bitmap bitmap = BitmapFactory.decodeStream(buffer);
    return new BitmapDrawable(context.getResources(), bitmap);
}

অ্যান্ড্রয়েড ট্রেনিং ক্লাস, " ডিসপ্লেটিং বিটম্যাপ কার্যকরীভাবে " ব্যতিক্রম, java.lang.OutOfMemoryError: bitmap size exceeds VM budget ব্যতিক্রমটি বোঝার ও মোকাবেলার জন্য কিছু দুর্দান্ত তথ্য সরবরাহ করে java.lang.OutOfMemoryError: bitmap size exceeds VM budget লোড করার সময় java.lang.OutOfMemoryError: bitmap size exceeds VM budget

বিটম্যাপ মাত্রা এবং টাইপ পড়ুন

BitmapFactory ক্লাস বিভিন্ন উত্স থেকে Bitmap তৈরি করার জন্য বিভিন্ন ডিকোডিং পদ্ধতি ( decodeByteArray() , decodeFile() , decodeResource() , ইত্যাদি) সরবরাহ করে। আপনার ইমেজ তথ্য উৎস উপর ভিত্তি করে সবচেয়ে উপযুক্ত ডিকোড পদ্ধতি নির্বাচন করুন। এই পদ্ধতিগুলি নির্মিত বিটম্যাপের জন্য মেমরি বরাদ্দ করার প্রচেষ্টা করে এবং এর ফলে সহজেই OutOfMemory ব্যতিক্রম হতে পারে। প্রতিটি ধরনের ডিকোড পদ্ধতিতে অতিরিক্ত স্বাক্ষর রয়েছে যা আপনাকে BitmapFactory.Options ক্লাসের মাধ্যমে ডিকোডিং বিকল্পগুলি নির্দিষ্ট করতে BitmapFactory.Options । ডিকোডিং মেমরি বরাদ্দ এড়ানো, বিটম্যাপ অবজেক্টের জন্য null প্রত্যাবর্তন কিন্তু সেটিংস outWidth , outHeight এবং outMimeType outHeight সেটিংস inJustDecodeBounds সম্পত্তিটি true সেট করা। এই কৌশলটি আপনাকে বিটম্যাপের নির্মাণ (এবং মেমরি বরাদ্দকরণ) এর পূর্বে চিত্রের মাত্রা এবং প্রকারটি পড়তে দেয়।

BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(getResources(), R.id.myimage, options);
int imageHeight = options.outHeight;
int imageWidth = options.outWidth;
String imageType = options.outMimeType;

java.lang.OutOfMemory ব্যতিক্রমগুলি এড়ানোর জন্য, এটি ডিকোড করার আগে বিটম্যাপের মাত্রাগুলি পরীক্ষা করুন, যদি না আপনি সম্পূর্ণরূপে উপলব্ধ আকারের চিত্রের ডেটা সরবরাহ করার জন্য উত্সকে সম্পূর্ণরূপে বিশ্বাস করেন যা সহজেই উপলব্ধ মেমরির মধ্যে ফিট করে।

মেমরি মধ্যে একটি স্কেল ডাউন সংস্করণ লোড করুন

এখন যে চিত্রের মাত্রাগুলি পরিচিত, সেগুলিকে পূর্ণ চিত্রটিকে মেমরিতে লোড করা উচিত কিনা তা নির্ধারণ করতে ব্যবহার করা যেতে পারে বা এর পরিবর্তে একটি নিম্নতর সংস্করণটি লোড করা উচিত। এখানে বিবেচনা করার কিছু কারণ রয়েছে:

  • মেমরি পূর্ণ ইমেজ লোড আনুমানিক মেমরি ব্যবহার।
  • আপনার চিত্রের অন্য মেমরির প্রয়োজনীয়তাগুলি প্রদত্ত মেমরির পরিমাণটি আপনি এই চিত্রটি লোড করতে প্রতিশ্রুতিবদ্ধ।
  • ইমেজ ভিউ বা UI উপাদানটির চিত্রের আকার যা লোড করা হবে।
  • বর্তমান ডিভাইসের স্ক্রিন সাইজ এবং ঘনত্ব।

উদাহরণস্বরূপ, এটি একটি 1024x768 পিক্সেল চিত্রটি মেমরিতে লোড করার যোগ্য নয় যদি এটি একটি চিত্র ভিউতে 128x96 পিক্সেল থাম্বনেইল প্রদর্শিত হবে।

inSampleSize ইমেজ inSampleSize করতে inSampleSize জন্য, মেমরিতে ছোট সংস্করণ লোড করা, আপনার BitmapFactory.Options বস্তুতে BitmapFactory.Options সেট করুন। উদাহরণস্বরূপ, রেজোলিউশন 2048x1536 একটি চিত্র যা 4 এর inSampleSize ডিকোড করা হয় প্রায় 512x384 এর বিটম্যাপ তৈরি করে। মেমরির মধ্যে লোড হচ্ছে পূর্ণ চিত্রের জন্য 1২MB এর চেয়ে 0.75MB ব্যবহার করে ( ARGB_8888 বিটম্যাপ কনফিগারেশন অনুমান করা হচ্ছে)। নমুনা আকারের মান গণনা করার জন্য এখানে একটি পদ্ধতি রয়েছে যা একটি লক্ষ্য প্রস্থ এবং উচ্চতার উপর ভিত্তি করে দুইটির শক্তি:

public static int calculateInSampleSize(
        BitmapFactory.Options options, int reqWidth, int reqHeight) {
    // Raw height and width of image
    final int height = options.outHeight;
    final int width = options.outWidth;
    int inSampleSize = 1;

    if (height > reqHeight || width > reqWidth) {

        final int halfHeight = height / 2;
        final int halfWidth = width / 2;

        // Calculate the largest inSampleSize value that is a power of 2 and keeps both
        // height and width larger than the requested height and width.
        while ((halfHeight / inSampleSize) > reqHeight
                && (halfWidth / inSampleSize) > reqWidth) {
            inSampleSize *= 2;
        }
    }

    return inSampleSize;
}

দ্রষ্টব্য : দুই মানের একটি শক্তি গণনা করা হয় কারণ inSampleSize ডকুমেন্টেশান অনুসারে দুইটি নিকটতম শক্তিতে বৃত্তাকার করে চূড়ান্ত মান ব্যবহার করে।

এই পদ্ধতিটি ব্যবহার করার জন্য, inJustDecodeBounds সাথে প্রথম inJustDecodeBounds true inJustDecodeBounds সেট করে, বিকল্পগুলির মাধ্যমে পাস করুন এবং তারপরে নতুন inSampleSize মান ব্যবহার করে আবার ডিকোড করুন এবং inJustDecodeBounds মিথ্যাতে সেট করুন:

public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId,
    int reqWidth, int reqHeight) {

    // First decode with inJustDecodeBounds=true to check dimensions
    final BitmapFactory.Options options = new BitmapFactory.Options();
    options.inJustDecodeBounds = true;
    BitmapFactory.decodeResource(res, resId, options);

    // Calculate inSampleSize
    options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);

    // Decode bitmap with inSampleSize set
    options.inJustDecodeBounds = false;
    return BitmapFactory.decodeResource(res, resId, options);
}

এই পদ্ধতিটি একটি চিত্র ImageView ইচ্ছাকৃতভাবে বড় আকারের বিটম্যাপটি লোড করা সহজ করে যা 100x100 পিক্সেল থাম্বনেইল প্রদর্শন করে, যেমন নিম্নোক্ত উদাহরণ কোডটিতে দেখানো হয়েছে:

mImageView.setImageBitmap(
    decodeSampledBitmapFromResource(getResources(), R.id.myimage, 100, 100));

প্রয়োজন অনুসারে যথাযথ BitmapFactory.decode* পদ্ধতিটি প্রতিস্থাপন করে আপনি অন্যান্য উত্সগুলির বিটম্যাপগুলি ডিকোড করার জন্য অনুরূপ প্রক্রিয়া অনুসরণ করতে পারেন।


SdCard থেকে বা নির্বাচিত বিটম্যাপ বস্তুর রূপান্তর করতে প্রতিটি চিত্রের জন্য এই কোডটি ব্যবহার করুন।

Resources res = getResources();
WindowManager window = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
Display display = window.getDefaultDisplay();
@SuppressWarnings("deprecation")
int width = display.getWidth();
@SuppressWarnings("deprecation")
int height = display.getHeight();
try {
    if (bitmap != null) {
        bitmap.recycle();
        bitmap = null;
        System.gc();
    }
    bitmap = Bitmap.createScaledBitmap(BitmapFactory
        .decodeFile(ImageData_Path.get(img_pos).getPath()),
        width, height, true);
} catch (OutOfMemoryError e) {
    if (bitmap != null) {
        bitmap.recycle();
        bitmap = null;
        System.gc();
    }
    BitmapFactory.Options options = new BitmapFactory.Options();
    options.inPreferredConfig = Config.RGB_565;
    options.inSampleSize = 1;
    options.inPurgeable = true;
    bitmapBitmap.createScaledBitmap(BitmapFactory.decodeFile(ImageData_Path.get(img_pos)
        .getPath().toString(), options), width, height,true);
}
return bitmap;

ImageData_Path.get (img_pos) .getPath () এর আপনার চিত্রের পথটি ব্যবহার করুন ।


আমার 2 সেন্ট: আমি আমার OOM ত্রুটিগুলি বিটম্যাপগুলির দ্বারা সমাধান করেছি:

একটি) 2 একটি ফ্যাক্টর দ্বারা আমার ছবি স্কেলিং

b) একটি তালিকা ভিউয়ের জন্য আমার কাস্টম অ্যাডাপ্টারের Picasso লাইব্রেরিটি ব্যবহার করে , getView এ এক-কল দিয়ে এটি পছন্দ করুন:Picasso.with(context).load(R.id.myImage).into(R.id.myImageView);


আমি নিম্নলিখিত পদ্ধতিতে একই সমস্যা সমাধান করেছেন।

Bitmap b = null;
Drawable d;
ImageView i = new ImageView(mContext);
try {
    b = Bitmap.createBitmap(320,424,Bitmap.Config.RGB_565);
    b.eraseColor(0xFFFFFFFF);
    Rect r = new Rect(0, 0,320 , 424);
    Canvas c = new Canvas(b);
    Paint p = new Paint();
    p.setColor(0xFFC0C0C0);
    c.drawRect(r, p);
    d = mContext.getResources().getDrawable(mImageIds[position]);
    d.setBounds(r);
    d.draw(c);

    /*   
        BitmapFactory.Options o2 = new BitmapFactory.Options();
        o2.inTempStorage = new byte[128*1024];
        b = BitmapFactory.decodeStream(mContext.getResources().openRawResource(mImageIds[position]), null, o2);
        o2.inSampleSize=16;
        o2.inPurgeable = true;
    */
} catch (Exception e) {

}
i.setImageBitmap(b);

এই আমার জন্য কাজ!

public Bitmap readAssetsBitmap(String filename) throws IOException {
    try {
        BitmapFactory.Options options = new BitmapFactory.Options(); 
        options.inPurgeable = true;
        Bitmap bitmap = BitmapFactory.decodeStream(assets.open(filename), null, options);
        if(bitmap == null) {
            throw new IOException("File cannot be opened: It's value is null");
        } else {
            return bitmap;
        }
    } catch (IOException e) {
        throw new IOException("File cannot be opened: " + e.getMessage());
    }
}

এখানে দুটি বিষয় আছে....


এটা আমার জন্য কাজ করে।

Bitmap myBitmap;

BitmapFactory.Options options = new BitmapFactory.Options(); 
options.InPurgeable = true;
options.OutHeight = 50;
options.OutWidth = 50;
options.InSampleSize = 4;

File imgFile = new File(filepath);
myBitmap = BitmapFactory.DecodeFile(imgFile.AbsolutePath, options);

এবং এই সি # monodroid হয়। আপনি সহজেই ছবির পথ পরিবর্তন করতে পারেন। এখানে কি গুরুত্বপূর্ণ সেট অপশন আছে।


আমার আরো অনেক কার্যকর সমাধান রয়েছে যা কোন ধরণের স্কেলিংয়ের প্রয়োজন নেই। শুধু একবার আপনার বিটম্যাপ ডিকোড করুন এবং তারপরে এটির নামের বিরুদ্ধে একটি মানচিত্রে ক্যাশ করুন। তারপর কেবলমাত্র নামটির বিরুদ্ধে বিটম্যাপটি পুনরুদ্ধার করুন এবং এটি চিত্র ভিউতে সেট করুন। সম্পন্ন করা প্রয়োজন যে আরও কিছু নেই।

এটি কাজ করবে কারণ ডিকোডেড বিটম্যাপের প্রকৃত বাইনারি তথ্য ডালিক ভিএম হিপের মধ্যে সংরক্ষণ করা হয় না। এটা বাইরের সংরক্ষণ করা হয়। তাই প্রতিবার যখন আপনি একটি বিটম্যাপ ডিকোড করেন, এটি ভিএম হিপের বাইরে মেমরি বরাদ্দ করে যা GC দ্বারা পুনরায় দাবি করা হয় না।

আপনাকে আরও ভালভাবে সাহায্য করার জন্য, কল্পনা করুন যে আপনি আপনার ছবিটি টেকসই ফোল্ডারে রেখেছেন। আপনি কেবল একটি getResources () পেতে পারেন। GetDrable (R.drawable।)। এটি প্রতিবার আপনার ছবিটি ডিকোড করবে না তবে আপনি যখনই এটি কল করবেন তখন পূর্বে ডিকোডেড উদাহরণটি পুনরায় ব্যবহার করুন। তাই সারাংশ এটা ক্যাশে হয়।

এখন যেহেতু আপনার ছবি কোথাও একটি ফাইল (অথবা এমনকি বাহ্যিক সার্ভার থেকেও আসছে) হতে পারে, তাই ডিকোডড বিটম্যাপ ইনস্ট্যান্সটি যে কোনও জায়গায় প্রয়োজন হয় সেটি পুনঃব্যবহার করা আপনার দায়িত্ব।

আশাকরি এটা সাহায্য করবে.


আমার এক আবেদনে আমি ছবিটি নিতে চাই Camera/Gallery। যদি ব্যবহারকারী ক্যামেরা থেকে ছবিটি ক্লিক করে (2 এমপি, 5 এমপি বা 8 এমপি হতে পারে), ছবির আকারটি kBs থেকে s তে পরিবর্তিত হয় MB। ইমেজ আকার কম কাজ (অথবা 1-2 এমবি পর্যন্ত) কোড কাজ সূক্ষ্ম কিন্তু যদি আমার আকার 4MB বা 5MB উপরে আকার আছে তারপর OOMফ্রেম মধ্যে আসে :(

তারপরে আমি এই সমস্যা সমাধানের জন্য কাজ করেছি এবং পরিশেষে আমি ফেডারোর (নীচে এমন চমৎকার সমাধান তৈরির জন্য ফেডারের সমস্ত ক্রেডিট) কোডে উন্নতি করেছি :)

private Bitmap decodeFile(String fPath) {
    // Decode image size
    BitmapFactory.Options opts = new BitmapFactory.Options();
    /*
     * If set to true, the decoder will return null (no bitmap), but the
     * out... fields will still be set, allowing the caller to query the
     * bitmap without having to allocate the memory for its pixels.
     */
    opts.inJustDecodeBounds = true;
    opts.inDither = false; // Disable Dithering mode
    opts.inPurgeable = true; // Tell to gc that whether it needs free
                                // memory, the Bitmap can be cleared
    opts.inInputShareable = true; // Which kind of reference will be used to
                                    // recover the Bitmap data after being
                                    // clear, when it will be used in the
                                    // future

    BitmapFactory.decodeFile(fPath, opts);

    // The new size we want to scale to
    final int REQUIRED_SIZE = 70;

    // Find the correct scale value. 
    int scale = 1;

    if (opts.outHeight > REQUIRED_SIZE || opts.outWidth > REQUIRED_SIZE) {

        // Calculate ratios of height and width to requested height and width
        final int heightRatio = Math.round((float) opts.outHeight
                / (float) REQUIRED_SIZE);
        final int widthRatio = Math.round((float) opts.outWidth
                / (float) REQUIRED_SIZE);

        // Choose the smallest ratio as inSampleSize value, this will guarantee
        // a final image with both dimensions larger than or equal to the
        // requested height and width.
        scale = heightRatio < widthRatio ? heightRatio : widthRatio;//
    }

    // Decode bitmap with inSampleSize set
    opts.inJustDecodeBounds = false;

    opts.inSampleSize = scale;

    Bitmap bm = BitmapFactory.decodeFile(fPath, opts).copy(
            Bitmap.Config.RGB_565, false);

    return bm;

}

আমি এই একই সমস্যা সম্মুখীন বন্ধুদের সাহায্য করবে আশা করি!

আরো জন্য this পড়ুনthis


আমি সারা দিন এই সমাধানগুলি পরীক্ষা করে কাটিয়েছি এবং আমার জন্য কাজ করা একমাত্র বিষয় হচ্ছে ছবিটি পাওয়ার জন্য উপরের পন্থা এবং নিজে নিজে জি.সি.কে ফোন করা, যা আমি জানি না তা প্রয়োজনীয় বলে মনে করা হয় না, তবে এটিই একমাত্র কাজ। যখন আমি ভারী লোড পরীক্ষার অধীনে আমার অ্যাপ্লিকেশন কার্যক্রম মধ্যে সুইচিং করা। আমার অ্যাপ্লিকেশানে তালিকার দৃশ্যের থাম্বনেইল চিত্রগুলির একটি তালিকা রয়েছে (কার্যকলাপ A বলুন) এবং যখন আপনি সেগুলির একটিতে ক্লিক করেন তখন এটি আপনাকে অন্য ক্রিয়াকলাপে নিয়ে যায় (ক্রিয়াকলাপ B বলুন) যা সেই আইটেমের জন্য একটি প্রধান চিত্র দেখায়। যখন আমি দুটি ক্রিয়াকলাপের মধ্যে পিছনে অগ্রসর হব, তখন অবশেষে আমি OOM ত্রুটিটি পেতে পারতাম এবং অ্যাপ্লিকেশন বন্ধ হয়ে যাবে।

যখন আমি তালিকা দেখুন নিচে অর্ধেক পথ পেতে হবে এটা ক্র্যাশ হবে।

এখন আমি যখন ক্রিয়াকলাপ B তে নিম্নলিখিতটি বাস্তবায়ন করি তখন আমি কোনও সমস্যা ছাড়াই পুরো তালিকাউইউউউউউর মাধ্যমে যেতে এবং চলতে এবং চলতে এবং চলতে এবং ... এর দ্রুততম দ্রুত যেতে পারি।

@Override
public void onDestroy()
{   
    Cleanup();
    super.onDestroy();
}

private void Cleanup()
{    
    bitmap.recycle();
    System.gc();
    Runtime.getRuntime().gc();  
}

উপরের কোনও উত্তর আমার জন্য কাজ করে নি, তবে আমি সমস্যাটির সমাধান করে এমন একটি ভয়ানক কুৎসিত কাজকর্ম নিয়ে এসেছি। আমি আমার প্রোজেক্টে একটি খুব ছোট, 1x1 পিক্সেল চিত্র যুক্ত করেছি, এবং আবর্জনা সংগ্রহে কল করার আগে আমার চিত্র ভিউতে লোড করেছি। আমি মনে করি ইমেজ ভিউ বিটম্যাপটি প্রকাশ করছে না, তাই জিসি কখনও এটি বাছাই করেনি। এটা কুৎসিত, কিন্তু এটা এখন জন্য কাজ বলে মনে হচ্ছে।

if (bitmap != null)
{
  bitmap.recycle();
  bitmap = null;
}
if (imageView != null)
{
  imageView.setImageResource(R.drawable.tiny); // This is my 1x1 png.
}
System.gc();

imageView.setImageBitmap(...); // Do whatever you need to do to load the image you want.

এই ব্যবহার করুন এই bitmap.recycle();কোনো ইমেজ মানের সমস্যা ছাড়া সাহায্য করে।


এই সমস্যা শুধুমাত্র অ্যান্ড্রয়েড emulators মধ্যে ঘটবে। আমি একটি এমুলেটর এই সমস্যা সম্মুখীন কিন্তু যখন আমি একটি ডিভাইস চেক আউট তারপর এটা সূক্ষ্ম কাজ।

সুতরাং একটি ডিভাইস চেক করুন। এটা ডিভাইস চালানো হতে পারে।


এখানে সব সমাধান একটি IMAGE_MAX_SIZE সেটিং প্রয়োজন। এটি আরও শক্তিশালী হার্ডওয়্যারগুলির সাথে ডিভাইসগুলিকে সীমাবদ্ধ করে এবং যদি চিত্রের আকার খুব কম হয় তবে এটি HD স্ক্রীনে কুৎসিত দেখাচ্ছে।

আমি আরো শক্তিশালী ডিভাইস ব্যবহার করা হয় যখন ভাল ইমেজ মানের সঙ্গে, আমার স্যামসাং আকাশগঙ্গা S3 এবং কম শক্তিশালী সহ অন্যান্য অনেক ডিভাইসের সাথে কাজ করে একটি সমাধান সঙ্গে এসেছিলেন।

এটির সারাংশটি একটি নির্দিষ্ট ডিভাইসে অ্যাপ্লিকেশনের জন্য বরাদ্দ সর্বাধিক মেমরি গণনা করা হয়, তারপরে এই মেমরি ছাড়িয়ে স্কেলটিকে সর্বনিম্ন সম্ভব হতে সেট করুন। এখানে কোডটি রয়েছে:

public static Bitmap decodeFile(File f)
{
    Bitmap b = null;
    try
    {
        // Decode image size
        BitmapFactory.Options o = new BitmapFactory.Options();
        o.inJustDecodeBounds = true;

        FileInputStream fis = new FileInputStream(f);
        try
        {
            BitmapFactory.decodeStream(fis, null, o);
        }
        finally
        {
            fis.close();
        }

        // In Samsung Galaxy S3, typically max memory is 64mb
        // Camera max resolution is 3264 x 2448, times 4 to get Bitmap memory of 30.5mb for one bitmap
        // If we use scale of 2, resolution will be halved, 1632 x 1224 and x 4 to get Bitmap memory of 7.62mb
        // We try use 25% memory which equals to 16mb maximum for one bitmap
        long maxMemory = Runtime.getRuntime().maxMemory();
        int maxMemoryForImage = (int) (maxMemory / 100 * 25);

        // Refer to
        // http://developer.android.com/training/displaying-bitmaps/cache-bitmap.html
        // A full screen GridView filled with images on a device with
        // 800x480 resolution would use around 1.5MB (800*480*4 bytes)
        // When bitmap option's inSampleSize doubled, pixel height and
        // weight both reduce in half
        int scale = 1;
        while ((o.outWidth / scale) * (o.outHeight / scale) * 4 > maxMemoryForImage)
        scale *= 2;

        // Decode with inSampleSize
        BitmapFactory.Options o2 = new BitmapFactory.Options();
        o2.inSampleSize = scale;
        fis = new FileInputStream(f);
        try
        {
            b = BitmapFactory.decodeStream(fis, null, o2);
        }
        finally
        {
            fis.close();
        }
    }
    catch (IOException e)
    {
    }
    return b;
}

আমি এই বিটম্যাপ দ্বারা সর্বাধিক মেমরি সর্বাধিক বরাদ্দকৃত মেমরির 25% হতে সেট করি, আপনাকে আপনার প্রয়োজনীয়তাগুলিতে এটি সামঞ্জস্য করতে হবে এবং এটি নিশ্চিত করুন যে এই বিটম্যাপটি পরিষ্কার করা হয়েছে এবং আপনি এটি ব্যবহার শেষ করার পরে মেমরিতে থাকবেন না। সাধারণত আমি ইমেজ ঘূর্ণন (উৎস এবং গন্তব্য বিটম্যাপ) সঞ্চালনের জন্য এই কোডটি ব্যবহার করি যাতে আমার অ্যাপ্লিকেশানটি একই সময়ে মেমরিতে 2 বিটম্যাপ লোড করতে হয় এবং 25% চিত্রের ঘূর্ণন সম্পাদন করার সময় মেমরির বাইরে চালানো ছাড়া আমাকে একটি ভাল বাফার দেয়।

আশা করছি এটা ওখানে কাওকে সাহায্য করবে..


মনে হচ্ছে এটি একটি খুব দীর্ঘ চলমান সমস্যা, বিভিন্ন ব্যাখ্যা নিয়ে অনেক। আমি এখানে দুটি সবচেয়ে সাধারণ উপস্থাপিত উত্তরগুলির পরামর্শ নিয়েছি, কিন্তু এগুলির মধ্যে কেউও ভিএম এর আমার সমস্যাগুলির সমাধান করেনি দাবি করে যে এটি বাইটগুলি প্রক্রিয়াটির ডিকোডিং অংশ সম্পাদন করতে পারে না । কিছু খনন করার পর আমি শিখেছি যে এখানে আসল সমস্যা ডিকোডিং প্রক্রিয়াটি ন্যাটাইভ হিপ থেকে দূরে চলে যাচ্ছে ।

এখানে দেখুন: BitmapFactory OOM আমাকে বাদাম ড্রাইভিং

এটি আমাকে আরেকটি আলোচনা থ্রেডের দিকে পরিচালিত করে যেখানে আমি এই সমস্যাটির আরো কয়েকটি সমাধান খুঁজে পেয়েছি। System.gc();আপনার ইমেজ প্রদর্শিত হয় একবার এক কল করতে হয়। তবে প্রকৃতপক্ষে আপনার অ্যাপ্লিকেশনটি স্থানীয় মেপে কমাতে একটি প্রচেষ্টায় আরো মেমরি ব্যবহার করে। 2.0 (ডোনাট) মুক্তির মতো ভাল সমাধান হল বিটম্যাপ ফ্যাক্টরি বিকল্পটি "ইনপুটযোগ্য" ব্যবহার করা। তাই আমি কেবল o2.inPurgeable=true;পরে শুধু যোগ করাo2.inSampleSize=scale;

এখানে যে বিষয় আরো: মেমরি সীমা শুধুমাত্র 6 ম মাপ?

এখন, এই সব বলে, আমি জাভা এবং অ্যান্ড্রয়েড সঙ্গে একটি সম্পূর্ণ dunce হয়। তাই যদি আপনি মনে করেন যে এই সমস্যাটির সমাধান করার এটি একটি দুর্দান্ত উপায়, আপনি সম্ভবত সঠিক। ;-) কিন্তু এটি আমার জন্য বিস্ময়কর কাজ করেছে, এবং আমি এখন হিপ ক্যাশে ভিএম চালানো অসম্ভব বলে মনে করেছি। আমি খুঁজে পেতে একমাত্র ত্রুটি যে আপনি আপনার ক্যাশে টানা ইমেজ ট্র্যাশিং হয়। যার অর্থ আপনি যদি সেই চিত্রটির দিকে ফিরে যান তবে আপনি এটি প্রতিবার পুনঃপ্রতিষ্ঠা করছেন। আমার আবেদন কিভাবে কাজ করে সে ক্ষেত্রে, এটি সত্যিই একটি সমস্যা নয়। আপনার মাইলেজ পরিবর্তিত হতে পারে.







android-bitmap