ধীর রেন্ডারিং

UI রেন্ডারিং হল আপনার অ্যাপ থেকে একটি ফ্রেম তৈরি করা এবং এটি স্ক্রিনে প্রদর্শন করা। আপনার অ্যাপের সাথে একজন ব্যবহারকারীর মিথস্ক্রিয়া যাতে মসৃণ হয় তা নিশ্চিত করতে সাহায্য করার জন্য, প্রতি সেকেন্ডে 60 ফ্রেম (fps) অর্জন করতে আপনার অ্যাপটিকে অবশ্যই 16ms এর নিচে ফ্রেম রেন্ডার করতে হবে। কেন 60 fps পছন্দ করা হয় তা বুঝতে, Android পারফরম্যান্স প্যাটার্নস দেখুন: কেন 60fps? . আপনি যদি 90 fps অর্জন করার চেষ্টা করেন, তাহলে এই উইন্ডোটি 11ms এ নেমে যায় এবং 120 fps এর জন্য এটি 8ms হয়।

আপনি যদি এই উইন্ডোটিকে 1ms দ্বারা ওভাররান করেন তবে এর অর্থ এই নয় যে ফ্রেমটি 1ms দেরিতে প্রদর্শিত হবে, তবে Choreographer ফ্রেমটিকে সম্পূর্ণভাবে ড্রপ করবেন৷ যদি আপনার অ্যাপটি ধীরগতির UI রেন্ডারিং-এ ভুগে থাকে, তাহলে সিস্টেমটি ফ্রেমগুলি এড়িয়ে যেতে বাধ্য হয় এবং ব্যবহারকারী আপনার অ্যাপে তোতলানো বুঝতে পারে। একে জ্যাঙ্ক বলা হয়। এই পৃষ্ঠাটি দেখায় কিভাবে জ্যাঙ্ক নির্ণয় এবং ঠিক করতে হয়।

আপনি যদি View সিস্টেম ব্যবহার না করে এমন গেমস ডেভেলপ করছেন, তাহলে আপনি Choreographer বাইপাস করবেন। এই ক্ষেত্রে ফ্রেম পেসিং লাইব্রেরি ওপেনজিএল এবং ভলকান গেমগুলিকে অ্যান্ড্রয়েডে মসৃণ রেন্ডারিং এবং সঠিক ফ্রেম পেসিং অর্জনে সহায়তা করে।

অ্যাপের গুণমান উন্নত করতে, Android স্বয়ংক্রিয়ভাবে জ্যাঙ্কের জন্য আপনার অ্যাপ নিরীক্ষণ করে এবং Android ভাইটাল ড্যাশবোর্ডে তথ্য প্রদর্শন করে। কীভাবে ডেটা সংগ্রহ করা হয় সে সম্পর্কে তথ্যের জন্য, Android ভাইটালগুলির সাথে আপনার অ্যাপের প্রযুক্তিগত গুণমান পর্যবেক্ষণ করুন।

জ্যাঙ্ক সনাক্ত করুন

আপনার অ্যাপে যে কোডটি জ্যাঙ্ক সৃষ্টি করছে সেটি খুঁজে পাওয়া কঠিন হতে পারে। এই বিভাগটি জ্যাঙ্ক সনাক্ত করার জন্য তিনটি পদ্ধতি বর্ণনা করে:

ভিজ্যুয়াল পরিদর্শন আপনাকে কয়েক মিনিটের মধ্যে আপনার অ্যাপের সমস্ত ব্যবহারের ক্ষেত্রে চালাতে দেয়, তবে এটি সিস্ট্রেসের মতো বিশদ প্রদান করে না। Systrace আরও বিশদ প্রদান করে, কিন্তু আপনি যদি আপনার অ্যাপের সমস্ত ব্যবহারের ক্ষেত্রে Systrace চালান, তাহলে আপনি এত বেশি ডেটা দিয়ে প্লাবিত হতে পারেন যা বিশ্লেষণ করা কঠিন হতে পারে। ভিজ্যুয়াল পরিদর্শন এবং সিস্ট্রেস উভয়ই আপনার স্থানীয় ডিভাইসে জ্যাঙ্ক সনাক্ত করে। আপনি যদি স্থানীয় ডিভাইসগুলিতে জ্যাঙ্ক পুনরুত্পাদন করতে না পারেন, আপনি ক্ষেত্রের মধ্যে চলমান ডিভাইসগুলিতে আপনার অ্যাপের নির্দিষ্ট অংশগুলি পরিমাপ করতে কাস্টম কর্মক্ষমতা নিরীক্ষণ তৈরি করতে পারেন।

চাক্ষুষ পরিদর্শন

ভিজ্যুয়াল পরিদর্শন আপনাকে জ্যাঙ্ক তৈরি করছে এমন ব্যবহারের ক্ষেত্রে সনাক্ত করতে সহায়তা করে। একটি ভিজ্যুয়াল পরিদর্শন করতে, আপনার অ্যাপটি খুলুন এবং ম্যানুয়ালি আপনার অ্যাপের বিভিন্ন অংশে যান এবং আপনার UI-তে জ্যাঙ্ক সন্ধান করুন।

চাক্ষুষ পরিদর্শন সম্পাদনের জন্য এখানে কিছু টিপস রয়েছে:

  • আপনার অ্যাপের রিলিজ-অথবা অন্তত অ-ডিবাগযোগ্য-সংস্করণ চালান। এআরটি রানটাইম ডিবাগিং বৈশিষ্ট্যগুলিকে সমর্থন করার জন্য বেশ কয়েকটি গুরুত্বপূর্ণ অপ্টিমাইজেশন অক্ষম করে, তাই নিশ্চিত করুন যে আপনি ব্যবহারকারী যা দেখেন তার অনুরূপ কিছু দেখছেন।
  • প্রোফাইল GPU রেন্ডারিং সক্ষম করুন ৷ প্রোফাইল GPU রেন্ডারিং স্ক্রিনে বারগুলি প্রদর্শন করে যা আপনাকে 16-এমএস-প্রতি-ফ্রেম বেঞ্চমার্কের সাপেক্ষে একটি UI উইন্ডোর ফ্রেম রেন্ডার করতে কত সময় নেয় তার একটি ভিজ্যুয়াল উপস্থাপনা দেয়। প্রতিটি বারে রঙিন উপাদান রয়েছে যা রেন্ডারিং পাইপলাইনের একটি পর্যায়ে ম্যাপ করে, যাতে আপনি দেখতে পারেন কোন অংশটি সবচেয়ে বেশি সময় নিচ্ছে। উদাহরণস্বরূপ, যদি ফ্রেম ইনপুট পরিচালনা করতে অনেক সময় ব্যয় করে, তাহলে আপনার অ্যাপ কোডটি দেখুন যা ব্যবহারকারীর ইনপুট পরিচালনা করে।
  • জ্যাঙ্কের সাধারণ উৎস , যেমন RecyclerView এমন উপাদানগুলির মাধ্যমে চালান।
  • কোল্ড স্টার্ট থেকে অ্যাপটি চালু করুন।
  • সমস্যাটি আরও বাড়াতে একটি ধীর ডিভাইসে আপনার অ্যাপ চালান।

আপনি যখন জ্যাঙ্ক তৈরি করে এমন ব্যবহারের ক্ষেত্রে খুঁজে পান, তখন আপনার অ্যাপে জ্যাঙ্কের কারণ কী তা সম্পর্কে আপনার ভাল ধারণা থাকতে পারে। আপনার যদি আরও তথ্যের প্রয়োজন হয়, আপনি কারণটি আরও দেখতে সিস্ট্রেস ব্যবহার করতে পারেন।

সিস্ট্রেস

যদিও সিস্ট্রেস একটি টুল যা দেখায় যে পুরো ডিভাইসটি কী করছে, এটি আপনার অ্যাপে জ্যাঙ্ক সনাক্ত করার জন্য কার্যকর হতে পারে। সিস্ট্রেসের ন্যূনতম সিস্টেম ওভারহেড রয়েছে, তাই আপনি ইন্সট্রুমেন্টেশনের সময় বাস্তবসম্মত ঝাঁকুনি অনুভব করতে পারেন।

আপনার ডিভাইসে জ্যাঙ্কি ইউজ কেস সম্পাদন করার সময় সিস্ট্রেসের সাথে একটি ট্রেস রেকর্ড করুন। কীভাবে সিস্ট্রেস ব্যবহার করবেন তার নির্দেশাবলীর জন্য, কমান্ড লাইনে একটি সিস্টেম ট্রেস ক্যাপচার দেখুন। Systrace প্রক্রিয়া এবং থ্রেড দ্বারা বিভক্ত করা হয়. সিস্ট্রেসে আপনার অ্যাপের প্রক্রিয়াটি দেখুন, যা চিত্র 1 এর মতো দেখতে।

সিস্ট্রেস উদাহরণ
চিত্র 1. সিস্ট্রেস উদাহরণ।

চিত্র 1-এর সিস্ট্রেস উদাহরণে জ্যাঙ্ক সনাক্তকরণের জন্য নিম্নলিখিত তথ্য রয়েছে:

  1. Systrace দেখায় যখন প্রতিটি ফ্রেম আঁকা হয় এবং ধীর রেন্ডারের সময়গুলিকে হাইলাইট করার জন্য প্রতিটি ফ্রেমের রঙ কোড করে। এটি আপনাকে ভিজ্যুয়াল পরিদর্শনের চেয়ে আরও সঠিকভাবে পৃথক জাঙ্কি ফ্রেমগুলি খুঁজে পেতে সহায়তা করে। আরও তথ্যের জন্য, UI ফ্রেম এবং সতর্কতা পরিদর্শন দেখুন।
  2. Systrace আপনার অ্যাপে সমস্যা শনাক্ত করে এবং পৃথক ফ্রেম এবং সতর্কতা প্যানেলে সতর্কতা প্রদর্শন করে। সতর্কতার নির্দেশাবলী অনুসরণ করা ভাল।
  3. অ্যান্ড্রয়েড ফ্রেমওয়ার্কের অংশ এবং লাইব্রেরি, যেমন RecyclerView , ট্রেস মার্কার ধারণ করে। সুতরাং, সিস্ট্রেস টাইমলাইন দেখায় যে সেই পদ্ধতিগুলি কখন UI থ্রেডে কার্যকর করা হয় এবং সেগুলি কার্যকর করতে কতক্ষণ সময় লাগে।

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

যদি Systrace আপনাকে UI থ্রেডের কাজ কেন দীর্ঘ সময় নিচ্ছে সে সম্পর্কে বিশদ বিবরণ না দেখায়, তাহলে একটি নমুনা বা যন্ত্রযুক্ত পদ্ধতির ট্রেস রেকর্ড করতে Android CPU প্রোফাইলার ব্যবহার করুন। সাধারণত, মেথড ট্রেসগুলি জ্যাঙ্ক শনাক্ত করার জন্য ভাল নয় কারণ তারা ভারী ওভারহেডের কারণে মিথ্যা-পজিটিভ জ্যাঙ্ক তৈরি করে এবং থ্রেডগুলি যখন ব্লক করা বনাম চলছে তখন তারা দেখতে পায় না। কিন্তু, পদ্ধতির চিহ্নগুলি আপনাকে আপনার অ্যাপের পদ্ধতিগুলি সনাক্ত করতে সাহায্য করতে পারে যা সবচেয়ে বেশি সময় নিচ্ছে৷ এই পদ্ধতিগুলি সনাক্ত করার পরে, ট্রেস মার্কার যোগ করুন এবং এই পদ্ধতিগুলি জ্যাঙ্ক সৃষ্টি করছে কিনা তা দেখতে সিস্ট্রেস পুনরায় চালান।

আরও তথ্যের জন্য, সিস্ট্রেস বুঝুন দেখুন।

কাস্টম কর্মক্ষমতা নিরীক্ষণ

আপনি যদি একটি স্থানীয় ডিভাইসে জ্যাঙ্ক পুনরুত্পাদন করতে না পারেন, আপনি ক্ষেত্রের ডিভাইসগুলিতে জ্যাঙ্কের উত্স সনাক্ত করতে সাহায্য করার জন্য আপনার অ্যাপে কাস্টম কর্মক্ষমতা পর্যবেক্ষণ তৈরি করতে পারেন।

এটি করার জন্য, FrameMetricsAggregator এর মাধ্যমে আপনার অ্যাপের নির্দিষ্ট অংশ থেকে ফ্রেম রেন্ডারের সময় সংগ্রহ করুন এবং Firebase পারফরম্যান্স মনিটরিং ব্যবহার করে ডেটা রেকর্ড ও বিশ্লেষণ করুন।

আরও জানতে, Android এর জন্য পারফরম্যান্স মনিটরিং দিয়ে শুরু করুন দেখুন।

হিমায়িত ফ্রেম

হিমায়িত ফ্রেমগুলি হল UI ফ্রেম যা রেন্ডার হতে 700ms এর বেশি সময় নেয়৷ এটি একটি সমস্যা কারণ আপনার অ্যাপটি আটকে আছে বলে মনে হচ্ছে এবং ফ্রেমটি রেন্ডার করার সময় প্রায় এক সেকেন্ডের জন্য ব্যবহারকারীর ইনপুটের প্রতি প্রতিক্রিয়াশীল নয়৷ আমরা মসৃণ UI নিশ্চিত করতে 16ms এর মধ্যে একটি ফ্রেম রেন্ডার করার জন্য অ্যাপগুলিকে অপ্টিমাইজ করার পরামর্শ দিই। যাইহোক, অ্যাপ স্টার্ট আপের সময় বা অন্য স্ক্রিনে রূপান্তরিত হওয়ার সময়, প্রাথমিক ফ্রেমের আঁকতে 16ms এর বেশি সময় নেওয়া স্বাভাবিক কারণ আপনার অ্যাপটিকে অবশ্যই ভিউ বৃদ্ধি করতে হবে, স্ক্রীন লেআউট করতে হবে এবং স্ক্র্যাচ থেকে প্রাথমিক অঙ্কনটি সম্পাদন করতে হবে। এ কারণেই অ্যান্ড্রয়েড স্লো রেন্ডারিং থেকে আলাদাভাবে হিমায়িত ফ্রেম ট্র্যাক করে। আপনার অ্যাপের কোনো ফ্রেম রেন্ডার হতে 700ms এর বেশি সময় নেবে না।

আপনাকে অ্যাপের গুণমান উন্নত করতে সাহায্য করতে, Android স্বয়ংক্রিয়ভাবে হিমায়িত ফ্রেমের জন্য আপনার অ্যাপ নিরীক্ষণ করে এবং Android Vitals ড্যাশবোর্ডে তথ্য প্রদর্শন করে। কীভাবে ডেটা সংগ্রহ করা হয় সে সম্পর্কে তথ্যের জন্য, Android ভাইটালগুলির সাথে আপনার অ্যাপের প্রযুক্তিগত গুণমান পর্যবেক্ষণ করুন।

হিমায়িত ফ্রেমগুলি ধীর রেন্ডারিংয়ের একটি চরম রূপ, তাই সমস্যাটি নির্ণয় এবং সমাধান করার পদ্ধতি একই।

ট্র্যাকিং জ্যাঙ্ক

পারফেটোতে ফ্রেমটাইমলাইন ধীর বা হিমায়িত ফ্রেম ট্র্যাক করতে সাহায্য করতে পারে।

ধীর ফ্রেম, হিমায়িত ফ্রেম, এবং ANR-এর মধ্যে সম্পর্ক

ধীরগতির ফ্রেম, হিমায়িত ফ্রেম এবং ANR হল বিভিন্ন ধরনের জ্যাঙ্ক যা আপনার অ্যাপের সম্মুখীন হতে পারে। পার্থক্য বুঝতে নীচের টেবিল দেখুন.

ধীর ফ্রেম হিমায়িত ফ্রেম ANR
রেন্ডারিং সময় 16ms এবং 700ms এর মধ্যে 700ms এবং 5s এর মধ্যে 5 সেকেন্ডের বেশি
দৃশ্যমান ব্যবহারকারী প্রভাব এলাকা
  • RecyclerView স্ক্রোল আকস্মিকভাবে আচরণ করছে
  • জটিল অ্যানিমেশন সহ পর্দায় সঠিকভাবে অ্যানিমেশন হচ্ছে না
  • অ্যাপ স্টার্টআপের সময়
  • এক স্ক্রীন থেকে অন্য স্ক্রীনে সরানো—উদাহরণস্বরূপ, স্ক্রীন ট্রানজিশনিং
  • আপনার অ্যাক্টিভিটি ফোরগ্রাউন্ডে থাকাকালীন, আপনার অ্যাপ পাঁচ সেকেন্ডের মধ্যে কোনো ইনপুট ইভেন্ট বা BroadcastReceiver যেমন কী প্রেস বা স্ক্রিন ট্যাপ ইভেন্টে সাড়া দেয়নি।
  • ফোরগ্রাউন্ডে আপনার কোনো ক্রিয়াকলাপ না থাকলেও, আপনার BroadcastReceiver যথেষ্ট সময়ের মধ্যে কার্যকর করা শেষ করেনি।

ধীরগতির ফ্রেম এবং হিমায়িত ফ্রেমগুলিকে আলাদাভাবে ট্র্যাক করুন

অ্যাপ স্টার্ট আপের সময় বা অন্য স্ক্রিনে রূপান্তরিত হওয়ার সময়, প্রাথমিক ফ্রেমের আঁকতে 16ms এর বেশি সময় নেওয়া স্বাভাবিক কারণ অ্যাপটিকে অবশ্যই ভিউ বাড়াতে হবে, স্ক্রীন লেআউট করতে হবে এবং স্ক্র্যাচ থেকে প্রাথমিক ড্র করতে হবে।

জ্যাঙ্ককে অগ্রাধিকার দেওয়া এবং সমাধান করার জন্য সর্বোত্তম অনুশীলন

আপনার অ্যাপে জ্যাঙ্ক সমাধান করার সময় নিম্নলিখিত সেরা অনুশীলনগুলি মনে রাখুন:

  • জ্যাঙ্কের সবচেয়ে সহজে পুনরুত্পাদনযোগ্য উদাহরণগুলি সনাক্ত করুন এবং সমাধান করুন।
  • ANR-কে অগ্রাধিকার দিন। যদিও ধীরগতির বা হিমায়িত ফ্রেমগুলি একটি অ্যাপকে অলস দেখাতে পারে, তবে ANRগুলি অ্যাপটিকে সাড়া দেওয়া বন্ধ করে দেয়।
  • ধীর রেন্ডারিং পুনরুত্পাদন করা কঠিন, কিন্তু আপনি 700ms হিমায়িত ফ্রেম মেরে শুরু করতে পারেন। অ্যাপটি শুরু হওয়ার সময় বা স্ক্রিন পরিবর্তন করার সময় এটি সবচেয়ে সাধারণ।

জ্যাংক ফিক্সিং

জ্যাঙ্ক ঠিক করতে, কোন ফ্রেমগুলি 16ms এ সম্পূর্ণ হচ্ছে না তা পরিদর্শন করুন এবং কী ভুল তা সন্ধান করুন৷ কিছু ফ্রেমে Record View#draw বা Layout অস্বাভাবিকভাবে দীর্ঘ হচ্ছে কিনা তা পরীক্ষা করুন। এই সমস্যাগুলি এবং অন্যান্যগুলির জন্য জ্যাঙ্কের সাধারণ উত্সগুলি দেখুন৷

জ্যাঙ্ক এড়াতে, UI থ্রেডের বাইরে অ্যাসিঙ্ক্রোনাসভাবে দীর্ঘ-চলমান কাজগুলি চালান। আপনার কোড কোন থ্রেডে চলছে সে সম্পর্কে সর্বদা সচেতন থাকুন এবং প্রধান থ্রেডে অ-তুচ্ছ কাজ পোস্ট করার সময় সতর্কতা অবলম্বন করুন।

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

জ্যাঙ্কের সাধারণ উৎস

নিম্নলিখিত বিভাগগুলি View সিস্টেম ব্যবহার করে অ্যাপগুলিতে জ্যাঙ্কের সাধারণ উত্স এবং সেগুলি মোকাবেলার জন্য সর্বোত্তম অনুশীলনগুলি ব্যাখ্যা করে৷ জেটপ্যাক কম্পোজের সাথে পারফরম্যান্সের সমস্যা সমাধানের তথ্যের জন্য, জেটপ্যাক কম্পোজ কর্মক্ষমতা দেখুন।

স্ক্রোলযোগ্য তালিকা

ListView —এবং বিশেষ করে RecyclerView —সাধারণত জটিল স্ক্রোলিং তালিকার জন্য ব্যবহৃত হয় যা জ্যাঙ্কের জন্য সবচেয়ে বেশি সংবেদনশীল। এগুলি উভয়েই সিস্ট্রেস মার্কার রয়েছে, তাই আপনি সিস্ট্রেস ব্যবহার করে দেখতে পারেন যে তারা আপনার অ্যাপে জ্যাঙ্কে অবদান রাখছে কিনা। কমান্ড-লাইন আর্গুমেন্ট পাস করুন -a <your-package-name> RecyclerView এ ট্রেস বিভাগগুলি পেতে — সেইসাথে আপনার যোগ করা যেকোন ট্রেস মার্কারগুলি দেখানোর জন্য। উপলব্ধ থাকলে, সিস্ট্রেস আউটপুটে তৈরি করা সতর্কতার নির্দেশিকা অনুসরণ করুন। Systrace-এর ভিতরে, আপনি RecyclerView ট্র্যাস করা বিভাগগুলিতে ক্লিক করতে পারেন RecyclerView যে কাজ করছে তার ব্যাখ্যা দেখতে।

RecyclerView: notifyDataSetChanged()

আপনি যদি দেখেন যে আপনার RecyclerView এর প্রতিটি আইটেম রিবাউন্ড হচ্ছে—এবং এইভাবে একটি ফ্রেমে পুনরায় সাজানো এবং পুনরায় আঁকা হয়েছে—নিশ্চিত করুন যে আপনি notifyDataSetChanged() , setAdapter(Adapter) , অথবা swapAdapter(Adapter, boolean) কল করছেন না । আপডেট এই পদ্ধতিগুলি ইঙ্গিত দেয় যে সম্পূর্ণ তালিকার বিষয়বস্তুর পরিবর্তন হয়েছে এবং Systrace-এ RV FullInvalidate হিসাবে প্রদর্শিত হবে। পরিবর্তে, বিষয়বস্তু পরিবর্তন বা যোগ করার সময় ন্যূনতম আপডেট তৈরি করতে SortedList বা DiffUtil ব্যবহার করুন।

উদাহরণস্বরূপ, একটি অ্যাপ বিবেচনা করুন যা একটি সার্ভার থেকে সংবাদ সামগ্রীর একটি তালিকার একটি নতুন সংস্করণ গ্রহণ করে৷ আপনি যখন অ্যাডাপ্টারে এই তথ্য পোস্ট করেন, notifyDataSetChanged() কল করা সম্ভব, যেমনটি নিম্নলিখিত উদাহরণে দেখানো হয়েছে:

কোটলিন

fun onNewDataArrived(news: List<News>) {
    myAdapter.news = news
    myAdapter.notifyDataSetChanged()
}

জাভা

void onNewDataArrived(List<News> news) {
    myAdapter.setNews(news);
    myAdapter.notifyDataSetChanged();
}

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

আমরা আপনাকে DiffUtil ব্যবহার করার পরামর্শ দিই, যা আপনার জন্য ন্যূনতম আপডেটগুলি গণনা করে এবং প্রেরণ করে:

কোটলিন

fun onNewDataArrived(news: List<News>) {
    val oldNews = myAdapter.items
    val result = DiffUtil.calculateDiff(MyCallback(oldNews, news))
    myAdapter.news = news
    result.dispatchUpdatesTo(myAdapter)
}

জাভা

void onNewDataArrived(List<News> news) {
    List<News> oldNews = myAdapter.getItems();
    DiffResult result = DiffUtil.calculateDiff(new MyCallback(oldNews, news));
    myAdapter.setNews(news);
    result.dispatchUpdatesTo(myAdapter);
}

আপনার তালিকাগুলি কীভাবে পরিদর্শন করবেন তা DiffUtil জানাতে, আপনার MyCallback একটি Callback বাস্তবায়ন হিসাবে সংজ্ঞায়িত করুন।

RecyclerView: নেস্টেড RecyclerViews

RecyclerView এর একাধিক উদাহরণ নেস্ট করা সাধারণ, বিশেষ করে অনুভূমিকভাবে স্ক্রোলিং তালিকার উল্লম্ব তালিকার সাথে। এর একটি উদাহরণ হল প্লে স্টোরের প্রধান পৃষ্ঠায় অ্যাপের গ্রিড। এটি দুর্দান্ত কাজ করতে পারে, তবে এটি অনেকগুলি দর্শনও ঘোরাফেরা করে৷

আপনি যদি প্রথম পৃষ্ঠাটি নীচে স্ক্রোল করার সময় প্রচুর অভ্যন্তরীণ আইটেম স্ফীত হতে দেখেন, আপনি দেখতে চাইতে পারেন যে আপনি RecyclerView.RecycledViewPool RecyclerView এর ভিতরের (অনুভূমিক) উদাহরণগুলির মধ্যে ভাগ করছেন। ডিফল্টরূপে, প্রতিটি RecyclerView আইটেমের নিজস্ব পুল আছে। যাইহোক, একই সময়ে স্ক্রীনে এক ডজন itemViews ক্ষেত্রে, সমস্ত সারি একই ধরণের ভিউ দেখালে itemViews বিভিন্ন অনুভূমিক তালিকা দ্বারা ভাগ করা না গেলে সমস্যা হয়৷

কোটলিন

class OuterAdapter : RecyclerView.Adapter<OuterAdapter.ViewHolder>() {

    ...

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        // Inflate inner item, find innerRecyclerView by ID.
        val innerLLM = LinearLayoutManager(parent.context, LinearLayoutManager.HORIZONTAL, false)
        innerRv.apply {
            layoutManager = innerLLM
            recycledViewPool = sharedPool
        }
        return OuterAdapter.ViewHolder(innerRv)
    }
    ...

জাভা

class OuterAdapter extends RecyclerView.Adapter<OuterAdapter.ViewHolder> {
    RecyclerView.RecycledViewPool sharedPool = new RecyclerView.RecycledViewPool();

    ...

    @Override
    public void onCreateViewHolder(ViewGroup parent, int viewType) {
        // Inflate inner item, find innerRecyclerView by ID.
        LinearLayoutManager innerLLM = new LinearLayoutManager(parent.getContext(),
                LinearLayoutManager.HORIZONTAL);
        innerRv.setLayoutManager(innerLLM);
        innerRv.setRecycledViewPool(sharedPool);
        return new OuterAdapter.ViewHolder(innerRv);

    }
    ...

আপনি যদি আরও অপ্টিমাইজ করতে চান, আপনি অভ্যন্তরীণ RecyclerView এর LinearLayoutManagersetInitialPrefetchItemCount(int) কল করতে পারেন। যদি, উদাহরণস্বরূপ, আপনার কাছে সর্বদা একটি সারিতে 3.5টি আইটেম দৃশ্যমান থাকে, তাহলে innerLLM.setInitialItemPrefetchCount(4) কল করুন। এটি RecyclerView সংকেত দেয় যে যখন একটি অনুভূমিক সারি স্ক্রিনে আসতে চলেছে, UI থ্রেডে অতিরিক্ত সময় থাকলে এটি অবশ্যই ভিতরে আইটেমগুলিকে প্রিফেচ করার চেষ্টা করবে৷

রিসাইক্লারভিউ: খুব বেশি মুদ্রাস্ফীতি বা তৈরি করুন খুব বেশি সময় নিচ্ছে

বেশিরভাগ ক্ষেত্রে, RecyclerView এর প্রিফেচ বৈশিষ্ট্যটি UI থ্রেড নিষ্ক্রিয় থাকাকালীন সময়ের আগে কাজ করে মুদ্রাস্ফীতির খরচের কাছাকাছি কাজ করতে সাহায্য করতে পারে। আপনি যদি একটি ফ্রেমের সময় মুদ্রাস্ফীতি দেখতে পান এবং RV প্রিফেচ লেবেলযুক্ত একটি বিভাগে না থাকেন তবে নিশ্চিত হন যে আপনি একটি সমর্থিত ডিভাইসে পরীক্ষা করছেন এবং সমর্থন লাইব্রেরির সাম্প্রতিক সংস্করণ ব্যবহার করছেন৷ প্রিফেচ শুধুমাত্র Android 5.0 API লেভেল 21 এবং পরবর্তীতে সমর্থিত।

আপনি যদি স্ক্রিনে নতুন আইটেম আসার সাথে সাথে মুদ্রাস্ফীতি ঘটতে দেখেন, তাহলে যাচাই করুন যে আপনার প্রয়োজনের চেয়ে বেশি দৃশ্যের ধরন নেই। RecyclerView এর বিষয়বস্তুতে যত কম ভিউ টাইপ হবে, স্ক্রিনে নতুন আইটেম টাইপ এলে মুদ্রাস্ফীতি তত কম হবে। যদি সম্ভব হয়, যেখানে যুক্তিসঙ্গত ভিউ প্রকারগুলি মার্জ করুন৷ যদি শুধুমাত্র একটি আইকন, রঙ, বা টেক্সটের টুকরো প্রকারের মধ্যে পরিবর্তন হয়, আপনি বাঁধাইয়ের সময়ে সেই পরিবর্তন করতে পারেন এবং মুদ্রাস্ফীতি এড়াতে পারেন, যা একই সময়ে আপনার অ্যাপের মেমরি পদচিহ্নকে হ্রাস করে।

যদি আপনার দর্শনের ধরনগুলি ভাল দেখায় তবে আপনার মুদ্রাস্ফীতির খরচ কমানোর দিকে তাকান৷ অপ্রয়োজনীয় ধারক এবং কাঠামোগত দৃষ্টিভঙ্গি হ্রাস করা সাহায্য করতে পারে। ConstraintLayout এর সাথে itemViews তৈরি করার কথা বিবেচনা করুন, যা কাঠামোগত দৃষ্টিভঙ্গি কমাতে সাহায্য করতে পারে।

আপনি যদি পারফরম্যান্সের জন্য আরও অপ্টিমাইজ করতে চান, এবং আপনার আইটেম শ্রেণীবিন্যাসগুলি সহজ এবং আপনার জটিল থিমিং এবং শৈলী বৈশিষ্ট্যগুলির প্রয়োজন নেই, তাহলে কনস্ট্রাক্টরদেরকে কল করার কথা বিবেচনা করুন। যাইহোক, XML এর সরলতা এবং বৈশিষ্ট্যগুলি হারানোর ট্রেডঅফ প্রায়ই মূল্যবান নয়।

রিসাইক্লারভিউ: বাঁধাই খুব বেশি সময় নেয়

Bind—অর্থাৎ, onBindViewHolder(VH, int) — অবশ্যই সোজা হতে হবে এবং সবচেয়ে জটিল আইটেম ছাড়া সবকিছুর জন্য এক মিলিসেকেন্ডের চেয়ে অনেক কম সময় নিতে হবে। এটি অবশ্যই আপনার অ্যাডাপ্টারের অভ্যন্তরীণ আইটেম ডেটা থেকে প্লেইন পুরানো জাভা অবজেক্ট (POJO) আইটেম নিতে হবে এবং ViewHolder ভিউয়ের উপর কল সেটার। RV OnBindView দীর্ঘ সময় নিলে, যাচাই করুন যে আপনি আপনার বাইন্ড কোডে ন্যূনতম কাজ করছেন।

আপনি যদি আপনার অ্যাডাপ্টারে ডেটা রাখার জন্য বেসিক POJO অবজেক্টগুলি ব্যবহার করেন, তাহলে আপনি ডেটা বাইন্ডিং লাইব্রেরি ব্যবহার করে onBindViewHolder এ বাইন্ডিং কোড লেখা সম্পূর্ণ এড়াতে পারেন।

RecyclerView বা ListView: লেআউট বা ড্র খুব বেশি সময় নেয়

ড্র এবং লেআউট সংক্রান্ত সমস্যার জন্য, লেআউট পারফরম্যান্স এবং রেন্ডারিং পারফরম্যান্স বিভাগগুলি দেখুন।

লিস্টভিউ: মুদ্রাস্ফীতি

আপনি যদি সতর্ক না হন তবে আপনি দুর্ঘটনাক্রমে ListView পুনর্ব্যবহারযোগ্য অক্ষম করতে পারেন। আপনি যদি প্রতিবার স্ক্রিনে কোনো আইটেম আসার সময় মুদ্রাস্ফীতি দেখতে পান, তাহলে চেক করুন যে আপনার Adapter.getView() এর প্রয়োগটি convertView প্যারামিটার মিউজিং, রি-বাইন্ডিং এবং রিটার্ন করছে কিনা। যদি আপনার getView() বাস্তবায়ন সবসময় স্ফীত হয়, তাহলে আপনার অ্যাপ ListView এ পুনর্ব্যবহার করার সুবিধা পায় না। আপনার getView() এর গঠন প্রায় সবসময় নিম্নলিখিত বাস্তবায়নের অনুরূপ হতে হবে:

কোটলিন

fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
    return (convertView ?: layoutInflater.inflate(R.layout.my_layout, parent, false)).apply {
        // Bind content from position to convertView.
    }
}

জাভা

View getView(int position, View convertView, ViewGroup parent) {

    if (convertView == null) {
        // Only inflate if no convertView passed.
        convertView = layoutInflater.inflate(R.layout.my_layout, parent, false)
    }
    // Bind content from position to convertView.
    return convertView;
}

লেআউট কর্মক্ষমতা

যদি Systrace দেখায় যে Choreographer#doFrame এর লেআউট সেগমেন্ট খুব বেশি কাজ করছে বা খুব বেশি কাজ করছে, তাহলে এর মানে হল আপনি লেআউট পারফরম্যান্সের সমস্যাগুলিকে আঘাত করছেন। আপনার অ্যাপের লেআউট পারফরম্যান্স নির্ভর করে ভিউ হায়ারার্কির কোন অংশে লেআউট প্যারামিটার বা ইনপুট পরিবর্তন করা হয়েছে।

বিন্যাস কর্মক্ষমতা: খরচ

যদি সেগমেন্টগুলো কয়েক মিলিসেকেন্ডের বেশি হয়, তাহলে এটা সম্ভব যে আপনি RelativeLayouts , অথবা weighted-LinearLayouts এর জন্য সবচেয়ে খারাপ-কেস নেস্টিং পারফরম্যান্সে আঘাত করছেন। এই লেআউটগুলির প্রত্যেকটি তার বাচ্চাদের একাধিক পরিমাপ এবং লেআউট পাসকে ট্রিগার করতে পারে, তাই তাদের বাসা বাঁধলে বাসা বাঁধার গভীরতায় O(n^2) আচরণ হতে পারে।

অনুক্রমের সর্বনিম্ন লিফ নোড বাদে সমস্ত ক্ষেত্রে RelativeLayout বা LinearLayout এর ওজন বৈশিষ্ট্য এড়ানোর চেষ্টা করুন। নিম্নলিখিত উপায়গুলি আপনি এটি করতে পারেন:

  • আপনার কাঠামোগত দৃষ্টিভঙ্গি পুনর্গঠিত করুন।
  • কাস্টম লেআউট লজিক সংজ্ঞায়িত করুন। একটি নির্দিষ্ট উদাহরণের জন্য অপ্টিমাইজ লেআউট শ্রেণিবিন্যাস দেখুন। আপনি ConstraintLayout এ রূপান্তর করার চেষ্টা করতে পারেন, যা কার্যকারিতা ত্রুটি ছাড়াই অনুরূপ বৈশিষ্ট্য প্রদান করে।

লেআউট কর্মক্ষমতা: ফ্রিকোয়েন্সি

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

সাধারণত, অ্যানিমেশনগুলি অবশ্যই View এর অঙ্কন বৈশিষ্ট্যগুলিতে চলতে হবে, যেমন নিম্নলিখিতগুলি:

আপনি প্যাডিং বা মার্জিনের মতো লেআউট বৈশিষ্ট্যগুলির চেয়ে অনেক বেশি সস্তায় এই সবগুলি পরিবর্তন করতে পারেন। সাধারনত, একটি সেটারকে কল করে একটি দৃশ্যের অঙ্কন বৈশিষ্ট্য পরিবর্তন করাও অনেক সস্তা যা একটি invalidate() ট্রিগার করে, পরবর্তী ফ্রেমে draw(Canvas) । এটি অকার্যকর দৃশ্যের জন্য অঙ্কন ক্রিয়াকলাপগুলি পুনরায় রেকর্ড করে এবং এটি সাধারণত লেআউটের তুলনায় অনেক সস্তা।

রেন্ডারিং কর্মক্ষমতা

Android UI দুটি পর্যায়ে কাজ করে:

  • UI থ্রেডে View#draw রেকর্ড করুন , যা প্রতিটি অবৈধ ভিউতে draw(Canvas) চালায় এবং কাস্টম ভিউ বা আপনার কোডে কল আনতে পারে।
  • RenderThreadDrawFrame , যা নেটিভ RenderThread এ চলে কিন্তু Record View#draw ফেজ দ্বারা তৈরি কাজের উপর ভিত্তি করে কাজ করে।

রেন্ডারিং কর্মক্ষমতা: UI থ্রেড

যদি রেকর্ড ভিউ#ড্র করতে দীর্ঘ সময় নেয়, তবে এটি সাধারণ যে UI থ্রেডে একটি বিটম্যাপ আঁকা হচ্ছে। একটি বিটম্যাপে পেইন্টিং সিপিইউ রেন্ডারিং ব্যবহার করে, তাই সাধারণত সম্ভব হলে এটি এড়িয়ে চলুন। এটি সমস্যা কিনা তা দেখতে আপনি Android CPU প্রোফাইলারের সাথে পদ্ধতি ট্রেসিং ব্যবহার করতে পারেন।

একটি বিটম্যাপে পেইন্ট করা প্রায়শই করা হয় যখন একটি অ্যাপ প্রদর্শন করার আগে একটি বিটম্যাপ সাজাতে চায়—কখনও কখনও বৃত্তাকার কোণগুলি যোগ করার মতো একটি সাজসজ্জা:

কোটলিন

val paint = Paint().apply {
    isAntiAlias = true
}
Canvas(roundedOutputBitmap).apply {
    // Draw a round rect to define the shape:
    drawRoundRect(
            0f,
            0f,
            roundedOutputBitmap.width.toFloat(),
            roundedOutputBitmap.height.toFloat(),
            20f,
            20f,
            paint
    )
    paint.xfermode = PorterDuffXfermode(PorterDuff.Mode.MULTIPLY)
    // Multiply content on top to make it rounded.
    drawBitmap(sourceBitmap, 0f, 0f, paint)
    setBitmap(null)
    // Now roundedOutputBitmap has sourceBitmap inside, but as a circle.
}

জাভা

Canvas bitmapCanvas = new Canvas(roundedOutputBitmap);
Paint paint = new Paint();
paint.setAntiAlias(true);
// Draw a round rect to define the shape:
bitmapCanvas.drawRoundRect(0, 0,
        roundedOutputBitmap.getWidth(), roundedOutputBitmap.getHeight(), 20, 20, paint);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.MULTIPLY));
// Multiply content on top to make it rounded.
bitmapCanvas.drawBitmap(sourceBitmap, 0, 0, paint);
bitmapCanvas.setBitmap(null);
// Now roundedOutputBitmap has sourceBitmap inside, but as a circle.

আপনি যদি UI থ্রেডে এই ধরণের কাজ করছেন তবে আপনি পরিবর্তে পটভূমিতে ডিকোডিং থ্রেডে এটি করতে পারেন। কিছু ক্ষেত্রে, পূর্বের উদাহরণের মতো, আপনি এমনকি ড্রয়ের সময়ে কাজটি করতে পারেন। সুতরাং, যদি আপনার Drawable বা View কোডটি এরকম কিছু দেখায়:

কোটলিন

fun setBitmap(bitmap: Bitmap) {
    mBitmap = bitmap
    invalidate()
}

override fun onDraw(canvas: Canvas) {
    canvas.drawBitmap(mBitmap, null, paint)
}

জাভা

void setBitmap(Bitmap bitmap) {
    mBitmap = bitmap;
    invalidate();
}

void onDraw(Canvas canvas) {
    canvas.drawBitmap(mBitmap, null, paint);
}

আপনি এটির সাথে এটি প্রতিস্থাপন করতে পারেন:

কোটলিন

fun setBitmap(bitmap: Bitmap) {
    shaderPaint.shader = BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP)
    invalidate()
}

override fun onDraw(canvas: Canvas) {
    canvas.drawRoundRect(0f, 0f, width, height, 20f, 20f, shaderPaint)
}

জাভা

void setBitmap(Bitmap bitmap) {
    shaderPaint.setShader(
            new BitmapShader(bitmap, TileMode.CLAMP, TileMode.CLAMP));
    invalidate();
}

void onDraw(Canvas canvas) {
    canvas.drawRoundRect(0, 0, width, height, 20, 20, shaderPaint);
}

আপনি ব্যাকগ্রাউন্ড সুরক্ষার জন্যও এটি করতে পারেন, যেমন বিটম্যাপের উপরে একটি গ্রেডিয়েন্ট আঁকার সময় এবং ColorMatrixColorFilter এর সাহায্যে ইমেজ ফিল্টারিং—বিটম্যাপ পরিবর্তন করার জন্য অন্য দুটি সাধারণ ক্রিয়াকলাপ করা হয়।

আপনি যদি অন্য কোনো কারণে বিটম্যাপে আঁকছেন-সম্ভবত এটিকে ক্যাশে হিসেবে ব্যবহার করছেন-তাহলে সরাসরি আপনার View বা Drawable হার্ডওয়্যার-এক্সিলারেটেড Canvas আঁকার চেষ্টা করুন। প্রয়োজনে, জটিল রেন্ডারিং আউটপুট ক্যাশে করতে LAYER_TYPE_HARDWARE এর সাথে setLayerType() কল করার কথা বিবেচনা করুন এবং এখনও GPU রেন্ডারিংয়ের সুবিধা নিন।

রেন্ডারিং কর্মক্ষমতা: RenderThread

কিছু Canvas অপারেশন রেকর্ড করা সস্তা কিন্তু RenderThread ব্যয়বহুল গণনা ট্রিগার করে। Systrace সাধারণত সতর্কতার সাথে এইগুলিকে কল করে।

বড় পাথ অ্যানিমেটিং

যখন View এ পাস করা হার্ডওয়্যার-অ্যাক্সিলারেটেড Canvas Canvas.drawPath() কল করা হয়, তখন Android এই পথগুলি প্রথমে CPU-তে আঁকে এবং GPU-তে আপলোড করে। আপনার যদি বড় পাথ থাকে, তাহলে সেগুলিকে ফ্রেম থেকে ফ্রেমে সম্পাদনা করা এড়িয়ে চলুন, যাতে সেগুলি ক্যাশে করা যায় এবং দক্ষতার সাথে আঁকা যায়৷ drawPoints() , drawLines() , এবং drawRect/Circle/Oval/RoundRect() যদি আপনি বেশি ড্র কল ব্যবহার করেন তাহলেও এটি ব্যবহার করা আরও কার্যকর এবং ভাল।

Canvas.clipPath

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

কোটলিন

canvas.apply {
    save()
    clipPath(circlePath)
    drawBitmap(bitmap, 0f, 0f, paint)
    restore()
}

জাভা

canvas.save();
canvas.clipPath(circlePath);
canvas.drawBitmap(bitmap, 0f, 0f, paint);
canvas.restore();

পরিবর্তে, পূর্ববর্তী উদাহরণটি নিম্নরূপ প্রকাশ করুন:

কোটলিন

paint.shader = BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP)
// At draw time:
canvas.drawPath(circlePath, mPaint)

জাভা

// One time init:
paint.setShader(new BitmapShader(bitmap, TileMode.CLAMP, TileMode.CLAMP));
// At draw time:
canvas.drawPath(circlePath, mPaint);
বিটম্যাপ আপলোড

অ্যান্ড্রয়েড ওপেনজিএল টেক্সচার হিসাবে বিটম্যাপ প্রদর্শন করে এবং প্রথমবার একটি বিটম্যাপ একটি ফ্রেমে প্রদর্শিত হলে, এটি GPU-তে আপলোড করা হয়। আপনি এটিকে Systrace-এ টেক্সচার আপলোড(আইডি) প্রস্থ x উচ্চতা হিসাবে দেখতে পারেন। চিত্র 2 তে দেখানো হিসাবে এটি বেশ কয়েকটি মিলিসেকেন্ড সময় নিতে পারে, তবে GPU এর সাথে চিত্রটি প্রদর্শন করা প্রয়োজন।

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

অ্যান্ড্রয়েড 7.0-এ, বিটম্যাপ লোডিং কোড-সাধারণত লাইব্রেরি দ্বারা করা হয়-প্রয়োজন হওয়ার আগে একটি প্রাথমিক আপলোড ট্রিগার করতে prepareToDraw() কে কল করতে পারে। এইভাবে, RenderThread নিষ্ক্রিয় থাকাকালীন আপলোড তাড়াতাড়ি হয়। আপনি এটি ডিকোড করার পরে বা একটি ভিউতে একটি বিটম্যাপ বাঁধার সময় করতে পারেন, যতক্ষণ না আপনি বিটম্যাপটি জানেন। আদর্শভাবে, আপনার বিটম্যাপ লোডিং লাইব্রেরি আপনার জন্য এটি করে, তবে আপনি যদি নিজের পরিচালনা করেন বা নিশ্চিত করতে চান যে আপনি নতুন ডিভাইসে আপলোডগুলি হিট করবেন না, আপনি আপনার নিজের কোডে prepareToDraw() কল করতে পারেন।

একটি অ্যাপ একটি বড় বিটম্যাপ আপলোড করার জন্য একটি ফ্রেমে উল্লেখযোগ্য সময় ব্যয় করে
চিত্র 2. একটি অ্যাপ একটি বড় বিটম্যাপ আপলোড করার জন্য একটি ফ্রেমে উল্লেখযোগ্য সময় ব্যয় করে৷ হয় এটির আকার কমিয়ে দিন অথবা আপনি যখন এটিকে ডিকোড করবেন তখনই এটিকে ট্রিগার করুন prepareToDraw() দিয়ে।

থ্রেড সময়সূচী বিলম্ব

থ্রেড শিডিউলার হল অ্যান্ড্রয়েড অপারেটিং সিস্টেমের একটি অংশ যা সিস্টেমের কোন থ্রেডগুলি চালাতে হবে, কখন চলবে এবং কতক্ষণ চলবে তা নির্ধারণ করার দায়িত্বে থাকে৷

কখনও কখনও, জ্যাঙ্ক ঘটে কারণ আপনার অ্যাপের UI থ্রেড ব্লক করা হয়েছে বা চলছে না। Systrace বিভিন্ন রং ব্যবহার করে, যেমন চিত্র 3-এ দেখানো হয়েছে, একটি থ্রেড কখন ঘুমাচ্ছে (ধূসর), রানযোগ্য (নীল: এটি চলতে পারে, কিন্তু এখনও চালানোর জন্য শিডিয়ুলার দ্বারা বাছাই করা হয়নি), সক্রিয়ভাবে চলছে (সবুজ), বা নিরবচ্ছিন্ন ঘুমের মধ্যে (লাল বা কমলা)। থ্রেড সময়সূচী বিলম্বের কারণে সৃষ্ট জ্যাঙ্ক সমস্যাগুলি ডিবাগ করার জন্য এটি অত্যন্ত কার্যকর।

যখন UI থ্রেড ঘুমোচ্ছে তখন একটি সময়কাল হাইলাইট করে
চিত্র 3. একটি সময়কালের হাইলাইট যখন UI থ্রেড ঘুমোচ্ছে।

প্রায়শই, বাইন্ডার কল—Android-এ ইন্টার-প্রসেস কমিউনিকেশন (IPC) মেকানিজম—আপনার অ্যাপের সঞ্চালনে দীর্ঘ বিরতি দেয়। অ্যান্ড্রয়েডের পরবর্তী সংস্করণগুলিতে, এটি UI থ্রেড চালানো বন্ধ করার সবচেয়ে সাধারণ কারণগুলির মধ্যে একটি। সাধারণত, ফিক্স হল কলিং ফাংশনগুলি এড়াতে যা বাইন্ডার কল করে। যদি এটি অনিবার্য হয়, মানটি ক্যাশে করুন বা কাজটি ব্যাকগ্রাউন্ড থ্রেডে সরান৷ কোডবেসগুলি বড় হওয়ার সাথে সাথে আপনি যদি সতর্ক না হন তবে আপনি দুর্ঘটনাক্রমে কিছু নিম্ন-স্তরের পদ্ধতি ব্যবহার করে একটি বাইন্ডার কল যোগ করতে পারেন। যাইহোক, আপনি খুঁজে পেতে এবং ট্রেসিং সঙ্গে তাদের ঠিক করতে পারেন.

আপনার যদি বাইন্ডার লেনদেন থাকে, তাহলে আপনি নিম্নলিখিত adb কমান্ডের সাহায্যে তাদের কল স্ট্যাকগুলি ক্যাপচার করতে পারেন:

$ adb shell am trace-ipc start
… use the app - scroll/animate ...
$ adb shell am trace-ipc stop --dump-file /data/local/tmp/ipc-trace.txt
$ adb pull /data/local/tmp/ipc-trace.txt

কখনও কখনও নিষ্পাপ মনে হয় এমন কলগুলি, যেমন getRefreshRate() , বাইন্ডার লেনদেনগুলিকে ট্রিগার করতে পারে এবং যখন ঘন ঘন কল করা হয় তখন বড় সমস্যা হতে পারে৷ পর্যায়ক্রমে ট্রেসিং আপনাকে এই সমস্যাগুলি দেখাতে এবং সমাধান করতে সহায়তা করতে পারে।

RV ফ্লিং-এ বাইন্ডার লেনদেনের কারণে UI থ্রেড স্লিপিং দেখায়। আপনার বাইন্ড লজিক ফোকাস রাখুন, এবং বাইন্ডার কল ট্র্যাক করতে এবং সরাতে ট্রেস-আইপিসি ব্যবহার করুন।
চিত্র 4. একটি আরভি ফ্লিং-এ বাইন্ডার লেনদেনের কারণে UI থ্রেড ঘুমোচ্ছে। আপনার বাইন্ড লজিক সহজ রাখুন এবং বাইন্ডার কল ট্র্যাক করতে এবং সরাতে trace-ipc ব্যবহার করুন।

আপনি যদি বাইন্ডার অ্যাক্টিভিটি দেখতে না পান কিন্তু তারপরও আপনার UI থ্রেড চালানো দেখতে না পান, তাহলে নিশ্চিত হোন যে আপনি অন্য থ্রেড থেকে লক বা অন্য অপারেশনের জন্য অপেক্ষা করছেন না। সাধারণত, UI থ্রেডকে অন্য থ্রেডের ফলাফলের জন্য অপেক্ষা করতে হয় না। অন্যান্য থ্রেড এটিতে তথ্য পোস্ট করা আবশ্যক.

বস্তু বরাদ্দ এবং আবর্জনা সংগ্রহ

অ্যান্ড্রয়েড 5.0-এ ডিফল্ট রানটাইম হিসাবে ART চালু হওয়ার কারণে অবজেক্ট অ্যালোকেশন এবং আবর্জনা সংগ্রহ (GC) উল্লেখযোগ্যভাবে কম সমস্যা, কিন্তু এই অতিরিক্ত কাজের সাথে আপনার থ্রেডগুলিকে ওজন করা এখনও সম্ভব। একটি বিরল ইভেন্টের প্রতিক্রিয়া হিসাবে বরাদ্দ করা ভাল যা প্রতি সেকেন্ডে অনেকবার ঘটে না—যেমন একজন ব্যবহারকারী একটি বোতামে ট্যাপ করছেন—কিন্তু মনে রাখবেন যে প্রতিটি বরাদ্দ একটি খরচ সহ আসে৷ যদি এটি একটি আঁটসাঁট লুপে থাকে যা ঘন ঘন বলা হয়, তাহলে GC-তে লোড হালকা করার জন্য বরাদ্দ এড়ানোর কথা বিবেচনা করুন।

GC ঘন ঘন চলছে কিনা Systrace আপনাকে দেখায়, এবং Android মেমরি প্রোফাইলার আপনাকে দেখাতে পারে যে বরাদ্দগুলি কোথা থেকে আসছে। আপনি যদি সম্ভব হলে বরাদ্দ এড়িয়ে যান, বিশেষ করে টাইট লুপে, আপনার সমস্যা হওয়ার সম্ভাবনা কম।

HeapTaskDemon-এ একটি 94ms GC দেখায়
চিত্র 5. HeapTaskDaemon থ্রেডে A 94ms GC।

অ্যান্ড্রয়েডের সাম্প্রতিক সংস্করণগুলিতে, GC সাধারণত HeapTaskDaemon নামে একটি ব্যাকগ্রাউন্ড থ্রেডে চলে। উল্লেখযোগ্য পরিমাণে বরাদ্দের অর্থ হতে পারে আরও বেশি CPU সম্পদ GC-তে ব্যয় করা হয়েছে, যেমন চিত্র 5 এ দেখানো হয়েছে।

{% শব্দার্থে %} {% endverbatim %} {% শব্দার্থে %} {% endverbatim %}