ভিজ্যুয়ালি সমৃদ্ধ Android অ্যাপে আউট-অফ-মেমরি (OOM) সংক্রান্ত ঝুঁকি কমানোর জন্য বিটম্যাপ মেমরি ম্যানেজ করা অত্যন্ত গুরুত্বপূর্ণ। ডেভেলপাররা ছবির সাইজ কমানোর ব্যাপারে জানলেও, অ্যাপের দীর্ঘমেয়াদী স্থায়িত্ব অর্জন করতে হলে আরও দুটি মূল স্তম্ভে দক্ষতা অর্জন করতে হবে: পুনর্ব্যবহার ও রিসাইকেল। এই সেশনে আধুনিক টুল, Glide ও Coil-এর মতো ওপেন-সোর্স লাইব্রেরি এবং সিস্টেম-লেভেল API ব্যবহার করে মেমরি পারফর্ম্যান্স অপ্টিমাইজ করার জন্য একটি প্র্যাকটিক্যাল প্লেবুক প্রদান করা হয়।
এই সেশনে, আপনি Android Vitals ব্যবহার করে বাস্তব-জগতের মেমরি রিগ্রেশন কীভাবে নির্ণয় করবেন, Glide এবং Coil-এর সাথে উন্নত ক্যাশিং (পুনরায় ব্যবহার) প্যাটার্ন প্রয়োগ করবেন এবং onTrimMemory কলব্যাক ব্যবহার করে প্রোঅ্যাক্টিভভাবে মেমরি (রিসাইকেল) রিলিজ করবেন তা শিখবেন।
BitmapRegionDecoder-এর মতো API ব্যবহার করুন।onTrimMemory ম্যানেজ করার মাধ্যমে আপনার অ্যাপ ব্যাকগ্রাউন্ডে চলে গেলে ইমেজ মেমরি রিলিজ করুন। ব্যাকগ্রাউন্ড মেমরি বৃদ্ধি আটকাতে onStop-এ ব্যাকগ্রাউন্ড পোলিং ও অ্যানিমেশন বন্ধ করুন।ট্রান্সস্ক্রিপ্ট করা
ফুং লাম
হ্যাঁ, লাঞ্চের আগে আমাদের কাছে প্রায় ১ ঘণ্টা সময় আছে, তাই আমার সাথে থাকুন।
আমি ফুং ল্যাম, লন্ডনে Android-এর ডেভেলপার রিলেশনস ইঞ্জিনিয়ার হিসেবে কাজ করি।
হ্যাঁ, ধন্যবাদ।
শুরু করার আগে, আমি কি একটি প্রশ্ন করতে পারি?
আপনাদের মধ্যে কতজন এই বছর নতুন ফোন কিনেছেন?
অসাধারণ।
অসাধারণ।
সত্যি করে বলো, তুমি Pixel না কিনলে আমি তোমাকে দোষ দেব না।
নতুন ফোনের দাম তো বেশি, তাই না?
হ্যাঁ, সেই কারণেই আপনাদের মধ্যে কেউ কেউ নতুন ফোন কেনেননি।
এটি আরও দামি কেন?
আপনি কি জানেন?
না।
RAM.
RAM, হ্যাঁ, হ্যাঁ।
হ্যাঁ, RAM-এর সমস্যা Android, আমাদের এবং ডেভেলপারদের জন্য সত্যিই একটি চ্যালেঞ্জ।
তাই আজ আমি এখানে এসেছি, মেমরি ও RAM-এর চ্যালেঞ্জ কীভাবে আমরা অতিক্রম করতে পারি তা বলতে।
Google I/O এবং Google I/O Connect-এ আগে আমরা মেমরি সম্পর্কে কিছু সেশন করেছিলাম, যেখানে অপারেটিং সিস্টেম কীভাবে মেমরি অ্যালোকেট করে, আপনি কীভাবে আপনার অ্যাপ্লিকেশনের প্রোফাইল তৈরি করতে পারেন, R8 ব্যবহার করে কীভাবে আপনার কোড অপ্টিমাইজ করতে পারেন এবং অবশ্যই, আমি সেই সময় বিটম্যাপ সম্পর্কে কিছুটা কভার করেছিলাম।
স্ক্রিনশটে আপনি আমার ফটো দেখতে পাবেন।
মেমরি অপ্টিমাইজেশন হল একটি বড় ডোমেন, যা Android রানটাইম, গার্বেজ কালেকশন, পারফর্ম্যান্স টুলিং, অবজেক্ট মেমরি অ্যালোকেশন, কম্পাইলার ইত্যাদির মতো বিভিন্ন ক্ষেত্র জুড়ে কাজ করে। এবং এই সেশনে, এই ৩০ মিনিটে, আমি আপনাকে বিটম্যাপ মেমরি কীভাবে অপ্টিমাইজ করতে হয় সে সম্পর্কে কিছু তথ্য দেব।
আপনি জিজ্ঞাসা করতে পারেন, কেন, কেন বিটম্যাপ?
বিটম্যাপ মেমরির উপর কেন আমাদের ফোকাস করা উচিত?
কারণ একটি ছবি হাজার শব্দের চেয়েও বেশি কার্যকর।
এটি সত্যি, আমি আপনাকে এর কারণ ব্যাখ্যা করব।
ফোনের স্ক্রিনে, যেমন Pixel 7, Pixel 9 বা Pixel 11 Pro ভার্সনে, স্ক্রিন রেজোলিউশন প্রায় ২৫০০, ১২০০, ১৪০০ হয়।
তাই, প্রতিটি পিক্সেলের জন্য আমরা ৩২ বিটের কালার ডেপথ ব্যবহার করি।
তাই, ফুল স্ক্রিনের ছবির জন্য, ওহ, আমার কাছে পর্যাপ্ত আঙুল নেই, তবে, যেমন, এটি প্রায় ১৫ এমবি মেমরি, ৫০ এমবি নেবে।
সুতরাং, কিন্তু, যেমন, OS সিস্টেমে একটি শব্দ হল ৬৪-বিট, যার অর্থ হল ৮ বাইট।
এক হাজার শব্দের সাইজ মাত্র ৮ এমবি।
হ্যাঁ, 8K।
তাই, একটি ছবি হাজার শব্দের চেয়েও বেশি কার্যকর।
হ্যাঁ, এটি গুরুত্বপূর্ণ।
একটি ছবির সাইজ ইতিমধ্যেই ১৫ এমবি।
আপনার অ্যাপে ১০, ১০০টি ছবি থাকলে কী হবে?
এটি একটি বড় সংখ্যা।
তাই, সাধারণত Bitmap আপনার অ্যাপ্লিকেশনে সবচেয়ে বেশি মেমরি ব্যবহার করে।
আমি যেমন বলেছি, মেমরিতে ছবি ডিকোড করার সময়, এটি ডাইমেনশন ও কালার ডেপথ হিসেবে বড় হয়।
This is not hey, how the file size it's is in, JPEG or is it in PNG format.
না, এটি ডিকোড করা হবে এবং মেমরি ব্যবহার করবে।
তাই, সম্পূর্ণ রেজোলিউশনের মাত্র কয়েকটি ছবিই আপনার ডিভাইসের মেমরিতে সহজেই কয়েকশো মেগাবাইট জায়গা নিয়ে নেবে।
দ্বিতীয়ত, মেমরি খুব কম থাকলে, মেমরি ব্যবহার ম্যানেজ করার জন্য অপারেটিং সিস্টেমকে আরও বেশি বিদ্যুৎ খরচ করতে হবে।
এর ফলে UI-তে সমস্যা দেখা দিতে পারে।
অথবা, OS মেমরি খালি করার জন্য আপনার অ্যাপ বন্ধ করে দিতে পারে।
অথবা আপনার অ্যাপে Out-Of-Memory সমস্যা, Out-Of-Memory ব্যতিক্রম দেখা যাবে।
তবে, সুখবর হল, এই ওয়াচফেসটি সাধারণত খুব কম পরিশ্রমেই দারুণ ফলাফল দেয়।
বেশিরভাগ মেমরি স্পাইক সাধারণ ভুল থেকে আসে, যা এড়ানো যেতে পারে এবং আমরা ছবির কোয়ালিটির সাথে কোনও আপস না করেই এটি ঠিক করতে পারি।
এখন আপনি জানেন যে, বিটম্যাপ মেমরি আপনার অ্যাপ্লিকেশনের জন্য গুরুত্বপূর্ণ, শুধু এটিকে মসৃণ করার জন্য নয়, স্থিতিশীলতা এবং ব্যবহারকারী ধরে রাখার জন্যও।
তাই, আজ আমরা পাঁচটি সহজ ধাপের মাধ্যমে আপনার অ্যাপ নির্বিঘ্নে চালানোর উপায় জানব।
প্রথমে, আমরা Google Play-এর টেকনিক্যাল কোয়ালিটি, নতুন টেকনিক্যাল কোয়ালিটির প্রয়োজনীয়তা দেখব, যার মধ্যে আসন্ন মেমরি সীমা এবং আপনি কোথায় সহজেই সীমা চেক করতে পারবেন তা অন্তর্ভুক্ত রয়েছে।
দ্বিতীয়ত, আমি প্রায় ৫০০টি Android অ্যাপ্লিকেশন নিয়ে আমার কেস স্টাডি শেয়ার করব, সেগুলি কীভাবে মেমরি ব্যবহার করে, তারা কি সঠিক উপায়ে তা করছে, নাকি এমন কিছু আছে যা থেকে আমরা শিখতে পারি?
এরপরে, আমি আপনাকে বিটম্যাপ মেমরির ব্যবহার কীভাবে অপ্টিমাইজ করতে হয় সেই নীতি দেখাব।
এবং সবশেষে, আমরা কিছু টুল শেয়ার করব যা আপনার নিজের অ্যাপ চেক করতে সাহায্য করতে পারে।
ফুং লাম
প্রথমত, Google Play-এর নতুন কোয়ালিটি সংক্রান্ত প্রয়োজনীয়তা।
আপনি কত ঘনঘন Google Play Console-এ যান?
প্রতি মাসে?
প্রতি সপ্তাহে?
কখনও নয়?
ওরা হাসছে মানে হ্যাঁ, তাই তো?
না?
না।
আপনি কি Android Vitals অংশটি দেখেছেন?
হ্যাঁ, একদম।
হ্যাঁ, তাই আপনি অবশ্যই, আমি এটি তৈরি করার আগে আপনি কিছু জানেন।
তাই, Google Play-তে পারফর্ম্যান্স থ্রেশহোল্ডের উপর নতুন কোয়ালিটি সংক্রান্ত প্রয়োজনীয়তা আছে।
আমরা Android এবং Play চাই যে ব্যবহারকারী যেন ভাল কোয়ালিটির অ্যাপ ব্যবহার করেন।
তাই, এই থ্রেশহোল্ডও এমন কিছু, যা আমরা ব্যবহারকারীকে সেরা অভিজ্ঞতা প্রদান করার জন্য চেষ্টা করি।
সহজ কথায়, "আপনার অ্যাপ ব্যাকগ্রাউন্ডে বা দৃশ্যমান ফোরগ্রাউন্ড সারফেসে চলার সময়, মেমরির ব্যবহারের ৯০ পার্সেন্টাইল এই থ্রেশহোল্ডের বেশি হওয়া উচিত নয়।
অথবা, Play Store-এ আপনার অ্যাপের দৃশ্যমানতা কমে যেতে পারে বা অন্য কিছু হতে পারে।"
এবং ফেব্রুয়ারি ২০২৭ থেকে অ্যাপ ও গেমে এনফোর্সমেন্ট শুরু হবে।
এই থ্রেশহোল্ড পেরিয়ে গেলে আপনার অ্যাপের স্বাস্থ্য মূল্যায়ন সরাসরি প্রভাবিত হবে।
তাই, Google Play Console-এ গিয়ে চেক করতে ভুলবেন না, "আজকে আমার ৯০ পার্সেন্টাইল কত?"
এবং সময়সীমার আগে উন্নতি করুন।
এটি হল অ্যানিমেশন।
"আপনি Google Play কনসোলে গেলে, Android Vitals দেখতে পাবেন।
এটি মেমরির একটি অংশ।
এবং আপনি ৯০ পার্সেন্টাইল দেখতে পাবেন।
এবং আপনি যদি এটিতে ক্লিক করেন, হ্যাঁ, আপনি সময়ের সাথে সাথে মেমরি খরচের গড় দেখতে পাবেন।
এছাড়াও, RAM, ফর্ম ফ্যাক্টর, স্ক্রিন ডেনসিটি, OS ভার্সন অনুযায়ী বিভিন্ন টিয়ার আছে, যা আপনাকে নির্দিষ্ট এন্ট্রি-লেভেল ডিভাইস বা নির্দিষ্ট অ্যাপ রিলিজে মেমরি সংক্রান্ত সমস্যা আলাদা করতে সাহায্য করে।
এখন, আমি জানি, আপনি বলতে পারেন, "আমার অ্যাপ থ্রেশহোল্ডের বেশি হয়ে গেছে, তা জানানোর জন্য ধন্যবাদ।
কিন্তু সত্যি, আমি জানি না কী সমস্যা হয়েছে।
আপনি কি সাহায্য করবেন?"
হ্যাঁ, সেই জন্যই আমি আপনাকে সাহায্য করতে এখানে আছি।
আমি আপনার জন্য এটি সহজ করার চেষ্টা করব, যেমন, আপনি যদি টিভি দেখেন এবং তারপরে আপনার টিভিতে কোনও ভিডিও বা অডিও না থাকে, তাহলে আপনি কী করবেন?
আপনি টিভির ম্যানুয়াল বের করে একদম শেষের কয়েকটি পৃষ্ঠা দেখেন, যেখানে সাধারণত সমস্যার সমাধান করার নির্দেশিকা থাকে, যেমন, "আপনার টিভিতে সাউন্ড না থাকলে, এই বোতাম বা ওই বোতাম টিপে দেখুন।"
হ্যাঁ, একইভাবে, আজ আমি কিছু সাধারণ সমস্যা শনাক্ত করেছি।
এবং আশা করি, এটি আপনার সমস্যার সমাধান সংক্রান্ত নির্দেশিকা।
সাধারণত, আমরা যখন টিভির ম্যানুয়াল পড়ি, তখন আমাদের প্রথম পৃষ্ঠা থেকে শুরু করা উচিত, যা সাধারণত ডায়াগন-- ডায়াগনস্টিক টুলকিট, যা আপনাকে টিভি কীভাবে কাজ করে তা বুঝতে সাহায্য করে।
কিন্তু এখন আমি জানি যে সেগুলি কম আকর্ষণীয়, তাই আজ, প্রথমে আমাকে সমস্যার সমাধানকরণ থেকে শুরু করতে দিন এবং আমরা পরে ফিরে আসব।
আর সত্যি বলতে, আমি এভাবেই টিভির ম্যানুয়াল পড়ি।
Android ইকোসিস্টেমে সবচেয়ে বেশি হওয়া বিটম্যাপ অ্যালোকেশন বিটম্যাপ মেমরি সংক্রান্ত সমস্যা খুঁজে বের করতে, আমি Android-এ প্রায় ৫০০টি জনপ্রিয় অ্যাপ নিয়ে রিসার্চ করেছি।
আমি সত্যিই অ্যাপটি চালাই, অ্যাপটি শুরু করি, লগ ইন করি, বিভিন্ন পৃষ্ঠায় যাই, গভীরে যাই এবং ফিরে আসি।
আমি বিভিন্ন RAM ও ডিভাইসেও অ্যাপটি পরীক্ষা করি, যেমন, ২ জিবি মেমরি সহ Android Go ডিভাইস, কিছু এন্ট্রি-লেভেল ৪ জিবি, কিছু মিড-লেভেল ৪ জিবি, ৬ জিবি থেকে ৮ জিবি, বা খুব বড় স্ক্রিন, খুব ভালো স্ক্রিন কোয়ালিটি এবং ১৬ জিবি মেমরি সহ কিছু প্রিমিয়াম ফোল্ডেবল ডিভাইস।
আমরা এই ডিভাইসে মেমরির ব্যবহার পরিমাপ করেছি যখন বিভিন্ন অ্যাপ স্ট্যাটাসে, হিপ ডাম্প ক্যাপচার করা এবং ব্যবহার, বিভিন্ন টুল, যার মধ্যে Perfetto AI Skill অন্তর্ভুক্ত, অ্যালোকেশন বিশ্লেষণ করতে, সাধারণ অ্যান্টি-প্যাটার্ন শনাক্ত করতে, হ্যাঁ, সাধারণ ভুল যা আমরা করি, স্কেলে।
তাই, বিভিন্ন অ্যাক্টিভিটি স্ট্যাটাসে মেমরি এইভাবে পরিবর্তিত হয়।
এই বিশ্লেষণের মাধ্যমে আমরা ১৫টির বেশি সাধারণ সমস্যা শনাক্ত করি, যার মধ্যে রয়েছে বড় সাইজের ছবি থেকে শুরু করে ব্যাকগ্রাউন্ড ক্যাশে বৃদ্ধি পাওয়া।
সুতরাং, এটি মূল কেস স্টাডির মতো যা আমরা শেয়ার করব, আমরা আজ এক্সপ্লোর করব।
ফুং লাম
হ্যাঁ, আমি এখন যে কেস স্টাডি শেয়ার করছি তা ৫০০টি অ্যাপের রিসার্চ সম্পর্কে।
আপনি এখানে আছেন, তাই আমি মনে করি আমরা সবাই Android পছন্দ করি, তাই না?
আমরা সবাই Android পছন্দ করি।
ধরা যাক, আমাদের মধ্যে কেউ একজন Android পছন্দ করেন, কিন্তু তিনি Android ডেভেলপমেন্টে বিশেষজ্ঞ নন।
তাই, তিনি Android ফিগার অর্ডার করার জন্য একটি Android অ্যাপ তৈরি করেন।
কিন্তু কিছু ভুল আছে।
Let's talk Let's see maybe this is the first mistake.
"প্রোডাক্ট পৃষ্ঠায়, আমাদের কাছে দুই-কলামের লেআউট আছে যা বিভিন্ন Android ফিগারিন দেখায়।
প্রতিটি কলামের জন্য, ছবির সাইজ প্রায় ৪০০ x ৪০০ পিক্সেল।
তবে, অ্যাপটি আসলে সার্ভার থেকে একটি ছবি ডাউনলোড করছে, আমার স্ক্রিন কত বড় তা বিবেচ্য নয়।
এটি ৩০০০ x ৩০০০ সাইজের ছবি ডাউনলোড করছে।
হ্যাঁ, কারণ ডেভেলপারদের মতো, "আরে, Android খুব সুন্দর, খুব চমৎকার।
আমি ব্যবহারকারীকে সেরাটা দেখাতে চাই।"
কিন্তু আসলে, না, কারণ, আরে, এটি ইমেজ ভিউয়ের ডাইমেনশন দ্বারা ক্যাপ করা হয়েছে।
তাই, আপনি বড় সাইজের ছবি ডাউনলোড করলেও, ব্যবহারকারীকে সেটি সবচেয়ে ভালভাবে দেখানো হয় না।
এছাড়াও, এই বড় ছবির জন্য অতিরিক্ত মেমরি ব্যবহার করা হয়েছে।
এমনকি আমরা যদি এটিকে ডাউনস্যাম্পল করি, তাহলেও ডাউনস্যাম্পল করার প্রসেস অতিরিক্ত মেমরি ব্যবহার করে।
এই ডেভেলপারকে এটি ঠিক করতে আমরা কীভাবে সাহায্য করতে পারি?
আপনি যদি CDN সম্পর্কে জানেন, তাহলে CDN আসলে কিছু ইমেজ অপারেশন যেমন ক্রপিং, রিসাইজ, রোটেট, ফিল্টার প্রয়োগ, স্কোয়ার থেকে রাউন্ড ইমেজ তৈরি করতে পারে।
HTTP অনুরোধের মাধ্যমে, CDN কিছু হ্যান্ডেল করতে পারে।
তাই, আপনার সার্ভার-সাইড শুধুমাত্র একটি ছবি হোস্ট করলেও, আপনি নিজের ডিভাইসে ছোট বড় করা ছবি পাঠাতে CDN ব্যবহার করতে পারবেন।
তাই, প্রথমত, হ্যাঁ, আপনি যখন ছবির জন্য অনুরোধ করেন, তখন CDN ব্যবহার করার চেষ্টা করুন, যাতে আপনি ImageView সাইজ হিসেবে ছবির জন্য অনুরোধ করতে পারেন।
কিন্তু যদি সম্ভব না হয়, যেমন ওহ এটি কখনও কখনও ImageView-এর চেয়ে একটু বড় হতে পারে, কোডে এটির সাইজ পরিবর্তন করতে ডাউনস্যাম্পল করতে ভুলবেন না।
তাই, মেমরিতে লোড করার সময়, এটি একটি ছোট ছবি লোড করছে, ছবির সম্পূর্ণ রেজোলিউশন লোড করছে না।
Coil-এর জন্য কোডের নমুনা এখানে দেওয়া হল।
// 1. Ask CDN for the exact UI card dimensions (e.g. 540x675)
val sizedUrl = "$cdnBaseUrl?w=$cardWidthPx&h=$cardHeightPx&fmt=webp"
// 2. Enforce exact downsampling + Hardware Bitmap config
AsyncImage(
model = ImageRequest.Builder(LocalContext.current)
.data(sizedUrl)
.size(cardWidthPx, cardHeightPx) // Never use Size.ORIGINAL!
.precision(Precision.EXACT) // Downsample to exact card size
.bitmapConfig(Bitmap.Config.HARDWARE)
.build(),
contentDescription = product.title
)আপনি হলুদ রঙের শব্দে সাইজ উল্লেখ করতে পারেন।
হ্যাঁ, আপনি HTTP অনুরোধে HTTP হিসেবে সাইজ পাস করতে পারেন।
এবং তারপর, এখানে, হাইলাইট করা কোডে, আপনি কি হাইলাইট দেখতে পাচ্ছেন, হ্যাঁ, হ্যাঁ, Size.ORIGINAL ব্যবহার করবেন না।
হ্যাঁ, প্রস্থ ও উচ্চতা ব্যবহার করো, যাতে এটি প্যারামিটার হিসেবে পাস করা যায়।
ছবিটি সঠিক আকারে ডাউনস্যাম্পল করতে প্রিসিশন ব্যবহার করুন।
এবং সম্ভব হলে, Bitmap.Config.HARDWARE ব্যবহার করুন, যা কম মেমরি ব্যবহার করে কারণ ছবি সরাসরি VRAM-এ সেভ করা হবে।
একইভাবে, এই অ্যাপে, Android-এর সংগ্রহযোগ্য আইটেমের নতুন ভার্সন রিলিজ করা হয়েছে, তাই একটি লম্বা ছবি আছে যা ব্যবহারকারী বাঁদিকে এবং ডানদিকে সোয়াইপ করে নতুন Android ফিগারের বিভিন্ন ডিজাইন দেখতে পারেন।
কিন্তু এখানে আরও একটি সমস্যা আছে।
লম্বা ছবির ক্ষেত্রে, এর বেশিরভাগ অংশই স্ক্রিনের বাইরে থাকে, যার অর্থ হল, ব্যবহারকারী এটি দেখতে পান না, কিন্তু ছবিটি মেমরিতে লোড হয়।
আমরা কি এটি আরও ভাল করতে পারি?
হ্যাঁ।
আমরা এটিকে আরও ছোট ছোট ছবিতে ভাগ করতে পারি এবং স্ক্রিনে দেখানো ছবিই শুধু লোড হবে।
স্ক্রিনের বাইরে থাকা বিজ্ঞাপন লোড করা হবে না বা আনলোড করা হবে।
তাই, এটি কম মেমরি ব্যবহার করবে।
একইভাবে, ওহ, এই ক্ষেত্রে, এটি প্রায় ৬০% মেমরি সেভ করেছে।
অবশ্যই, আপনি যদি ছোট আয়তক্ষেত্রে ট্রিম করেন, তাহলে এটি আপনাকে আরও বেশি সাশ্রয় করতে সাহায্য করবে।
কিন্তু একইভাবে, ওহ, কোনও ব্যবহারকারী যদি ব্যবহারকারীর জন্য কোনও ফিচার প্রদান করতে চান, আরে, আপনি Android ফিগারিনের প্রতিটি বিবরণ দেখতে জুম ইন এবং জুম ইন করতে পারেন, কিছু সাধারণ ভুল হল তারা সত্যিই লোড করে, আবার, একটি খুব বড় ছবি, তাই এটি জুম করা এবং আবার জুম করা যেতে পারে।
কিন্তু, না, আপনাকে এটি করতে হবে না।
আরও ভালো উপায় হল, ব্যবহারকারী যখন আগে থেকে লোড করা কম রেজোলিউশনের ছবি জুম করেন এবং পিঞ্চ করা বন্ধ করেন, তখন আপনি কোঅর্ডিনেট হিসেব করে সম্পূর্ণ রেজোলিউশন লোড করেন-- শুধুমাত্র সেই অংশটি লোড করেন, হাই-রেজোলিউশন ছবি থেকে হিসেব করা অংশ।
তাই, শুধুমাত্র সেই দৃশ্যমান এলাকা মেমরিতে লোড করা হবে।
এটি কীভাবে করতে হয়?
ওহ, BitmapRegionDecoder নামে একটি API আছে, যা আপনাকে কোনও ছবির নির্দিষ্ট অঞ্চল লোড করতে সাহায্য করে।
এবং অবশ্যই, কিছু টুল ও লাইব্রেরিও আপনাকে সাহায্য করতে পারে।
আপনি এটি GitHub-এ সার্চ করতে পারেন।
কিছু কমিক্স অ্যাপ বা কিছু ম্যাপ এটি আগেই ব্যবহার করছে।
আপনি এগুলি রেফারেন্স হিসেবে ব্যবহার করতে পারেন।
এছাড়াও, আমরা মানুষ, আমাদের ভুল হয়।
AI-ও ভুল করে।
তাই, ভুল এড়াতে, ছবি লোড করার সময় আমরা কিছু সীমাও যোগ করতে পারি।
যেমন, এই ক্ষেত্রে আমি বলতে পারি, "উইন্ডোর সাইজ বা স্ক্রিনের ডাইমেনশনকে সীমা হিসেবে ব্যবহার করে min ফাংশনে সেটি যোগ করা যাক, অনুরোধ করা প্রস্থ বা বাউন্ড প্রস্থের min।"
// Query active window bounds instead of hardcoding 1080 / 1920
val bounds = WindowMetricsCalculator.getOrCreate()
.computeCurrentWindowMetrics(activity).bounds
// Clamp target dimensions so Bitmap NEVER exceeds the active window
val safeWidth = minOf(requestedWidthPx, bounds.width())
val safeHeight = minOf(requestedHeightPx, bounds.height())
val bitmap = Bitmap.createBitmap(safeWidth, safeHeight, config)তাহলে, এই ফাংশন ব্যবহার করে, আমি যখনই কোনও ছবি লোড করব, সেটি কি কখনও সীমানা অতিক্রম করবে না?
তাই, এটি স্ক্রিন রেজোলিউশনের চেয়ে বড় সাইজের ছবি লোড করবে না।
মনে রাখবেন, ছবির শুধুমাত্র দৃশ্যমান অংশ ডিকোড করুন, এতে আপনার মেমরি বাঁচবে।
ফুং লাম
আবার, এই অ্যাপটি আসলে একজন ডেভেলপারের তৈরি নয়।
আসলে, এটি একাধিক কন্ট্রিবিউটরের জন্য এবং তারা বিভিন্ন টুলিং ব্যবহার করতে পারে।
যেমন, এর একটি অংশ হল, ওহ দুঃখিত, ব্যবহার করা।
আমি আবার শুরু করছি।
এই অ্যাপের ক্ষেত্রেও একই।
আমি প্রোডাক্ট পৃষ্ঠায় আছি, আমার কাছে প্রোডাক্টের একটি তালিকা আছে এবং আমি এই ছবিটি দেখেছি, আমি এটি শপিং কার্টে যোগ করেছি।
কয়েক মিনিট পরে, আমি চেকআউট করতে যাই, আরে, একই ছবি আবার দেখা যাচ্ছে।
কিন্তু এটি কি সত্যিই একই ছবি নাকি মেমরিতে দুটি আলাদা অবজেক্ট?
হ্যাঁ, আমরা যে সাধারণ ভুলগুলি খুঁজে পেয়েছি তার মধ্যে একটি হল, অ্যাপটি অনেক ছবি লোড করছে।
তবে, মেমরিতে অনেক ডুপ্লিকেট ছবিও আছে।
আপনি যদি ইমেজ লোডার ব্যবহার করেন, হ্যাঁ, আসলে, ক্যাশিং করার জন্য আপনি একটি কী পাস করতে পারেন।
তাই একই ছবি ব্যবহার করা হলে, আপনি নতুন অবজেক্ট তৈরি করার পরিবর্তে আগে থেকে বরাদ্দ করা বিটম্যাপ অবজেক্ট ব্যবহার করতে পারবেন।
Android Studio-তে, আপনি মেমরি প্রোফাইলার ব্যবহার করে দেখতে পারেন যে, আপনার অ্যাপে ডুপ্লিকেট বিটম্যাপ আছে কিনা?
আমি আমার Google I/O সেশনে এটি কভার করেছি, তাই আপনি ভিডিওটি দেখার জন্য YouTube-এ ফিরে যেতে পারেন।
আর আমি যদি Android Studio ব্যবহার না করি, তাহলে হিপ ডাম্প ক্যাপচার করার জন্য adb কমান্ডও আছে এবং তারপর আমার অ্যাপে ডুপ্লিকেট বিটম্যাপ আছে কিনা তা কোয়েরি করার জন্য Perfetto হিপ গ্রাফ SQL ভাষা ব্যবহার করতে পারি।
এটি Coil-এ কোডের একটি উদাহরণ, কীভাবে আমি Bitmap ক্যাশিংয়ের জন্য কী যোগ করব।
// Strip volatile query tokens (?from=list / ?sig=...) for cache key
val canonicalKey = MemoryCache.Key(productUrl.substringBefore("?"))
// On Checkout Screen: reuse the 200x200 Bitmap already loaded in the List!
AsyncImage(
model = ImageRequest.Builder(context)
.data(productUrl)
.placeholderMemoryCacheKey(canonicalKey) // Instant zero-decode reuse!
.memoryCacheKey(canonicalKey)
.diskCacheKey(productUrl.substringBefore("?"))
.build(),
contentDescription = product.title
)আর এখন, হ্যাঁ।
আমি আগের উদাহরণে ফিরে যাই।
হ্যালো, আমার অ্যাপের ডেভেলপার আলাদা।
এর মধ্যে কিছু Views ব্যবহার করছে, তাই এটি ইমেজ লোডার হিসেবে Glide ব্যবহার করছে।
এবং তাদের মধ্যে কেউ কেউ Coil ব্যবহার করছেন কারণ তারা Compose ব্যবহার করছেন।
তাহলে আপনি যে বললেন, ইমেজ লোডার আমাদের ক্যাশিং করতে সাহায্য করে, তাহলে আমার কাছে একাধিক ইমেজ লোডার থাকলে কি কোনও সমস্যা হবে?
নিশ্চয়ই কোনও সমস্যা হয়েছে।
তাই, ইমেজ লোডারের জন্য, ডিফল্ট হিসেবে, তারা ডিফল্ট ক্যাশে সাইজ হিসেবে হিপ মেমরি সাইজের X% ব্যবহার করবে।
তাই আপনার কাছে একটি ইমেজ লোডার থাকলে, আপনার মেমরির X% ব্যবহার করা হয়।
আপনার কাছে দুটি ইমেজ লোডার থাকলে, এটি মেমরির ২ গুণ হবে।
আপনার কাছে তিনটি ইমেজ লোডার থাকলে, এটি ৩X হবে।
এবং আপনার ইমেজ লোডার একই পুল শেয়ার না করলে, একই জিনিস ঘটবে।
যেমন, প্রোডাক্ট পৃষ্ঠায় আমি Glide ব্যবহার করে একটি ছবি লোড করি এবং তারপর চেক-আউট পৃষ্ঠায় Coil ব্যবহার করে একই ছবি লোড করা হবে।
তবুও, মেমরিতে দুটি ছবি থাকবে।
সেটি ভালো নয়।
হ্যাঁ, তাই এটি ঠিক করার জন্য, আদর্শভাবে, আমরা ক্যাশিংয়ের জন্য শুধুমাত্র একটি ইমেজ লোডার বা একটি শেয়ার্ড পুল ব্যবহার করি।
কিন্তু যদি এমন হয় যে, ওহ, অনেক ইঞ্জিনিয়ারিংয়ের কাজ, আমি করতে পারব না।
ওহ, আরও সহজ সমাধান হল, এই ইমেজ লোডার কত শতাংশ ইমেজ হ্যান্ডেল করবে এবং অন্য ইমেজ লোডার কত শতাংশ ইমেজ হ্যান্ডেল করবে তা পরিমাপ করা এবং এই কোডের মতো বিভিন্ন ইমেজ লোডারের জন্য ওয়েট সেট করা।
val totalBudgetBytes = computeAdaptiveCacheBytes(context)
val numberOfLoaders = 2 // e.g., Team A (Glide) + Team B (Coil)
// Approach A (With Stats): Weight by image traffic (70% Team A / 30% Team B)
val loaderABudget = (totalBudgetBytes * 0.70).toInt()
val loaderBBudget = (totalBudgetBytes * 0.30).toInt()
// Approach B (Simple Fix without stats): Divide by number of loaders!
val simpleSplitBudget = totalBudgetBytes / numberOfLoaders
MemoryCache.Builder()
.maxSizeBytes(simpleSplitBudget)
.build()আমি loaderABudget-কে ৭০% ও loaderBBudget-কে ৩০% হিসেবে সেট করতে পারি, এটি আরেকটি উপায়।
আপনি যদি সত্যিই না জানেন যে প্রতিটি লোডার কতগুলি ছবি হ্যান্ডেল করবে, তবুও, শুধু ভাগ করে নেওয়া ভাল।
আমার কাছে দুটি ইমেজ লোডার আছে, ২ দিয়ে ভাগ করুন; তিনটি ইমেজ লোডার, ৩ দিয়ে ভাগ করুন, ডিফল্ট ভ্যালু ব্যবহার করবেন না কারণ তাতে মেমরি বেশি ব্যবহার হবে।
এবং ধরুন, প্রোডাক্ট পৃষ্ঠায়, আমরা এখনও আশা করি যে ব্যবহারকারী প্রোডাক্টের আরও তথ্য দেখতে স্ক্রল করবেন।
তাই সাধারণত, আমরা আমি আমরা হয়তো আরে, ৫০টি ছবি বা ৫০ এমবি ছবি ক্যাশে করি।
কিন্তু অ্যাপটি ব্যাকগ্রাউন্ডে চলে গেলে কী হবে?
ওহ, অ্যাপটি ব্যাকগ্রাউন্ডে থাকলে, ব্যবহারকারী ব্রাউজ নাও করতে পারেন।
ব্যবহারকারী ব্রাউজ না করলে, আমি কি এখনও এই পরিমাণ মেম- এই পরিমাণ ক্যাশে ইমেজ মেমরিতে রাখব?
না, আমাদের এটি রিলিজ করা উচিত।
হ্যাঁ, আমাদের onTrimMemory কলব্যাক মেনে চলা উচিত।
হ্যাঁ, আসলে অনেক অ্যাপই বর্তমানে onTrimMemory কলব্যাক প্রয়োগ বা মেনে চলে না।
onTrimMemory কলব্যাকের জন্য, আমাদের দুটি সিগন্যালের ব্যাপারে খেয়াল রাখতে হবে।
একটি হল UI_HIDDEN, যা ব্যবহারকারী হোম বোতাম প্রেস করার মতো এবং এটি হোম বোতাম প্রেস করার ঠিক পরেই নয়, হোম বোতাম প্রেস করার পরে একটি নির্দিষ্ট সময়কাল, যার অর্থ, "ওহ, আপনার অ্যাপটি আসলে এমন একটি অবস্থায় রয়েছে যেখানে ব্যবহারকারীর কাছে কোনও দৃশ্যমান UI নেই।"
এবং আমরা আশা করতে পারি, "আরে, ব্যবহারকারী আপনার অ্যাপ ব্যবহার করছেন না।
আপনার OS-এ রিসোর্স রিলিজ করা উচিত।"
তাই আমাদের ক্যাশের সাইজ কমাতে হবে।
এবং অন্যটি হল TRIM_MEMORY_BACKGROUND, যার অর্থ হল অ্যাপটি আগে থেকেই ব্যাকগ্রাউন্ডে অনেকক্ষণ ধরে চলছে এবং এখন OS-এর সত্যিই কিছু রিসোর্স প্রয়োজন।
এই পর্যায়ে, আপনার যতটা সম্ভব মেমরি খালি করা উচিত, প্রায় ১০০%।
এটি করার মাধ্যমে, হ্যাঁ, আপনি আপনার সুযোগও কমিয়ে দেন, OS-এর মাধ্যমে আপনার অ্যাপ বন্ধ হওয়ার ঝুঁকি কমিয়ে দেন।
"যেমন, 'ওরা মেমরি চাইছে, তুমি দিয়ে দাও, তারপর OS সেটা ম্যানেজ করবে'।"
যদি না হয়, তাহলে OS-এর কাছে কোনও বিকল্প থাকে না, তাকে কিছু একটা করতেই হয়।
ফুং লাম
আমি আরেকটি বড় ভুল যা দেখি তা হল, "আমি এইমাত্র উল্লেখ করেছি যে আপনার অ্যাপ, যদি অ্যাপটি ব্যাকগ্রাউন্ডে চলে যায়, তাহলে এটির কম মেমরি ব্যবহার করা উচিত।"
তবে, আমি দেখেছি যে অ্যাপগুলি আসলে ব্যাকগ্রাউন্ডে আরও বেশি মেমরি ব্যবহার করছে, আরও বেশি মেমরি।
কেন?
সেই জন্যই আমি রিসার্চ করি।
আমি কারণটি খুঁজে বের করার চেষ্টা করেছি।
আর এর অন্যতম কারণ হল, "আরে, তাদের অ্যাপে কিছু অ্যানিমেশন বা ক্যারোজেল আছে।
যেমন, প্রতি ১৫ সেকেন্ডে একটি নতুন ছবি ডাউনলোড করে এবং ব্যবহারকারীকে একটি নতুন ছবি দেখায়।"
তবে, অ্যাপ ব্যাকগ্রাউন্ডে চলে গেলেও ডেভেলপার অ্যানিমেশন বন্ধ করেননি।
তাই, অ্যাপ ব্যাকগ্রাউন্ডে থাকলেও, কোড এখনও চলছে, এখনও নতুন ছবি পাচ্ছে, নতুন ছবি ডিকোড করছে, আরও মেমরি ব্যবহার করছে।
তাই, অ্যাপের আসলে এটি করা উচিত নয়।
হ্যাঁ৷
অ্যাপ ব্যাকগ্রাউন্ডে চলে গেলে আমাদের সব অ্যানিমেশন, ক্যাশিং বা সম্পর্কহীন কাজ বন্ধ করে দিতে হবে।
তাই আপনি যদি অ্যাক্টিভিটি লাইফ সাইকেল সম্পর্কে জানেন, তাহলে onPause, onStop ইভেন্ট আছে, নিশ্চিত করুন যে আপনি অ্যানিমেশন বন্ধ করতে onStop, onPause, onDestroyView প্রয়োগ করেছেন, হ্যাঁ, ইমেজ পুলিং অনুরোধ বন্ধ করতে, বা কাজের সাথে সম্পর্কিত অন্যান্য জিনিস যা ব্যবহারকারীর মনোযোগের প্রয়োজন নেই।
override fun onStop() {
super.onStop()
// 1. Stop animations so they don't decode next frames in background!
bannerAnimationView.cancelAnimation()
animatedImageDrawable?.stop()
// 2. Cancel next-image buffering / prefetch queues!
nextImagesBufferingJob?.cancel()
Glide.with(this).pauseRequests()
}
override fun onDestroyView() {
super.onDestroyView()
bannerAnimationView.clearAnimation() // Release resources!
}ফুং লাম
আমি জানি যে আপনার সাথে অনেক কেস নিয়ে কথা বলেছি, তবে আমি বলেছি, "আমার কাছে ১৫টির বেশি কেস আছে।"
আমি জানি যে আমি যদি আপনার সাথে সব কেস শেয়ার করি, তাহলে আপনি সবকিছু ভুলে যেতে পারেন।
আপনি বাড়ি ফিরে Google-এ সার্চ করবেন, "আমি কীভাবে আমার মেমরি সংক্রান্ত সমস্যার সমাধান করব?"
তাই আমি আপনার জন্য এটি মনে রাখা সহজ করে দিই।
হ্যাঁ৷
আমি এটি খুব পরিচিত 3R ফ্রেমওয়ার্কের সাথে লিঙ্ক করব যাতে আপনি এগুলি মনে রাখতে পারেন।
এই 3R ফ্রেমওয়ার্ক, আমি মনে করি প্রত্যেকেরই এই বিষয়ে শোনা উচিত।
প্রথমটি হল কমানো, ছবি লোড করার সময় কীভাবে মেমরি কমানো যায়।
অবশ্যই, আমি যেমন বলেছি, আমরা ডাউনস্যাম্পল করতে পারি, সার্ভার থেকে ছবি পাওয়ার সময় সঠিক ডাইমেনশন পেতে পারি।
আমরা কালার ডেপথ অপ্টিমাইজ করি অথবা সম্ভব হলে হার্ডওয়্যার বিটম্যাপ ব্যবহার করি।
আপনি CDN ব্যবহার না করলে, CDN ব্যবহার করে দেখুন।
তাই, সার্ভার থেকে ছবি পাওয়ার সময়, এটি শুধু সেই ছবিই পায় যা সাইজের সাথে সবচেয়ে ভালোভাবে মানানসই হয়।
পুনরায় ব্যবহার, তাই আমরা ক্যাশে ব্যবহার করি যাতে মেমরিতে লোড করা ছবি পুনরায় ব্যবহার করা যায় এবং আমাদের মেমরিতে ডুপ্লিকেট বিটম্যাপ ছবি না থাকে।
এবং অবশ্যই, আপনার কোডে একাধিক ইমেজ লোডার না রাখার চেষ্টা করুন, কারণ এটি কম দক্ষ।
কমানো, পুনর্ব্যবহার করা এবং বাকিটা কী?
আপনি কি জানেন?
রিসাইকেল।
আবার চেষ্টা করতে চান?
রিসাইকেল, হ্যাঁ, রিসাইকেল।
হ্যাঁ, আমরা প্রাইমারি স্কুলে কমানো, পুনর্ব্যবহার করা এবং রিসাইকেল করা শিখেছি, যদিও আমরা প্রাইমারি স্কুলে কোডিং শিখি না।
হ্যাঁ, রিসাইকেল, হ্যাঁ।
হ্যাঁ, এটি মেমরি রিলিজ করার ব্যাপারে যাতে অন্য অ্যাপ্লিকেশন বা OS মেমরি ব্যবহার করতে পারে।
সেখানে রিসাইকেল সম্পর্কে তথ্য আছে।
প্রথমে, আমি onTrimMemory ইভেন্টের কথা উল্লেখ করেছি, ধরুন আপনার UI লুকানো থাকলে বা OS-এর সত্যিই রিসোর্সের প্রয়োজন হলে OS আপনাকে দুটি সিগন্যাল পাঠাবে।
হ্যাঁ, এই অনুরোধটি প্রসেস করার চেষ্টা করুন।
এবং অবশ্যই, আপনার যদি অ্যানিমেশন, ইমেজ লোডার বা অন্য কোনও কাজ থাকে যা ফোরগ্রাউন্ডে চলছে, তাহলে নিশ্চিত করুন যে আপনি এটি বন্ধ করেছেন যখন এটি onPause, onStop ইভেন্টের মতো হয়।
তাই, কম ব্যবহার, পুনর্ব্যবহার ও রিসাইকেল করুন।
মনে রাখা সহজ, তাই না?
ফুং লাম
এখন আমরা টিভি ম্যানুয়ালের কম আকর্ষণীয় অংশে ফিরে যাচ্ছি।
এই মেমরি সংক্রান্ত সমস্যা কার্যকরভাবে পরিমাপ করার জন্য আমরা কীভাবে বিভিন্ন টুলকিট ব্যবহার করি?
তাই প্রথমটি হল Google Play Console, Android Vitals এবং রিপোর্টিং API।
হ্যাঁ, Google Play Console-এ ৯০তম পার্সেন্টাইল চেক করুন।
আপনি এখন কোথায়?
অথবা আপনি ওয়েব পেজে না গেলে Reporting API ব্যবহার করুন।
আপনি এখনও ভ্যালু পেতে API ব্যবহার করতে পারেন।
হ্যাঁ, নিশ্চিত করুন, হ্যাঁ, থ্রেশহোল্ড হল ২০০ এমবি এবং ৪০০ এমবি।
নিশ্চিত করুন যে আপনি থ্রেশহোল্ডের বেশি উপার্জন করেছেন।
এছাড়াও, হিপ ডাম্প ক্যাপচার করতে বা সিমুলেট করার জন্য ইভেন্ট পাঠাতে সাহায্য করার জন্য ADB কমান্ড রয়েছে, যেমন, আমার অ্যাপ এখন UI_HIDDEN স্টেজে রয়েছে।
adb shell dumpsys meminfo <pkg> # watch Native Heap!
adb shell am send-trim-memory <pkg> UI_HIDDENআপনি Android Studio ব্যবহার করলে, ভাল।
তবুও, এটি সবসময় আপনার ভালো বন্ধু।
আপনি Android Studio প্রোফাইলার ব্যবহার করে হিপ ডাম্প ক্যাপচার করতে পারেন, যাতে আপনার মেমরির ব্যবহার এবং মেমরি অ্যালোকেশন আসলে কী তা দেখার জন্য একটি UI থাকে।
এবং অবশ্যই, আমরা Android Studio-তে Gemini-র সাথে AI বা উপলভ্য অন্যান্য Android স্কিল সম্পর্কে কথা বলি।
এটি আপনাকে হিপ ডাম্প বিশ্লেষণ করতে এবং বিটম্যাপ খুঁজে পেতে সাহায্য করার জন্য Perfetto SQL ট্রেস ব্যবহার করতে সাহায্য করে, সাধারণত ক্যাশের মালিক কে তা বলতে।
আমার ছবি কি Glide নাকি Coil-এর মাধ্যমে লোড করা হয়েছে?
আমার অ্যাপ্লিকেশনে কি অন্য কোনও মেমরি লিক আছে?
আমি জানি আপনাদের মধ্যে কেউ কেউ বলবেন, "আরে, আমি তো আর IDE ব্যবহার করি না।
আমি একজন প্রম্পট ইঞ্জিনিয়ার।
আমি ব্যবহার করি, হ্যাঁ, আমি কোড করার জন্য AI এজেন্টের সাথে প্রম্পট পাঠাচ্ছি।"
হ্যাঁ, আমি জানি।
আমি অবসর সময়ে কিছু ভাইব কোডিংও করি।
তাই, আমি আপনার সাথে এটি শেয়ার করছি, এটি একটি স্যাম্পেল মাত্র।
হ্যাঁ, আমার ৫০০ অ্যাপ রিসার্চের জন্য যে প্রম্পট ব্যবহার করি, এটি তারই অংশ।
হ্যাঁ, শুধু এর অংশ।
আপনি জানেন যে স্ক্রিনটি বড় নয়।
আমি আরও বেশি রাখলে, আপনি এটি দেখতেই পেতেন না।
তবে, এটি আপনাকে একটি ধারণা দেয় যে কীভাবে আপনি অটোমেট করতে, হিপ ডাম্প সহ মেমরির ব্যবহার ক্যাপচার করতে এবং বিশ্লেষণ করতে এবং আপনার সাথে ফলাফল প্রদান করতে AI ব্যবহার করতে পারেন।
এবং হ্যাঁ, আমি এখানে আরও একটি বাক্য বলতে পারি, হ্যাঁ, "আমার কোডের জন্য কোড ফিক্সও আমাকে প্রদান করুন।"
হ্যাঁ, আমি আশা করি এটি আপনার ভয় কমাতে পারে, যেমন, "আরে, মেমরি একটি বড় ডোমেন।
আমি বিশ্ববিদ্যালয়ে কম্পিউটার সায়েন্স নিয়ে পড়াশোনা করলেও অপারেটিং সিস্টেম বা কম্পিউটার সিস্টেম আর্কিটেকচার নিয়ে পড়িনি।
কিন্তু আসলে, এটি ততটা ভয়ঙ্কর নয়, এটি ততটা কঠিন নয়।"
হ্যাঁ, এটি আপনার অ্যাপ বিশ্লেষণ করার জন্য সহজ।
এটি ব্যবহার করে দেখুন।
তবে, AI ভুল করবেই, তাই মেমরির ব্যবহার এবং OS কীভাবে মেমরি বরাদ্দ করে সেই সম্পর্কে মৌলিক জ্ঞান থাকা এখনও গুরুত্বপূর্ণ।
তাই আমার টক শোতে আসুন এবং YouTube-এ আমাদের ভিডিও দেখুন।
ফুং লাম
তাহলে, রিক্যাপ করার জন্য, আমাদের কাছে কিছু টেকঅ্যাওয়ে আছে।
প্রথমে, কমান।
ছবির সঠিক সাইজ পেয়েছেন কিনা তা নিশ্চিত করুন।
আপনি ছবিটিকে ছোট ছোট ছবিতে ভাগ করেন যাতে মেমরিতে সবকিছু লোড না হয়, হ্যাঁ, শুধুমাত্র ব্যবহারকারীর কাছে দৃশ্যমান ছবিটি মেমরিতে লোড করার জন্য।
সম্ভব হলে হার্ডওয়্যার bitmapConfig বা RGB_565 ব্যবহার করুন।
পুনরায় ব্যবহার করুন, তাই আপনার কাছে ক্যাশে স্ট্র্যাটেজি আছে কিনা তা নিশ্চিত করুন, মেমরিতে ডুপ্লিকেট বিটম্যাপের সংখ্যা কমাতে সাহায্য করার জন্য ইমেজ লোডার ব্যবহার করুন।
এবং অবশ্যই, একাধিক বিটম্যাপ ছবি ব্যবহার করবেন না, এমনকি আপনি যদি সেইসব ছবি লোডারের ডিফল্ট ক্যাশে সাইজ ওভাররাইট করার চেষ্টা করেন তাহলেও।
আমরা পুনর্ব্যবহার, রিসাইকেল করি না।
হ্যাঁ৷
আপনার অ্যাপের মেমোরি ম্যানেজমেন্ট অ্যাপের স্ট্যাটাসের সাথে মানানসই হতে হবে।
UI লুকানো থাকলে, হ্যাঁ, আপনার কম মেমরি ব্যবহার করা উচিত।
OS যদি সত্যিই আপনাকে মেমরি খালি করতে বলে, তাহলে যতটা সম্ভব খালি করুন।
এবং বিটম্যাপ, পাওয়ার বা কম্পিউটেশনাল রিসোর্স যাই হোক না কেন, রিসোর্স শেষ করা বন্ধ করুন।
হ্যাঁ, ব্যানার টাইমার বন্ধ করুন, অ্যানিমেশন বন্ধ করুন, ইমেজ পুলিং বন্ধ করুন।
এবং সবশেষে, আপনি মনিটর করছেন কিনা তা নিশ্চিত করুন।
নিয়মিত Google Play Console-এ যান।
এটি একটি প্র্যাক্টিস কিনা তা ভাল করে দেখে নিন।
হ্যাঁ, এটি আপনাকে বুঝতে সাহায্য করবে যে, সম্পূর্ণ ব্যবহারকারী জনসংখ্যার মধ্যে আমার অ্যাপের মেমরি ব্যবহারের ৯০তম পার্সেন্টাইলের বর্তমান স্ট্যাটাস কী?
I এর ফলে আপনি সমস্যাটি আগে থেকেই শনাক্ত করতে পারবেন।
হ্যাঁ৷
লোকালি প্রোফাইলিং করতে, আপনি Android Studio মেমরি প্রোফাইলার ব্যবহার করতে পারেন।
আমরা কিছু ADB কমান্ডও ব্যবহার করতে পারি।
আমাদের Android স্কিলও আছে।
তবে, আপনি যদি বাস্তব-জগতের ব্যবহারকারীর পরিসংখ্যান দেখতে চান, তাহলে Google Play Console-এ তা দেখতে পাবেন।
এছাড়াও, Google Play Reporting API-এর মাধ্যমে আপনি Play Console-এ লগ-ইন না করেই API ব্যবহার করতে পারবেন।
সবসময়ের মতো, আপনি আরও জানতে চাইলে, developer.android.com/memory দেখুন।
এর মাধ্যমে কম ব্যবহার, পুনর্ব্যবহার ও রিসাইকেল করুন।
আমরা আরও ভালো কিছু তৈরি করতে পারি। আমি আশা করি যে আমরা একসাথে আরও ভালো Android ইকোসিস্টেম তৈরি করতে পারব এবং বর্তমানে যে চ্যালেঞ্জের সম্মুখীন হচ্ছি তা অতিক্রম করতে পারব।
ধন্যবাদ এবং কোডিং উপভোগ করুন।
আমি শীঘ্রই বাইরে অফিস আওয়ার্স করব, তাই আপনার কোনও প্রশ্ন থাকলে, নির্দ্বিধায় আসুন।
আর পরবর্তী বক্তা, আচ্ছা, কিছু সময় আছে, তাই পরবর্তী বক্তা স্টেজে আসা পর্যন্ত অপেক্ষা করুন এবং অনেক ধন্যবাদ।
// 1. Ask CDN for the exact UI card dimensions (e.g. 540x675)
val sizedUrl = "$cdnBaseUrl?w=$cardWidthPx&h=$cardHeightPx&fmt=webp"
// 2. Enforce exact downsampling + Hardware Bitmap config
AsyncImage(
model = ImageRequest.Builder(LocalContext.current)
.data(sizedUrl)
.size(cardWidthPx, cardHeightPx) // Never use Size.ORIGINAL!
.precision(Precision.EXACT) // Downsample to exact card size
.bitmapConfig(Bitmap.Config.HARDWARE)
.build(),
contentDescription = product.title
)// Query active window bounds instead of hardcoding 1080 / 1920
val bounds = WindowMetricsCalculator.getOrCreate()
.computeCurrentWindowMetrics(activity).bounds
// Clamp target dimensions so Bitmap NEVER exceeds the active window
val safeWidth = minOf(requestedWidthPx, bounds.width())
val safeHeight = minOf(requestedHeightPx, bounds.height())
val bitmap = Bitmap.createBitmap(safeWidth, safeHeight, config)// Strip volatile query tokens (?from=list / ?sig=...) for cache key
val canonicalKey = MemoryCache.Key(productUrl.substringBefore("?"))
// On Checkout Screen: reuse the 200x200 Bitmap already loaded in the List!
AsyncImage(
model = ImageRequest.Builder(context)
.data(productUrl)
.placeholderMemoryCacheKey(canonicalKey) // Instant zero-decode reuse!
.memoryCacheKey(canonicalKey)
.diskCacheKey(productUrl.substringBefore("?"))
.build(),
contentDescription = product.title
)val totalBudgetBytes = computeAdaptiveCacheBytes(context)
val numberOfLoaders = 2 // e.g., Team A (Glide) + Team B (Coil)
// Approach A (With Stats): Weight by image traffic (70% Team A / 30% Team B)
val loaderABudget = (totalBudgetBytes * 0.70).toInt()
val loaderBBudget = (totalBudgetBytes * 0.30).toInt()
// Approach B (Simple Fix without stats): Divide by number of loaders!
val simpleSplitBudget = totalBudgetBytes / numberOfLoaders
MemoryCache.Builder()
.maxSizeBytes(simpleSplitBudget)
.build()override fun onStop() {
super.onStop()
// 1. Stop animations so they don't decode next frames in background!
bannerAnimationView.cancelAnimation()
animatedImageDrawable?.stop()
// 2. Cancel next-image buffering / prefetch queues!
nextImagesBufferingJob?.cancel()
Glide.with(this).pauseRequests()
}
override fun onDestroyView() {
super.onDestroyView()
bannerAnimationView.clearAnimation() // Release resources!
}adb shell dumpsys meminfo <pkg> # watch Native Heap!
adb shell am send-trim-memory <pkg> UI_HIDDEN